RecyclableList.AddRange(IList<T> items) performance improvements
This commit is contained in:
1 parent
44c8286f85
commit
fb3290f853
1 file changed
+30
-20
@@ -443,41 +443,51 @@ namespace Recyclable.Collections
|
|||||||
_longCount = targetCapacity;
|
_longCount = targetCapacity;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddRange(in IList<T> items)
|
public void AddRange(IList<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,
|
||||||
int targetItemIdx = (int)(oldLongCount % blockSize);
|
targetBlockIndex = _lastBlockIndex,
|
||||||
int targetBlockIdx = (int)(oldLongCount / blockSize) + (targetItemIdx > 0 ? 1 : 0);
|
memoryBlockCount = _memoryBlocks.Length;
|
||||||
Span<T[]> memoryBlocksSpan = new(_memoryBlocks);
|
|
||||||
var memoryBlocksCount = memoryBlocksSpan.Length;
|
T[] itemsBuffer = items.Count >= RecyclableDefaults.MinPooledArrayLength ? _blockArrayPool.Rent(items.Count) : new T[items.Count];
|
||||||
Span<T> targetBlockSpan = new(memoryBlocksSpan[targetBlockIdx]);
|
try
|
||||||
for (int i = 0; i < sourceItemsCount; i++)
|
|
||||||
{
|
{
|
||||||
targetBlockSpan[targetItemIdx++] = items[i];
|
items.CopyTo(itemsBuffer, 0);
|
||||||
if (targetItemIdx == blockSize)
|
|
||||||
|
Span<T> itemsSpan = new(itemsBuffer, 0, items.Count);
|
||||||
|
Span<T[]> memoryBlocksSpan = new(_memoryBlocks, 0, memoryBlockCount);
|
||||||
|
Span<T> targetBlockArraySpan = new(memoryBlocksSpan[targetBlockIndex], _nextItemIndex, blockSize - _nextItemIndex);
|
||||||
|
while (targetBlockArraySpan.Length <= itemsSpan.Length)
|
||||||
{
|
{
|
||||||
targetBlockIdx++;
|
itemsSpan[..targetBlockArraySpan.Length].CopyTo(targetBlockArraySpan);
|
||||||
if (targetBlockIdx == memoryBlocksCount)
|
itemsSpan = itemsSpan[targetBlockArraySpan.Length..];
|
||||||
|
targetBlockIndex++;
|
||||||
|
if (targetBlockIndex == memoryBlockCount)
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
targetBlockSpan = new Span<T>(memoryBlocksSpan[targetBlockIdx]);
|
targetBlockArraySpan = new(memoryBlocksSpan[targetBlockIndex], 0, blockSize);
|
||||||
targetItemIdx = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
itemsSpan.CopyTo(targetBlockArraySpan);
|
||||||
_longCount = targetCapacity;
|
_longCount = targetCapacity;
|
||||||
_lastBlockIndex = targetBlockIdx;
|
_lastBlockIndex = targetBlockIndex;
|
||||||
_nextItemIndex = targetItemIdx;
|
_nextItemIndex = itemsSpan.Length;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
if (items.Count >= RecyclableDefaults.MinPooledArrayLength)
|
||||||
|
{
|
||||||
|
_blockArrayPool.Return(itemsBuffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddRange(IEnumerable<T> source, int growByCount = RecyclableDefaults.MinPooledArrayLength)
|
public void AddRange(IEnumerable<T> source, int growByCount = RecyclableDefaults.MinPooledArrayLength)
|
||||||
|
|||||||
Reference in new issue
Block a user