RecyclableList.AddRange(List<T> items) performance improvements.

This commit is contained in:
Marek Lemańczyk committed 2023-03-10 18:30:41 +01:00
1 parent 948bbaff5c
commit 9c640f4251
1 file changed
+21 -21
+21 -21
View File
@@ -342,7 +342,6 @@ namespace Recyclable.Collections
_nextItemIndex = toCopy; _nextItemIndex = toCopy;
_longCount = targetCapacity; _longCount = targetCapacity;
_lastBlockIndex = targetBlockIndex; _lastBlockIndex = targetBlockIndex;
} }
public void AddRange(in RecyclableList<T> items) public void AddRange(in RecyclableList<T> items)
@@ -413,46 +412,47 @@ namespace Recyclable.Collections
} }
public void AddRange(in List<T> items) public void AddRange(List<T> items)
{ {
long sourceItemsCount = items.Count; long targetCapacity = _longCount + items.Count;
long oldLongCount = _longCount;
long targetCapacity = oldLongCount + sourceItemsCount;
if (_capacity < targetCapacity) if (_capacity < targetCapacity)
{ {
_ = EnsureCapacity(targetCapacity); _ = EnsureCapacity(targetCapacity);
} }
int blockSize = _blockSize; int blockSize = _blockSize, targetBlockIndex = _lastBlockIndex, toCopy = 0,
int targetItemIdx = (int)(oldLongCount % blockSize); copiedCount = 0, targetItemIndex = _nextItemIndex, totalItemsCount = items.Count;
int targetBlockIdx = (int)(oldLongCount / blockSize) + (targetItemIdx > 0 ? 1 : 0);
Span<T[]> memoryBlocksSpan = new(_memoryBlocks);
var memoryBlocksCount = memoryBlocksSpan.Length;
Span<T> targetBlockSpan = new(memoryBlocksSpan[targetBlockIdx], 0, blockSize);
for (int i = 0; i < sourceItemsCount; i++) Span<T[]> memoryBlocksSpan = new(_memoryBlocks);
T[] targetBlockArray = memoryBlocksSpan[targetBlockIndex];
while (true)
{ {
targetBlockSpan[targetItemIdx] = items[i]; if (blockSize - targetItemIndex <= totalItemsCount - copiedCount)
if (targetItemIdx + 1 == blockSize)
{ {
targetBlockIdx++; toCopy = blockSize - targetItemIndex;
if (targetBlockIdx == memoryBlocksCount) items.CopyTo(copiedCount, targetBlockArray, targetItemIndex, toCopy);
targetItemIndex = 0;
targetBlockIndex++;
if (targetBlockIndex > memoryBlocksSpan.Length)
{ {
break; break;
} }
targetBlockSpan = new Span<T>(memoryBlocksSpan[targetBlockIdx], 0, blockSize); targetBlockArray = memoryBlocksSpan[targetBlockIndex];
targetItemIdx = 0; copiedCount += toCopy;
} }
else else
{ {
targetItemIdx++; toCopy = totalItemsCount - copiedCount;
items.CopyTo(copiedCount, targetBlockArray, targetItemIndex, toCopy);
targetItemIndex = toCopy;
break;
} }
} }
_longCount = targetCapacity; _longCount = targetCapacity;
_lastBlockIndex = targetBlockIdx; _lastBlockIndex = targetBlockIndex;
_nextItemIndex = targetItemIdx; _nextItemIndex = targetItemIndex;
} }
public void AddRange(in IList<T> items) public void AddRange(in IList<T> items)