RecyclableList.SetNewLength renamed to RecyclableList.Resize & performance improved.
This commit is contained in:
1 parent
8c0d3c5fbc
commit
d1e0482693
1 file changed
+64
-72
@@ -230,99 +230,93 @@ namespace Recyclable.Collections
|
|||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
protected static T[][] SetNewLength(in T[][]? source, int minBlockSize, long oldCapacity, long newCapacity, ArrayPool<T[]> memoryBlocksPool, ArrayPool<T> blockArrayPool)
|
protected static long Resize(ref T[][]? source, int minBlockSize, long oldCapacity, long newCapacity, ArrayPool<T[]> memoryBlocksPool, ArrayPool<T> blockArrayPool)
|
||||||
{
|
{
|
||||||
const int sourceBlockCount = 0, requiredBlockCount = 1, uninitializedBlocksCount = 2, i = 3;
|
int minBlockSizePowerToShift = 31 - BitOperations.LeadingZeroCount((uint)minBlockSize);
|
||||||
minBlockSize = (int)BitOperations.RoundUpToPowerOf2((uint)minBlockSize);
|
int sourceBlockCount = (int)(oldCapacity >> minBlockSizePowerToShift);
|
||||||
int minBlockSizePowerToShift = MathUtils.GetPow2Shift(minBlockSize);
|
int requiredBlockCount = (int)(newCapacity >> minBlockSizePowerToShift) + ((newCapacity & (minBlockSize - 1)) > 0 ? 1 : 0);
|
||||||
Span<int> localInts = stackalloc int[4]
|
int blockIndex;
|
||||||
{
|
T[][]? newMemoryBlocks;
|
||||||
(int)(oldCapacity >> minBlockSizePowerToShift), // sourceBlockCount
|
Span<T[]> memoryBlocksSpan;
|
||||||
(int)(newCapacity >> minBlockSizePowerToShift) + ((newCapacity & (minBlockSize - 1)) > 0 ? 1 : 0), // requiredBlockCount
|
|
||||||
0, // uninitializedBlocksCount
|
|
||||||
0, // i
|
|
||||||
};
|
|
||||||
|
|
||||||
T[][] newMemoryBlocks = localInts[requiredBlockCount] < RecyclableDefaults.MinPooledArrayLength
|
// Release excesive blocks if we're downsizing
|
||||||
? new T[localInts[requiredBlockCount]][]
|
if (requiredBlockCount < sourceBlockCount && (minBlockSize >= RecyclableDefaults.MinPooledArrayLength))
|
||||||
: memoryBlocksPool.Rent(localInts[requiredBlockCount]);
|
|
||||||
|
|
||||||
Span<T[]> newMemoryBlocksSpan = new(newMemoryBlocks);
|
|
||||||
if (localInts[sourceBlockCount] > 0)
|
|
||||||
{
|
{
|
||||||
Span<T[]> sourceSpan = new(source);
|
memoryBlocksSpan = new(source, requiredBlockCount, sourceBlockCount - requiredBlockCount);
|
||||||
sourceSpan.CopyTo(newMemoryBlocksSpan);
|
blockIndex = 0;
|
||||||
if (localInts[sourceBlockCount] >= RecyclableDefaults.MinPooledArrayLength)
|
while (blockIndex < memoryBlocksSpan.Length)
|
||||||
{
|
{
|
||||||
memoryBlocksPool.Return(source!, NeedsClearing);
|
blockArrayPool.Return(memoryBlocksSpan[blockIndex++]!, NeedsClearing);
|
||||||
}
|
}
|
||||||
|
|
||||||
newMemoryBlocksSpan = newMemoryBlocksSpan[localInts[sourceBlockCount]..];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
localInts[uninitializedBlocksCount] = newMemoryBlocksSpan.Length;
|
// Allocate new memory block for all arrays
|
||||||
if (localInts[uninitializedBlocksCount] >= localInts[requiredBlockCount])
|
newMemoryBlocks = requiredBlockCount < RecyclableDefaults.MinPooledArrayLength
|
||||||
|
? (new T[requiredBlockCount][])
|
||||||
|
: memoryBlocksPool.Rent(requiredBlockCount);
|
||||||
|
|
||||||
|
// Copy arrays from the old memory block for all arrays
|
||||||
|
if (sourceBlockCount > 0)
|
||||||
{
|
{
|
||||||
|
Array.Copy(source!, newMemoryBlocks, sourceBlockCount);
|
||||||
|
// We can now return the old memory block for all arrays itself
|
||||||
|
if (sourceBlockCount >= RecyclableDefaults.MinPooledArrayLength)
|
||||||
|
{
|
||||||
|
memoryBlocksPool.Return(source!, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
source = newMemoryBlocks;
|
||||||
|
|
||||||
|
// Allocate arrays for any new blocks
|
||||||
|
if (requiredBlockCount > sourceBlockCount)
|
||||||
|
{
|
||||||
|
memoryBlocksSpan = new(newMemoryBlocks, sourceBlockCount, newMemoryBlocks.Length - sourceBlockCount);
|
||||||
if (minBlockSize >= RecyclableDefaults.MinPooledArrayLength)
|
if (minBlockSize >= RecyclableDefaults.MinPooledArrayLength)
|
||||||
{
|
{
|
||||||
newMemoryBlocksSpan[0] = blockArrayPool.Rent(minBlockSize);
|
if (sourceBlockCount == 0)
|
||||||
minBlockSize = newMemoryBlocksSpan[0].Length;
|
{
|
||||||
|
memoryBlocksSpan[0] = blockArrayPool.Rent(minBlockSize);
|
||||||
|
minBlockSize = memoryBlocksSpan[0].Length;
|
||||||
|
blockIndex = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
blockIndex = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (blockIndex < memoryBlocksSpan.Length)
|
||||||
|
{
|
||||||
|
memoryBlocksSpan[blockIndex++] = blockArrayPool.Rent(minBlockSize);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
newMemoryBlocksSpan[0] = new T[minBlockSize];
|
blockIndex = 0;
|
||||||
}
|
while (blockIndex < memoryBlocksSpan.Length)
|
||||||
|
{
|
||||||
newMemoryBlocksSpan = newMemoryBlocksSpan[1..];
|
memoryBlocksSpan[blockIndex++] = new T[minBlockSize];
|
||||||
localInts[uninitializedBlocksCount]--;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (minBlockSize >= RecyclableDefaults.MinPooledArrayLength)
|
|
||||||
{
|
|
||||||
for (localInts[i] = 0; localInts[i] < localInts[uninitializedBlocksCount]; localInts[i]++)
|
|
||||||
{
|
|
||||||
newMemoryBlocksSpan[localInts[i]] = blockArrayPool.Rent(minBlockSize);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for (localInts[i] = 0; localInts[i] < localInts[uninitializedBlocksCount]; localInts[i]++)
|
|
||||||
{
|
|
||||||
newMemoryBlocksSpan[localInts[i]] = new T[minBlockSize];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return newMemoryBlocks;
|
return newMemoryBlocks.Length << minBlockSizePowerToShift;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected long EnsureCapacity(long requestedCapacity)
|
protected long EnsureCapacity(long requestedCapacity)
|
||||||
{
|
{
|
||||||
T[][] memory = _memoryBlocks;
|
long newCapacity = _capacity > 0
|
||||||
long newCapacity;
|
? checked((long)BitOperations.RoundUpToPowerOf2((ulong)requestedCapacity))
|
||||||
|
: requestedCapacity;
|
||||||
|
|
||||||
if (_capacity > 0)
|
newCapacity = Resize(ref _memoryBlocks!, _blockSize, _capacity, newCapacity, _memoryBlocksPool, _blockArrayPool);
|
||||||
{
|
|
||||||
newCapacity = _capacity;
|
|
||||||
while (newCapacity < requestedCapacity)
|
|
||||||
{
|
|
||||||
newCapacity *= 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
newCapacity = requestedCapacity;
|
|
||||||
}
|
|
||||||
|
|
||||||
memory = SetNewLength(memory, _blockSize, _capacity, newCapacity, _memoryBlocksPool, _blockArrayPool);
|
|
||||||
if (newCapacity > 0 && _capacity == 0)
|
if (newCapacity > 0 && _capacity == 0)
|
||||||
{
|
{
|
||||||
_blockSize = memory[0].Length;
|
_blockSize = _memoryBlocks[0].Length;
|
||||||
_blockSizePow2Shift = MathUtils.GetPow2Shift(_blockSize);
|
_blockSizePow2Shift = MathUtils.GetPow2Shift(_blockSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
newCapacity = memory.Length * _blockSize;
|
|
||||||
_capacity = newCapacity;
|
_capacity = newCapacity;
|
||||||
_memoryBlocks = memory;
|
|
||||||
return newCapacity;
|
return newCapacity;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -335,7 +329,7 @@ namespace Recyclable.Collections
|
|||||||
|
|
||||||
if (expectedItemsCount > 0)
|
if (expectedItemsCount > 0)
|
||||||
{
|
{
|
||||||
_memoryBlocks = SetNewLength(_memoryBlocks, minBlockSize, 0, expectedItemsCount.Value, memoryBlocksPool, blockArrayPool);
|
_capacity = Resize(ref _memoryBlocks!, (int)BitOperations.RoundUpToPowerOf2((uint)minBlockSize), 0, expectedItemsCount.Value, memoryBlocksPool, blockArrayPool);
|
||||||
if (_memoryBlocks.Length > 0)
|
if (_memoryBlocks.Length > 0)
|
||||||
{
|
{
|
||||||
minBlockSize = _memoryBlocks[0].Length;
|
minBlockSize = _memoryBlocks[0].Length;
|
||||||
@@ -343,11 +337,10 @@ namespace Recyclable.Collections
|
|||||||
|
|
||||||
_blockSize = minBlockSize;
|
_blockSize = minBlockSize;
|
||||||
_blockSizePow2Shift = MathUtils.GetPow2Shift(minBlockSize);
|
_blockSizePow2Shift = MathUtils.GetPow2Shift(minBlockSize);
|
||||||
_capacity = _memoryBlocks.Length * minBlockSize;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_blockSize = minBlockSize;
|
_blockSize = (int)BitOperations.RoundUpToPowerOf2((uint)minBlockSize);
|
||||||
_blockSizePow2Shift = MathUtils.GetPow2Shift(minBlockSize);
|
_blockSizePow2Shift = MathUtils.GetPow2Shift(minBlockSize);
|
||||||
_memoryBlocks = _emptyMemoryBlocksArray;
|
_memoryBlocks = _emptyMemoryBlocksArray;
|
||||||
}
|
}
|
||||||
@@ -362,7 +355,7 @@ namespace Recyclable.Collections
|
|||||||
|
|
||||||
if (expectedItemsCount > 0)
|
if (expectedItemsCount > 0)
|
||||||
{
|
{
|
||||||
_memoryBlocks = SetNewLength(_memoryBlocks, minBlockSize, 0, expectedItemsCount.Value, memoryBlocksPool, blockArrayPool);
|
_capacity = Resize(ref _memoryBlocks!, (int)BitOperations.RoundUpToPowerOf2((uint)minBlockSize), 0, expectedItemsCount.Value, memoryBlocksPool, blockArrayPool);
|
||||||
if (_memoryBlocks.Length > 0)
|
if (_memoryBlocks.Length > 0)
|
||||||
{
|
{
|
||||||
minBlockSize = _memoryBlocks[0].Length;
|
minBlockSize = _memoryBlocks[0].Length;
|
||||||
@@ -370,11 +363,10 @@ namespace Recyclable.Collections
|
|||||||
|
|
||||||
_blockSize = minBlockSize;
|
_blockSize = minBlockSize;
|
||||||
_blockSizePow2Shift = MathUtils.GetPow2Shift(minBlockSize);
|
_blockSizePow2Shift = MathUtils.GetPow2Shift(minBlockSize);
|
||||||
_capacity = _memoryBlocks.Length * minBlockSize;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_blockSize = minBlockSize;
|
_blockSize = (int)BitOperations.RoundUpToPowerOf2((uint)minBlockSize);
|
||||||
_blockSizePow2Shift = MathUtils.GetPow2Shift(minBlockSize);
|
_blockSizePow2Shift = MathUtils.GetPow2Shift(minBlockSize);
|
||||||
_memoryBlocks = _emptyMemoryBlocksArray;
|
_memoryBlocks = _emptyMemoryBlocksArray;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user