RecyclableArrayPool<T> & OneSizeArrayPool converted to structs.
This commit is contained in:
1 parent
ff4a4b6683
commit
fc2335f5e4
9 files changed
+233
-377
No files matched your search
+20
-22
@@ -900,7 +900,7 @@ namespace Recyclable.Collections.Benchmarks.POC
|
||||
protected static readonly bool NeedsClearing = !typeof(T).IsValueType;
|
||||
|
||||
protected ArrayPool<T[]> _memoryBlocksPool;
|
||||
protected ArrayPool<T> _blockArrayPool;
|
||||
protected OneSizeArrayPool<T> _blockArrayPool;
|
||||
protected T[][] _memoryBlocks;
|
||||
|
||||
private long _capacity;
|
||||
@@ -1133,7 +1133,6 @@ namespace Recyclable.Collections.Benchmarks.POC
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
protected static long Resize(RecyclableLongListV3<T> list, int minBlockSize, byte minBlockSizePow2Shift, long newCapacity)
|
||||
{
|
||||
ArrayPool<T> blockArrayPool = list._blockArrayPool;
|
||||
int sourceBlockCount = list._reservedBlockCount;
|
||||
int requiredBlockCount = checked((int)(newCapacity >> minBlockSizePow2Shift) + ((newCapacity & (minBlockSize - 1)) > 0 ? 1 : 0));
|
||||
int blockIndex;
|
||||
@@ -1146,7 +1145,7 @@ namespace Recyclable.Collections.Benchmarks.POC
|
||||
blockIndex = 0;
|
||||
while (blockIndex < memoryBlocksSpan.Length)
|
||||
{
|
||||
blockArrayPool.Return(memoryBlocksSpan[blockIndex++], NeedsClearing);
|
||||
list._blockArrayPool.ReturnUnchecked(memoryBlocksSpan[blockIndex++], NeedsClearing);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1177,8 +1176,7 @@ namespace Recyclable.Collections.Benchmarks.POC
|
||||
{
|
||||
if (sourceBlockCount == 0)
|
||||
{
|
||||
memoryBlocksSpan[0] = blockArrayPool.Rent(minBlockSize);
|
||||
minBlockSize = memoryBlocksSpan[0].Length;
|
||||
memoryBlocksSpan[0] = list._blockArrayPool.Rent();
|
||||
blockIndex = 1;
|
||||
}
|
||||
else
|
||||
@@ -1188,7 +1186,7 @@ namespace Recyclable.Collections.Benchmarks.POC
|
||||
|
||||
while (blockIndex < memoryBlocksSpan.Length)
|
||||
{
|
||||
memoryBlocksSpan[blockIndex++] = blockArrayPool.Rent(minBlockSize);
|
||||
memoryBlocksSpan[blockIndex++] = list._blockArrayPool.Rent();
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -1206,14 +1204,14 @@ namespace Recyclable.Collections.Benchmarks.POC
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
protected static void SetupBlockArrayPooling(RecyclableLongListV3<T> list, int blockSize, ArrayPool<T>? blockArrayPool = null)
|
||||
protected static void SetupBlockArrayPooling(RecyclableLongListV3<T> list, int blockSize, ref OneSizeArrayPool<T> blockArrayPool)
|
||||
{
|
||||
list._blockSize = blockSize;
|
||||
list._blockSizePow2Shift = (byte)(31 - BitOperations.LeadingZeroCount((uint)blockSize));
|
||||
if (blockSize >= RecyclableDefaults.MinPooledArrayLength)
|
||||
{
|
||||
list._blockPoolingRequired = true;
|
||||
list._blockArrayPool = blockArrayPool ?? RecyclableArrayPool<T>.Shared(blockSize);
|
||||
list._blockArrayPool = blockArrayPool;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1233,7 +1231,7 @@ namespace Recyclable.Collections.Benchmarks.POC
|
||||
newCapacity = Resize(list, blockSize, list._blockSizePow2Shift, newCapacity);
|
||||
if (blockSize != list._memoryBlocks[0].Length && newCapacity > 0)
|
||||
{
|
||||
SetupBlockArrayPooling(list, list._memoryBlocks[0].Length);
|
||||
SetupBlockArrayPooling(list, list._memoryBlocks[0].Length, ref list._blockArrayPool);
|
||||
list._blockSizeMinus1 = list._blockSize - 1;
|
||||
}
|
||||
|
||||
@@ -1243,7 +1241,7 @@ namespace Recyclable.Collections.Benchmarks.POC
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
|
||||
#pragma warning disable CS8618 // It's set by SetupBlockArrayPooling
|
||||
public RecyclableLongListV3(int minBlockSize = RecyclableDefaults.BlockSize, long? expectedItemsCount = default, ArrayPool<T[]>? memoryBlocksPool = default, ArrayPool<T>? blockArrayPool = default)
|
||||
public RecyclableLongListV3(ref OneSizeArrayPool<T> blockArrayPool, int minBlockSize = RecyclableDefaults.BlockSize, long? expectedItemsCount = default, ArrayPool<T[]>? memoryBlocksPool = default)
|
||||
#pragma warning restore CS8618
|
||||
{
|
||||
_memoryBlocksPool = memoryBlocksPool ?? _defaultMemoryBlocksPool;
|
||||
@@ -1251,11 +1249,11 @@ namespace Recyclable.Collections.Benchmarks.POC
|
||||
if (expectedItemsCount > 0)
|
||||
{
|
||||
minBlockSize = checked((int)BitOperations.RoundUpToPowerOf2((uint)minBlockSize));
|
||||
SetupBlockArrayPooling(this, minBlockSize, blockArrayPool);
|
||||
SetupBlockArrayPooling(this, minBlockSize, ref blockArrayPool);
|
||||
_capacity = Resize(this, minBlockSize, _blockSizePow2Shift, expectedItemsCount.Value);
|
||||
if (_blockSize != _memoryBlocks![0].Length && _capacity > 0)
|
||||
{
|
||||
SetupBlockArrayPooling(this, _memoryBlocks[0].Length, blockArrayPool);
|
||||
SetupBlockArrayPooling(this, _memoryBlocks[0].Length, ref blockArrayPool);
|
||||
_blockSizeMinus1 = _blockSize - 1;
|
||||
}
|
||||
else
|
||||
@@ -1265,25 +1263,25 @@ namespace Recyclable.Collections.Benchmarks.POC
|
||||
}
|
||||
else
|
||||
{
|
||||
SetupBlockArrayPooling(this, checked((int)BitOperations.RoundUpToPowerOf2((uint)minBlockSize)), blockArrayPool);
|
||||
SetupBlockArrayPooling(this, checked((int)BitOperations.RoundUpToPowerOf2((uint)minBlockSize)), ref blockArrayPool);
|
||||
_blockSizeMinus1 = _blockSize - 1;
|
||||
_memoryBlocks = _emptyMemoryBlocksArray;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma warning disable CS8618 // It's set by SetupBlockArrayPooling
|
||||
public RecyclableLongListV3(IEnumerable<T> source, int minBlockSize = RecyclableDefaults.BlockSize, long? expectedItemsCount = default, ArrayPool<T[]>? memoryBlocksPool = default, ArrayPool<T>? blockArrayPool = default)
|
||||
public RecyclableLongListV3(ref OneSizeArrayPool<T> blockArrayPool, IEnumerable<T> source, int minBlockSize = RecyclableDefaults.BlockSize, long? expectedItemsCount = default, ArrayPool<T[]>? memoryBlocksPool = default)
|
||||
#pragma warning restore CS8618
|
||||
{
|
||||
_memoryBlocksPool = memoryBlocksPool ?? _defaultMemoryBlocksPool;
|
||||
if (expectedItemsCount > 0)
|
||||
{
|
||||
minBlockSize = checked((int)BitOperations.RoundUpToPowerOf2((uint)minBlockSize));
|
||||
SetupBlockArrayPooling(this, minBlockSize, blockArrayPool);
|
||||
SetupBlockArrayPooling(this, minBlockSize, ref blockArrayPool);
|
||||
_capacity = Resize(this, minBlockSize, _blockSizePow2Shift, expectedItemsCount.Value);
|
||||
if (minBlockSize != _memoryBlocks![0].Length && _capacity > 0)
|
||||
{
|
||||
SetupBlockArrayPooling(this, _memoryBlocks[0].Length, blockArrayPool);
|
||||
SetupBlockArrayPooling(this, _memoryBlocks[0].Length, ref blockArrayPool);
|
||||
_blockSizeMinus1 = _blockSize - 1;
|
||||
}
|
||||
else
|
||||
@@ -1293,7 +1291,7 @@ namespace Recyclable.Collections.Benchmarks.POC
|
||||
}
|
||||
else
|
||||
{
|
||||
SetupBlockArrayPooling(this, checked((int)BitOperations.RoundUpToPowerOf2((uint)minBlockSize)), blockArrayPool);
|
||||
SetupBlockArrayPooling(this, checked((int)BitOperations.RoundUpToPowerOf2((uint)minBlockSize)), ref blockArrayPool);
|
||||
_blockSizeMinus1 = _blockSize - 1;
|
||||
_memoryBlocks = _emptyMemoryBlocksArray;
|
||||
}
|
||||
@@ -1633,10 +1631,10 @@ namespace Recyclable.Collections.Benchmarks.POC
|
||||
{
|
||||
Span<T[]> memoryBlocksSpan = new(_memoryBlocks, 0, _reservedBlockCount);
|
||||
int memoryBlocksCount = memoryBlocksSpan.Length;
|
||||
ArrayPool<T> blockArrayPool = _blockArrayPool;
|
||||
ref OneSizeArrayPool<T> blockArrayPool = ref _blockArrayPool;
|
||||
for (int toRemoveIdx = 0; toRemoveIdx < memoryBlocksCount; toRemoveIdx++)
|
||||
{
|
||||
blockArrayPool.Return(memoryBlocksSpan[toRemoveIdx], NeedsClearing);
|
||||
blockArrayPool.ReturnUnchecked(memoryBlocksSpan[toRemoveIdx], NeedsClearing);
|
||||
memoryBlocksSpan[toRemoveIdx] = _emptyBlockArray;
|
||||
}
|
||||
}
|
||||
@@ -1733,7 +1731,7 @@ namespace Recyclable.Collections.Benchmarks.POC
|
||||
{
|
||||
if (_blockPoolingRequired)
|
||||
{
|
||||
_blockArrayPool.Return(_memoryBlocks[index], NeedsClearing);
|
||||
_blockArrayPool.ReturnUnchecked(_memoryBlocks[index], NeedsClearing);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1851,7 +1849,7 @@ namespace Recyclable.Collections.Benchmarks.POC
|
||||
|
||||
public void RecyclableLongList_EnsureCapacityV3_ByPowOf2()
|
||||
{
|
||||
using var list = new RecyclableLongListV3<long>(minBlockSize: BlockSize, expectedItemsCount: TestObjectCount);
|
||||
using var list = new RecyclableLongListV3<long>(ref RecyclableArrayPool<long>._pools[BlockSize], minBlockSize: BlockSize, expectedItemsCount: TestObjectCount);
|
||||
DoNothing(_ensureCapacityV3Func.Invoke(null, new object[] { list, TestObjectCount }));
|
||||
}
|
||||
|
||||
@@ -1869,7 +1867,7 @@ namespace Recyclable.Collections.Benchmarks.POC
|
||||
|
||||
public void RecyclableLongList_EnsureCapacityV3_ByBlockSize()
|
||||
{
|
||||
using var list = new RecyclableLongListV3<long>();
|
||||
using var list = new RecyclableLongListV3<long>(ref RecyclableArrayPool<long>._pools[BlockSize]);
|
||||
DoNothing(_ensureCapacityV3Func.Invoke(null, new object[] { list, TestObjectCount }));
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
namespace Recyclable.Collections.Pools
|
||||
{
|
||||
internal enum MemoryPressure
|
||||
{
|
||||
High,
|
||||
Medium,
|
||||
Low
|
||||
}
|
||||
|
||||
internal static class MemoryUtils
|
||||
{
|
||||
public static MemoryPressure GetMemoryPressure()
|
||||
{
|
||||
const double HighPressureThreshold = .90; // Percent of GC memory pressure threshold we consider "high"
|
||||
const double MediumPressureThreshold = .70; // Percent of GC memory pressure threshold we consider "medium"
|
||||
|
||||
GCMemoryInfo memoryInfo = GC.GetGCMemoryInfo();
|
||||
|
||||
if (memoryInfo.MemoryLoadBytes >= memoryInfo.HighMemoryLoadThresholdBytes * HighPressureThreshold)
|
||||
{
|
||||
return MemoryPressure.High;
|
||||
}
|
||||
|
||||
if (memoryInfo.MemoryLoadBytes >= memoryInfo.HighMemoryLoadThresholdBytes * MediumPressureThreshold)
|
||||
{
|
||||
return MemoryPressure.Medium;
|
||||
}
|
||||
|
||||
return MemoryPressure.Low;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,61 +1,13 @@
|
||||
using System.Buffers;
|
||||
|
||||
namespace Recyclable.Collections.Pools
|
||||
namespace Recyclable.Collections.Pools
|
||||
{
|
||||
public sealed class OneSizeArrayPool<T> : ArrayPool<T>
|
||||
public struct OneSizeArrayPool<T>
|
||||
{
|
||||
private const int MemoryReleaseTaskSleepMilliseconds = 500;
|
||||
internal bool _memoryExceeded;
|
||||
private bool _disposed;
|
||||
|
||||
~OneSizeArrayPool()
|
||||
{
|
||||
_disposed = true;
|
||||
}
|
||||
|
||||
private async Task ReleaseMemoryOnExcess()
|
||||
{
|
||||
while (!_disposed)
|
||||
{
|
||||
if (_memoryExceeded)
|
||||
{
|
||||
Enter();
|
||||
if (_currentBucket != null)
|
||||
{
|
||||
_blockCount--;
|
||||
_currentBucket = _currentBucket.NextBucket;
|
||||
}
|
||||
|
||||
if (_currentBucket != null)
|
||||
{
|
||||
_blockCount--;
|
||||
_currentBucket = _currentBucket.NextBucket;
|
||||
}
|
||||
|
||||
if (_currentBucket != null)
|
||||
{
|
||||
_blockCount--;
|
||||
_currentBucket = _currentBucket.NextBucket;
|
||||
}
|
||||
|
||||
if (_currentBucket != null)
|
||||
{
|
||||
_blockCount--;
|
||||
_currentBucket = _currentBucket.NextBucket;
|
||||
}
|
||||
|
||||
Exit();
|
||||
}
|
||||
|
||||
await Task.Delay(MemoryReleaseTaskSleepMilliseconds);
|
||||
}
|
||||
}
|
||||
|
||||
private volatile MemoryBucket<T>? _currentBucket;
|
||||
private volatile int _blockCount;
|
||||
private volatile int _locked;
|
||||
private readonly int _blockSize;
|
||||
private readonly int _minBlockCount;
|
||||
private volatile int _blockCount;
|
||||
private volatile MemoryBucket<T>? _currentBucket;
|
||||
private volatile int _locked;
|
||||
internal volatile bool _memoryExceeded;
|
||||
|
||||
private void Enter()
|
||||
{
|
||||
@@ -78,35 +30,15 @@ namespace Recyclable.Collections.Pools
|
||||
|
||||
public OneSizeArrayPool(int blockSize, int minBlockCount)
|
||||
{
|
||||
_blockCount = 0;
|
||||
_currentBucket = null;
|
||||
_locked = 0;
|
||||
_memoryExceeded = false;
|
||||
_blockSize = blockSize;
|
||||
_minBlockCount = minBlockCount;
|
||||
_ = Task.Run(ReleaseMemoryOnExcess);
|
||||
}
|
||||
|
||||
public override T[] Rent(int minimumLength)
|
||||
{
|
||||
if (minimumLength != _blockSize)
|
||||
{
|
||||
ThrowWrongRentedArraySizeException(minimumLength, _blockSize);
|
||||
}
|
||||
|
||||
MemoryBucket<T>? bucket;
|
||||
Enter();
|
||||
if (_currentBucket != null)
|
||||
{
|
||||
_blockCount--;
|
||||
bucket = _currentBucket;
|
||||
_currentBucket = _currentBucket.NextBucket;
|
||||
}
|
||||
else
|
||||
{
|
||||
bucket = null;
|
||||
}
|
||||
|
||||
Exit();
|
||||
return bucket != null ? bucket.Memory : new T[_blockSize];
|
||||
}
|
||||
|
||||
public T[] Rent()
|
||||
{
|
||||
MemoryBucket<T>? bucket;
|
||||
@@ -143,14 +75,13 @@ namespace Recyclable.Collections.Pools
|
||||
Exit();
|
||||
}
|
||||
|
||||
public override void Return(T[] array, bool clearArray = false)
|
||||
public void Return(T[] array, bool clearArray = false)
|
||||
{
|
||||
if (array.Length != _blockSize)
|
||||
{
|
||||
ThrowWrongReturnedArraySizeException(array.Length, _blockSize);
|
||||
ThrowHelper.ThrowWrongReturnedArraySizeException(array.Length, _blockSize);
|
||||
}
|
||||
|
||||
MemoryBucket<T> bucket = new(array);
|
||||
if (clearArray)
|
||||
{
|
||||
// TODO: Measure performance
|
||||
@@ -158,6 +89,7 @@ namespace Recyclable.Collections.Pools
|
||||
Array.Clear(array, 0, array.Length);
|
||||
}
|
||||
|
||||
MemoryBucket<T> bucket = new(array);
|
||||
Enter();
|
||||
if (_blockCount < _minBlockCount)
|
||||
{
|
||||
@@ -169,14 +101,44 @@ namespace Recyclable.Collections.Pools
|
||||
Exit();
|
||||
}
|
||||
|
||||
private static void ThrowWrongReturnedArraySizeException(int returnedLength, int blockSize)
|
||||
{
|
||||
throw new InvalidOperationException($"The array size {returnedLength} doesn't match the size {blockSize} of the pool buffer and cannot be returned to this pool.");
|
||||
}
|
||||
private const int MemoryReleaseTaskSleepMilliseconds = 500;
|
||||
|
||||
private static void ThrowWrongRentedArraySizeException(int requestedSize, int blockSize)
|
||||
private async Task ReleaseMemoryOnExcess()
|
||||
{
|
||||
throw new InvalidOperationException($"The requested size {requestedSize} doesn't match the size {blockSize} of the pool buffer and cannot be taken from this pool.");
|
||||
while (true)
|
||||
{
|
||||
if (_memoryExceeded)
|
||||
{
|
||||
Enter();
|
||||
if (_currentBucket != null)
|
||||
{
|
||||
_blockCount--;
|
||||
_currentBucket = _currentBucket.NextBucket;
|
||||
}
|
||||
|
||||
if (_currentBucket != null)
|
||||
{
|
||||
_blockCount--;
|
||||
_currentBucket = _currentBucket.NextBucket;
|
||||
}
|
||||
|
||||
if (_currentBucket != null)
|
||||
{
|
||||
_blockCount--;
|
||||
_currentBucket = _currentBucket.NextBucket;
|
||||
}
|
||||
|
||||
if (_currentBucket != null)
|
||||
{
|
||||
_blockCount--;
|
||||
_currentBucket = _currentBucket.NextBucket;
|
||||
}
|
||||
|
||||
Exit();
|
||||
}
|
||||
|
||||
await Task.Delay(MemoryReleaseTaskSleepMilliseconds);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,41 +2,36 @@ using System.Numerics;
|
||||
|
||||
namespace Recyclable.Collections.Pools
|
||||
{
|
||||
public static class RecyclableArrayPool<T>
|
||||
public readonly struct RecyclableArrayPool<T>
|
||||
{
|
||||
private enum MemoryPressure
|
||||
internal static readonly OneSizeArrayPool<T>[] _pools = new OneSizeArrayPool<T>[32];
|
||||
public static T[] RentShared(int blockSize) => _pools[31 - BitOperations.LeadingZeroCount((uint)blockSize)].Rent();
|
||||
public static void ReturnShared(in T[] memoryBlock, bool needsClearing)
|
||||
=> _pools[31 - BitOperations.LeadingZeroCount((uint)memoryBlock.Length)].ReturnUnchecked(memoryBlock, needsClearing);
|
||||
|
||||
public static ref OneSizeArrayPool<T> Shared(int blockSize)
|
||||
=> ref _pools[31 - BitOperations.LeadingZeroCount((uint)blockSize)];
|
||||
|
||||
static RecyclableArrayPool()
|
||||
{
|
||||
High,
|
||||
Medium,
|
||||
Low
|
||||
var pools = _pools;
|
||||
for (var arraySize = 0; arraySize < 32; arraySize++)
|
||||
{
|
||||
int blockSize = 1 << arraySize;
|
||||
pools[arraySize] = new OneSizeArrayPool<T>(blockSize, 1000);
|
||||
}
|
||||
|
||||
_ = Task.Run(CheckAndReportMemoryPressure);
|
||||
}
|
||||
|
||||
private static MemoryPressure GetMemoryPressure()
|
||||
{
|
||||
const double HighPressureThreshold = .90; // Percent of GC memory pressure threshold we consider "high"
|
||||
const double MediumPressureThreshold = .70; // Percent of GC memory pressure threshold we consider "medium"
|
||||
|
||||
GCMemoryInfo memoryInfo = GC.GetGCMemoryInfo();
|
||||
|
||||
if (memoryInfo.MemoryLoadBytes >= memoryInfo.HighMemoryLoadThresholdBytes * HighPressureThreshold)
|
||||
{
|
||||
return MemoryPressure.High;
|
||||
}
|
||||
|
||||
if (memoryInfo.MemoryLoadBytes >= memoryInfo.HighMemoryLoadThresholdBytes * MediumPressureThreshold)
|
||||
{
|
||||
return MemoryPressure.Medium;
|
||||
}
|
||||
|
||||
return MemoryPressure.Low;
|
||||
}
|
||||
public static readonly OneSizeArrayPool<T> Null = new(0, 0);
|
||||
|
||||
private static async Task CheckAndReportMemoryPressure()
|
||||
{
|
||||
var previousValue = false;
|
||||
while (true)
|
||||
{
|
||||
bool memoryExceeded = GetMemoryPressure() == MemoryPressure.High;
|
||||
bool memoryExceeded = MemoryUtils.GetMemoryPressure() == MemoryPressure.High;
|
||||
if (memoryExceeded != previousValue)
|
||||
{
|
||||
previousValue = memoryExceeded;
|
||||
@@ -49,36 +44,5 @@ namespace Recyclable.Collections.Pools
|
||||
await Task.Delay(500);
|
||||
}
|
||||
}
|
||||
|
||||
static RecyclableArrayPool()
|
||||
{
|
||||
var pools = _pools;
|
||||
for (var arraySize = 0; arraySize < 32; arraySize++)
|
||||
{
|
||||
int blockSize = 2 << arraySize;
|
||||
pools[arraySize] = new OneSizeArrayPool<T>(blockSize, 1000);
|
||||
}
|
||||
|
||||
_ = Task.Run(CheckAndReportMemoryPressure);
|
||||
}
|
||||
|
||||
public static readonly OneSizeArrayPool<T> Null = new(0, 0);
|
||||
|
||||
private static readonly OneSizeArrayPool<T>[] _pools = new OneSizeArrayPool<T>[32];
|
||||
public static T[] Rent(int blockSize) => _pools[31 - BitOperations.LeadingZeroCount((uint)blockSize) - 1].Rent();
|
||||
public static void Return(in T[] memoryBlock, bool needsClearing) => _pools[31 - BitOperations.LeadingZeroCount((uint)memoryBlock.Length) - 1].ReturnUnchecked(memoryBlock, needsClearing);
|
||||
|
||||
// private static readonly ConcurrentDictionary<int, ArrayPool<T>> _pools = new();
|
||||
|
||||
public static OneSizeArrayPool<T> Shared(int blockSize) =>
|
||||
//lock (_lock)
|
||||
//{
|
||||
|
||||
// if (!_pools.TryGetValue(blockSize, out ArrayPool<T>? pool))
|
||||
// {
|
||||
// pool = new OneSizeArrayPool<T>(blockSize, 100);
|
||||
// pool = _pools.TryAdd(blockSize, pool) ? pool : _pools[blockSize];
|
||||
// }
|
||||
_pools[31 - BitOperations.LeadingZeroCount((uint)blockSize) - 1];//}//_lock.Wait();//try//{//}//finally//{// _lock.Release();//}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Buffers;
|
||||
using System.Numerics;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Recyclable.Collections.Pools;
|
||||
|
||||
@@ -6,6 +7,8 @@ namespace Recyclable.Collections
|
||||
{
|
||||
internal static class RecyclableListHelpers<T>
|
||||
{
|
||||
private static readonly bool NeedsClearing = !typeof(T).IsValueType;
|
||||
|
||||
[Obsolete("This method MAY be removed in the near future.")]
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool Contains(RecyclableList<T[]> arrays, T item) => arrays.Any(x => x.Contains(item));
|
||||
@@ -50,19 +53,6 @@ namespace Recyclable.Collections
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
public static int EnsureCapacity(RecyclableList<T> list, int requestedCapacity)
|
||||
{
|
||||
int newCapacity = list._capacity;
|
||||
while (newCapacity < requestedCapacity)
|
||||
{
|
||||
newCapacity <<= 1;
|
||||
}
|
||||
|
||||
ResizeAndCopy(list, newCapacity);
|
||||
return list._capacity;
|
||||
}
|
||||
|
||||
[Obsolete("This method WILL be removed in the near future. Please use the existing enumerators instead of it.")]
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static IEnumerable<T> Enumerate(RecyclableList<T[]> arrays, int chunkSize, long totalCount)
|
||||
@@ -224,8 +214,6 @@ namespace Recyclable.Collections
|
||||
return values[middle];
|
||||
}
|
||||
|
||||
private static readonly bool NeedsClearing = !typeof(T).IsValueType;
|
||||
|
||||
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
public static void ResizeAndCopy(RecyclableList<T> list)
|
||||
{
|
||||
@@ -234,7 +222,7 @@ namespace Recyclable.Collections
|
||||
T[] oldMemoryBlock = list._memoryBlock;
|
||||
list._memoryBlock = (list._capacity <<= 1) < RecyclableDefaults.MinPooledArrayLength
|
||||
? new T[list._capacity]
|
||||
: RecyclableArrayPool<T>.Rent(list._capacity);
|
||||
: RecyclableArrayPool<T>.RentShared(list._capacity);
|
||||
|
||||
// & WAS SLOWER WITHOUT
|
||||
new Span<T>(oldMemoryBlock, 0, list._count).CopyTo(list._memoryBlock);
|
||||
@@ -248,25 +236,22 @@ namespace Recyclable.Collections
|
||||
//}
|
||||
|
||||
// // If anything, it has been already cleared above, so we don't need to repeat it.
|
||||
RecyclableArrayPool<T>.Return(oldMemoryBlock, NeedsClearing);
|
||||
RecyclableArrayPool<T>.ReturnShared(oldMemoryBlock, NeedsClearing);
|
||||
}
|
||||
|
||||
// list._memoryBlock = newMemoryBlock;
|
||||
list._capacity = list._memoryBlock.Length;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
public static void ResizeAndCopy(RecyclableList<T> sourceList, int newSize)
|
||||
public static int ResizeAndCopy(RecyclableList<T> sourceList, int newSize)
|
||||
{
|
||||
T[] newMemoryBlock = newSize >= RecyclableDefaults.MinPooledArrayLength
|
||||
? RecyclableArrayPool<T>.Rent(newSize)
|
||||
T[] oldMemoryBlock = sourceList._memoryBlock;
|
||||
sourceList._memoryBlock = newSize >= RecyclableDefaults.MinPooledArrayLength
|
||||
? RecyclableArrayPool<T>.RentShared(newSize)
|
||||
: new T[newSize];
|
||||
|
||||
// & WAS SLOWER WITHOUT
|
||||
T[] oldMemoryBlock = sourceList._memoryBlock;
|
||||
|
||||
// & WAS SLOWER AS ARRAY
|
||||
new Span<T>(oldMemoryBlock, 0, sourceList._count).CopyTo(newMemoryBlock);
|
||||
new Span<T>(oldMemoryBlock, 0, sourceList._count).CopyTo(sourceList._memoryBlock);
|
||||
|
||||
if (oldMemoryBlock.Length >= RecyclableDefaults.MinPooledArrayLength)
|
||||
{
|
||||
@@ -277,11 +262,10 @@ namespace Recyclable.Collections
|
||||
//}
|
||||
|
||||
// If anything, it has been already cleared above, so we don't need to repeat it.
|
||||
RecyclableArrayPool<T>.Return(oldMemoryBlock, NeedsClearing);
|
||||
RecyclableArrayPool<T>.ReturnShared(oldMemoryBlock, NeedsClearing);
|
||||
}
|
||||
|
||||
sourceList._memoryBlock = newMemoryBlock;
|
||||
sourceList._capacity = newMemoryBlock.Length;
|
||||
return newSize;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Collections;
|
||||
using System.Numerics;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Recyclable.Collections.Pools;
|
||||
|
||||
@@ -35,7 +36,7 @@ namespace Recyclable.Collections
|
||||
{
|
||||
if (targetItemIdx + growByCount > capacity)
|
||||
{
|
||||
capacity = RecyclableListHelpers<T>.EnsureCapacity(this, capacity + growByCount);
|
||||
capacity = RecyclableListHelpers<T>.ResizeAndCopy(this, checked((int)BitOperations.RoundUpToPowerOf2((uint)(capacity + growByCount))));
|
||||
memorySpan = new(_memoryBlock);
|
||||
available = capacity - targetItemIdx;
|
||||
}
|
||||
@@ -52,13 +53,14 @@ namespace Recyclable.Collections
|
||||
while (i >= available);
|
||||
}
|
||||
|
||||
_capacity = capacity;
|
||||
_count = targetItemIdx;
|
||||
return enumerator;
|
||||
}
|
||||
|
||||
private void AddRangeWithKnownCount(IEnumerable<T> source, int targetItemIdx, int requiredAdditionalCapacity)
|
||||
{
|
||||
_ = RecyclableListHelpers<T>.EnsureCapacity(this, targetItemIdx + requiredAdditionalCapacity);
|
||||
_capacity = RecyclableListHelpers<T>.ResizeAndCopy(this, checked((int)BitOperations.RoundUpToPowerOf2((uint)(targetItemIdx + requiredAdditionalCapacity))));
|
||||
|
||||
Span<T> memorySpan = new(_memoryBlock);
|
||||
foreach (var item in source)
|
||||
@@ -80,7 +82,7 @@ namespace Recyclable.Collections
|
||||
if (initialCapacity >= RecyclableDefaults.InitialCapacity)
|
||||
{
|
||||
_memoryBlock = initialCapacity >= RecyclableDefaults.MinPooledArrayLength
|
||||
? RecyclableArrayPool<T>.Rent(initialCapacity)
|
||||
? RecyclableArrayPool<T>.RentShared(checked((int)BitOperations.RoundUpToPowerOf2((uint)initialCapacity)))
|
||||
: new T[initialCapacity];
|
||||
_capacity = _memoryBlock.Length;
|
||||
}
|
||||
@@ -138,7 +140,7 @@ namespace Recyclable.Collections
|
||||
if (initialCapacity >= RecyclableDefaults.InitialCapacity)
|
||||
{
|
||||
_memoryBlock = initialCapacity >= RecyclableDefaults.MinPooledArrayLength
|
||||
? RecyclableArrayPool<T>.Rent(initialCapacity)
|
||||
? RecyclableArrayPool<T>.RentShared(checked((int)BitOperations.RoundUpToPowerOf2((uint)initialCapacity)))
|
||||
: new T[initialCapacity];
|
||||
_capacity = _memoryBlock.Length;
|
||||
}
|
||||
@@ -172,7 +174,7 @@ namespace Recyclable.Collections
|
||||
{
|
||||
if (_capacity != value)
|
||||
{
|
||||
RecyclableListHelpers<T>.ResizeAndCopy(this, value);
|
||||
_capacity = RecyclableListHelpers<T>.ResizeAndCopy(this, checked((int)BitOperations.RoundUpToPowerOf2((uint)value)));
|
||||
_version++;
|
||||
}
|
||||
}
|
||||
@@ -200,7 +202,7 @@ namespace Recyclable.Collections
|
||||
{
|
||||
if (_capacity < _count + items.Length)
|
||||
{
|
||||
_ = RecyclableListHelpers<T>.EnsureCapacity(this, _count + items.Length);
|
||||
_capacity = RecyclableListHelpers<T>.ResizeAndCopy(this, checked((int)BitOperations.RoundUpToPowerOf2((uint)(_count + items.Length))));
|
||||
}
|
||||
|
||||
new Span<T>(items).CopyTo(new Span<T>(_memoryBlock, _count, items.Length));
|
||||
@@ -213,7 +215,7 @@ namespace Recyclable.Collections
|
||||
{
|
||||
if (_capacity < _count + items.Length)
|
||||
{
|
||||
_ = RecyclableListHelpers<T>.EnsureCapacity(this, _count + items.Length);
|
||||
_capacity = RecyclableListHelpers<T>.ResizeAndCopy(this, checked((int)BitOperations.RoundUpToPowerOf2((uint)(_count + items.Length))));
|
||||
}
|
||||
|
||||
items.CopyTo(new Span<T>(_memoryBlock, _count, items.Length));
|
||||
@@ -226,7 +228,7 @@ namespace Recyclable.Collections
|
||||
{
|
||||
if (_capacity < _count + items.Count)
|
||||
{
|
||||
_ = RecyclableListHelpers<T>.EnsureCapacity(this, _count + items.Count);
|
||||
_capacity = RecyclableListHelpers<T>.ResizeAndCopy(this, checked((int)BitOperations.RoundUpToPowerOf2((uint)(_count + items.Count))));
|
||||
}
|
||||
|
||||
items.CopyTo(_memoryBlock, _count);
|
||||
@@ -239,7 +241,7 @@ namespace Recyclable.Collections
|
||||
{
|
||||
if (_capacity < _count + items.Count)
|
||||
{
|
||||
_ = RecyclableListHelpers<T>.EnsureCapacity(this, _count + items.Count);
|
||||
_capacity = RecyclableListHelpers<T>.ResizeAndCopy(this, checked((int)BitOperations.RoundUpToPowerOf2((uint)(_count + items.Count))));
|
||||
}
|
||||
|
||||
items.CopyTo(_memoryBlock, _count);
|
||||
@@ -252,7 +254,7 @@ namespace Recyclable.Collections
|
||||
{
|
||||
if (_capacity < _count + items._count)
|
||||
{
|
||||
_ = RecyclableListHelpers<T>.EnsureCapacity(this, _count + items._count);
|
||||
_capacity = RecyclableListHelpers<T>.ResizeAndCopy(this, checked((int)BitOperations.RoundUpToPowerOf2((uint)(_count + items._count))));
|
||||
}
|
||||
|
||||
new Span<T>(items._memoryBlock, 0, items._count).CopyTo(new Span<T>(_memoryBlock, _count, items._count));
|
||||
@@ -282,7 +284,7 @@ namespace Recyclable.Collections
|
||||
int targetCapacity = _count + (int)sourceItemsCount;
|
||||
if (_capacity < targetCapacity)
|
||||
{
|
||||
_ = RecyclableListHelpers<T>.EnsureCapacity(this, targetCapacity);
|
||||
_capacity = RecyclableListHelpers<T>.ResizeAndCopy(this, checked((int)BitOperations.RoundUpToPowerOf2((uint)targetCapacity)));
|
||||
}
|
||||
|
||||
Span<T> targetSpan = new Span<T>(_memoryBlock)[_count..],
|
||||
@@ -291,7 +293,7 @@ namespace Recyclable.Collections
|
||||
int blockIndex,
|
||||
sourceBlockSize = items.BlockSize,
|
||||
// TODO: Convert to bit-shift
|
||||
lastBlockIndex = (int)(sourceItemsCount / sourceBlockSize) - 1;
|
||||
lastBlockIndex = (int)(sourceItemsCount >> items._blockSizePow2BitShift) - 1;
|
||||
|
||||
for (blockIndex = 0; blockIndex <= lastBlockIndex; blockIndex++)
|
||||
{
|
||||
@@ -381,7 +383,7 @@ namespace Recyclable.Collections
|
||||
int requestedCapacity = oldCount + 1;
|
||||
if (_capacity < requestedCapacity)
|
||||
{
|
||||
_ = RecyclableListHelpers<T>.EnsureCapacity(this, requestedCapacity);
|
||||
_capacity = RecyclableListHelpers<T>.ResizeAndCopy(this, checked((int)BitOperations.RoundUpToPowerOf2((uint)requestedCapacity)));
|
||||
}
|
||||
|
||||
if (oldCount > 0)
|
||||
@@ -468,7 +470,7 @@ namespace Recyclable.Collections
|
||||
{
|
||||
_capacity = 0;
|
||||
// If anything, it has been already cleared by .Clear(), Remove() or RemoveAt() methods, as the list was modified / disposed.
|
||||
RecyclableArrayPool<T>.Return(_memoryBlock, false);
|
||||
RecyclableArrayPool<T>.ReturnShared(_memoryBlock, false);
|
||||
}
|
||||
|
||||
GC.SuppressFinalize(this);
|
||||
|
||||
@@ -107,25 +107,6 @@ namespace Recyclable.Collections
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
public static long EnsureCapacity(RecyclableLongList<T> list, long requestedCapacity)
|
||||
{
|
||||
long newCapacity = list._capacity > 0
|
||||
? checked((long)BitOperations.RoundUpToPowerOf2((ulong)requestedCapacity))
|
||||
: requestedCapacity;
|
||||
|
||||
int blockSize = list._blockSize;
|
||||
newCapacity = Resize(list, blockSize, list._blockSizePow2BitShift, newCapacity);
|
||||
if (blockSize != list._memoryBlocks[0].Length && newCapacity > 0)
|
||||
{
|
||||
SetupBlockArrayPooling(list, list._memoryBlocks[0].Length);
|
||||
list._blockSizeMinus1 = list._blockSize - 1;
|
||||
}
|
||||
|
||||
list._capacity = newCapacity;
|
||||
return newCapacity;
|
||||
}
|
||||
|
||||
public static IEnumerable<T> Enumerate(T[][] arrays, int chunkSize, long totalCount)
|
||||
{
|
||||
long currentCount = 0;
|
||||
@@ -174,10 +155,9 @@ namespace Recyclable.Collections
|
||||
/// gain - 1+ operation less for each call. If you need this functionality, you need to implement it on a higher level.
|
||||
/// </remarks>
|
||||
/// <returns>The maximum no. of items <paramref name="list"/> can store.</returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
public static long Resize(RecyclableLongList<T> list, int minBlockSize, byte minBlockSizePow2Shift, long newCapacity)
|
||||
{
|
||||
ArrayPool<T> blockArrayPool = list._blockArrayPool;
|
||||
int sourceBlockCount = list._reservedBlockCount;
|
||||
int requiredBlockCount = checked((int)(newCapacity >> minBlockSizePow2Shift) + ((newCapacity & (minBlockSize - 1)) > 0 ? 1 : 0));
|
||||
int blockIndex;
|
||||
@@ -186,7 +166,7 @@ namespace Recyclable.Collections
|
||||
if (requiredBlockCount > (list._memoryBlocks?.Length ?? 0))
|
||||
{
|
||||
// Allocate new memory block for all arrays
|
||||
newMemoryBlocks = requiredBlockCount >= RecyclableDefaults.MinPooledArrayLength ? list._memoryBlocksPool.Rent(requiredBlockCount) : new T[requiredBlockCount][];
|
||||
newMemoryBlocks = requiredBlockCount >= RecyclableDefaults.MinPooledArrayLength ? RecyclableArrayPool<T[]>.RentShared(requiredBlockCount) : new T[requiredBlockCount][];
|
||||
|
||||
// Copy arrays from the old memory block for all arrays
|
||||
if (sourceBlockCount > 0)
|
||||
@@ -195,7 +175,7 @@ namespace Recyclable.Collections
|
||||
// We can now return the old memory block for all arrays itself
|
||||
if (sourceBlockCount >= RecyclableDefaults.MinPooledArrayLength)
|
||||
{
|
||||
list._memoryBlocksPool.Return(list._memoryBlocks!, NeedsClearing);
|
||||
RecyclableArrayPool<T[]>.ReturnShared(list._memoryBlocks!, NeedsClearing);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -212,9 +192,10 @@ namespace Recyclable.Collections
|
||||
if (minBlockSize >= RecyclableDefaults.MinPooledArrayLength)
|
||||
{
|
||||
blockIndex = sourceBlockCount;
|
||||
ref OneSizeArrayPool<T> blockArrayPool = ref RecyclableArrayPool<T>.Shared(minBlockSize);
|
||||
while (true)
|
||||
{
|
||||
newMemoryBlocks[blockIndex] = blockArrayPool.Rent(minBlockSize);
|
||||
newMemoryBlocks[blockIndex] = blockArrayPool.Rent();
|
||||
if (blockIndex + 1 < requiredBlockCount)
|
||||
{
|
||||
blockIndex++;
|
||||
@@ -248,13 +229,10 @@ namespace Recyclable.Collections
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
public static void SetupBlockArrayPooling(RecyclableLongList<T> list, int blockSize, ArrayPool<T>? blockArrayPool = null)
|
||||
public static void SetupBlockArrayPooling(RecyclableLongList<T> list, int blockSize)
|
||||
{
|
||||
list._blockSize = blockSize;
|
||||
list._blockSizePow2BitShift = (byte)(31 - BitOperations.LeadingZeroCount((uint)blockSize));
|
||||
list._blockArrayPool = blockSize >= RecyclableDefaults.MinPooledArrayLength
|
||||
? blockArrayPool ?? RecyclableArrayPool<T>.Shared(blockSize)
|
||||
: RecyclableArrayPool<T>.Null;
|
||||
}
|
||||
|
||||
#pragma warning disable CA2208
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using System.Buffers;
|
||||
using System.Collections;
|
||||
using System.Collections;
|
||||
using System.Numerics;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Recyclable.Collections.Pools;
|
||||
|
||||
[assembly: InternalsVisibleTo("Recyclable.Collections.Benchmarks")]
|
||||
[assembly: InternalsVisibleTo("Recyclable.CollectionsTests")]
|
||||
@@ -10,8 +10,6 @@ namespace Recyclable.Collections
|
||||
{
|
||||
public partial class RecyclableLongList<T> : IList<T>, IReadOnlyList<T>, IDisposable
|
||||
{
|
||||
private static readonly ArrayPool<T[]> _defaultMemoryBlocksPool = ArrayPool<T[]>.Create();
|
||||
private static readonly ArrayPool<T> _defaultBlockArrayPool = ArrayPool<T>.Create();
|
||||
#pragma warning disable CA1825
|
||||
private static readonly T[][] _emptyMemoryBlocksArray = new T[0][];
|
||||
private static readonly T[] _emptyBlockArray = new T[0];
|
||||
@@ -26,8 +24,6 @@ namespace Recyclable.Collections
|
||||
internal int _nextItemIndex;
|
||||
private int _reservedBlockCount;
|
||||
|
||||
private readonly ArrayPool<T[]> _memoryBlocksPool;
|
||||
private ArrayPool<T> _blockArrayPool;
|
||||
#nullable disable
|
||||
internal T[][] _memoryBlocks;
|
||||
#nullable restore
|
||||
@@ -42,7 +38,7 @@ namespace Recyclable.Collections
|
||||
_version++;
|
||||
if (_capacity != value)
|
||||
{
|
||||
_capacity = Helpers.Resize(this, _blockSize, _blockSizePow2BitShift, value);
|
||||
_capacity = Helpers.Resize(this, _blockSize, _blockSizePow2BitShift, checked((long)BitOperations.RoundUpToPowerOf2((ulong)value)));
|
||||
_version++;
|
||||
}
|
||||
}
|
||||
@@ -87,7 +83,7 @@ namespace Recyclable.Collections
|
||||
{
|
||||
if (copied + growByCount > capacity)
|
||||
{
|
||||
capacity = Helpers.EnsureCapacity(this, capacity + growByCount);
|
||||
capacity = Helpers.Resize(this, _blockSize, _blockSizePow2BitShift, checked((long)BitOperations.RoundUpToPowerOf2((ulong)(capacity + growByCount))));
|
||||
memoryBlocksCount = _reservedBlockCount;
|
||||
if (blockSize != _blockSize)
|
||||
{
|
||||
@@ -118,6 +114,7 @@ namespace Recyclable.Collections
|
||||
_nextItemIndex = 0;
|
||||
}
|
||||
|
||||
_capacity = capacity;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -151,7 +148,7 @@ namespace Recyclable.Collections
|
||||
long requiredCapacity = copied + requiredAdditionalCapacity;
|
||||
if (_capacity < requiredCapacity)
|
||||
{
|
||||
_ = Helpers.EnsureCapacity(this, requiredCapacity);
|
||||
_capacity = Helpers.Resize(this, _blockSize, _blockSizePow2BitShift, checked((long)BitOperations.RoundUpToPowerOf2((ulong)requiredCapacity)));
|
||||
blockSize = _blockSize;
|
||||
}
|
||||
|
||||
@@ -182,57 +179,40 @@ namespace Recyclable.Collections
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
|
||||
#pragma warning disable CS8618 // The reported properties / fields are set by SetupBlockArrayPooling
|
||||
public RecyclableLongList(int minBlockSize = RecyclableDefaults.BlockSize, long? expectedItemsCount = default, ArrayPool<T[]>? memoryBlocksPool = default, ArrayPool<T>? blockArrayPool = default)
|
||||
public RecyclableLongList(int minBlockSize = RecyclableDefaults.BlockSize, long? expectedItemsCount = default)
|
||||
#pragma warning restore CS8618
|
||||
{
|
||||
_memoryBlocksPool = memoryBlocksPool ?? _defaultMemoryBlocksPool;
|
||||
minBlockSize = checked((int)BitOperations.RoundUpToPowerOf2((uint)minBlockSize));
|
||||
|
||||
if (expectedItemsCount > 0)
|
||||
{
|
||||
minBlockSize = checked((int)BitOperations.RoundUpToPowerOf2((uint)minBlockSize));
|
||||
Helpers.SetupBlockArrayPooling(this, minBlockSize, blockArrayPool);
|
||||
_capacity = Helpers.Resize(this, minBlockSize, _blockSizePow2BitShift, expectedItemsCount.Value);
|
||||
if (_blockSize != _memoryBlocks![0].Length && _capacity > 0)
|
||||
{
|
||||
Helpers.SetupBlockArrayPooling(this, _memoryBlocks[0].Length, blockArrayPool);
|
||||
_blockSizeMinus1 = _blockSize - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
_blockSizeMinus1 = minBlockSize - 1;
|
||||
}
|
||||
Helpers.SetupBlockArrayPooling(this, minBlockSize);
|
||||
_capacity = Helpers.Resize(this, minBlockSize, _blockSizePow2BitShift, checked((long)BitOperations.RoundUpToPowerOf2((ulong)expectedItemsCount.Value)));
|
||||
_blockSizeMinus1 = minBlockSize - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
Helpers.SetupBlockArrayPooling(this, checked((int)BitOperations.RoundUpToPowerOf2((uint)minBlockSize)), blockArrayPool);
|
||||
Helpers.SetupBlockArrayPooling(this, minBlockSize);
|
||||
_blockSizeMinus1 = _blockSize - 1;
|
||||
_memoryBlocks = _emptyMemoryBlocksArray;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma warning disable CS8618 // The reported properties / fields are set by SetupBlockArrayPooling
|
||||
public RecyclableLongList(in T[] source, int minBlockSize = RecyclableDefaults.BlockSize, long? expectedItemsCount = default, ArrayPool<T[]>? memoryBlocksPool = default, ArrayPool<T>? blockArrayPool = default)
|
||||
public RecyclableLongList(in T[] source, int minBlockSize = RecyclableDefaults.BlockSize, long? expectedItemsCount = default)
|
||||
#pragma warning restore CS8618
|
||||
{
|
||||
_memoryBlocksPool = memoryBlocksPool ?? _defaultMemoryBlocksPool;
|
||||
minBlockSize = checked((int)BitOperations.RoundUpToPowerOf2((uint)minBlockSize));
|
||||
|
||||
if (expectedItemsCount > 0)
|
||||
{
|
||||
minBlockSize = checked((int)BitOperations.RoundUpToPowerOf2((uint)minBlockSize));
|
||||
Helpers.SetupBlockArrayPooling(this, minBlockSize, blockArrayPool);
|
||||
_capacity = Helpers.Resize(this, minBlockSize, _blockSizePow2BitShift, expectedItemsCount.Value);
|
||||
if (minBlockSize != _memoryBlocks![0].Length && _capacity > 0)
|
||||
{
|
||||
Helpers.SetupBlockArrayPooling(this, _memoryBlocks[0].Length, blockArrayPool);
|
||||
_blockSizeMinus1 = _blockSize - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
_blockSizeMinus1 = minBlockSize - 1;
|
||||
}
|
||||
Helpers.SetupBlockArrayPooling(this, minBlockSize);
|
||||
_capacity = Helpers.Resize(this, minBlockSize, _blockSizePow2BitShift, checked((long)BitOperations.RoundUpToPowerOf2((ulong)expectedItemsCount.Value)));
|
||||
_blockSizeMinus1 = minBlockSize - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
Helpers.SetupBlockArrayPooling(this, checked((int)BitOperations.RoundUpToPowerOf2((uint)minBlockSize)), blockArrayPool);
|
||||
Helpers.SetupBlockArrayPooling(this, minBlockSize);
|
||||
_blockSizeMinus1 = _blockSize - 1;
|
||||
_memoryBlocks = _emptyMemoryBlocksArray;
|
||||
}
|
||||
@@ -241,28 +221,20 @@ namespace Recyclable.Collections
|
||||
}
|
||||
|
||||
#pragma warning disable CS8618 // The reported properties / fields are set by SetupBlockArrayPooling
|
||||
public RecyclableLongList(ReadOnlySpan<T> source, int minBlockSize = RecyclableDefaults.BlockSize, long? expectedItemsCount = default, ArrayPool<T[]>? memoryBlocksPool = default, ArrayPool<T>? blockArrayPool = default)
|
||||
public RecyclableLongList(ReadOnlySpan<T> source, int minBlockSize = RecyclableDefaults.BlockSize, long? expectedItemsCount = default)
|
||||
#pragma warning restore CS8618
|
||||
{
|
||||
_memoryBlocksPool = memoryBlocksPool ?? _defaultMemoryBlocksPool;
|
||||
minBlockSize = checked((int)BitOperations.RoundUpToPowerOf2((uint)minBlockSize));
|
||||
|
||||
if (expectedItemsCount > 0)
|
||||
{
|
||||
minBlockSize = checked((int)BitOperations.RoundUpToPowerOf2((uint)minBlockSize));
|
||||
Helpers.SetupBlockArrayPooling(this, minBlockSize, blockArrayPool);
|
||||
_capacity = Helpers.Resize(this, minBlockSize, _blockSizePow2BitShift, expectedItemsCount.Value);
|
||||
if (minBlockSize != _memoryBlocks![0].Length && _capacity > 0)
|
||||
{
|
||||
Helpers.SetupBlockArrayPooling(this, _memoryBlocks[0].Length, blockArrayPool);
|
||||
_blockSizeMinus1 = _blockSize - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
_blockSizeMinus1 = minBlockSize - 1;
|
||||
}
|
||||
Helpers.SetupBlockArrayPooling(this, minBlockSize);
|
||||
_capacity = Helpers.Resize(this, minBlockSize, _blockSizePow2BitShift, checked((long)BitOperations.RoundUpToPowerOf2((ulong)expectedItemsCount.Value)));
|
||||
_blockSizeMinus1 = minBlockSize - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
Helpers.SetupBlockArrayPooling(this, checked((int)BitOperations.RoundUpToPowerOf2((uint)minBlockSize)), blockArrayPool);
|
||||
Helpers.SetupBlockArrayPooling(this, minBlockSize);
|
||||
_blockSizeMinus1 = _blockSize - 1;
|
||||
_memoryBlocks = _emptyMemoryBlocksArray;
|
||||
}
|
||||
@@ -271,28 +243,20 @@ namespace Recyclable.Collections
|
||||
}
|
||||
|
||||
#pragma warning disable CS8618 // The reported properties / fields are set by SetupBlockArrayPooling
|
||||
public RecyclableLongList(RecyclableList<T> source, int minBlockSize = RecyclableDefaults.BlockSize, long? expectedItemsCount = default, ArrayPool<T[]>? memoryBlocksPool = default, ArrayPool<T>? blockArrayPool = default)
|
||||
public RecyclableLongList(RecyclableList<T> source, int minBlockSize = RecyclableDefaults.BlockSize, long? expectedItemsCount = default)
|
||||
#pragma warning restore CS8618
|
||||
{
|
||||
_memoryBlocksPool = memoryBlocksPool ?? _defaultMemoryBlocksPool;
|
||||
minBlockSize = checked((int)BitOperations.RoundUpToPowerOf2((uint)minBlockSize));
|
||||
|
||||
if (expectedItemsCount > 0)
|
||||
{
|
||||
minBlockSize = checked((int)BitOperations.RoundUpToPowerOf2((uint)minBlockSize));
|
||||
Helpers.SetupBlockArrayPooling(this, minBlockSize, blockArrayPool);
|
||||
_capacity = Helpers.Resize(this, minBlockSize, _blockSizePow2BitShift, expectedItemsCount.Value);
|
||||
if (minBlockSize != _memoryBlocks![0].Length && _capacity > 0)
|
||||
{
|
||||
Helpers.SetupBlockArrayPooling(this, _memoryBlocks[0].Length, blockArrayPool);
|
||||
_blockSizeMinus1 = _blockSize - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
_blockSizeMinus1 = minBlockSize - 1;
|
||||
}
|
||||
Helpers.SetupBlockArrayPooling(this, minBlockSize);
|
||||
_capacity = Helpers.Resize(this, minBlockSize, _blockSizePow2BitShift, checked((long)BitOperations.RoundUpToPowerOf2((ulong)expectedItemsCount.Value)));
|
||||
_blockSizeMinus1 = minBlockSize - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
Helpers.SetupBlockArrayPooling(this, checked((int)BitOperations.RoundUpToPowerOf2((uint)minBlockSize)), blockArrayPool);
|
||||
Helpers.SetupBlockArrayPooling(this, minBlockSize);
|
||||
_blockSizeMinus1 = _blockSize - 1;
|
||||
_memoryBlocks = _emptyMemoryBlocksArray;
|
||||
}
|
||||
@@ -301,28 +265,20 @@ namespace Recyclable.Collections
|
||||
}
|
||||
|
||||
#pragma warning disable CS8618 // The reported properties / fields are set by SetupBlockArrayPooling
|
||||
public RecyclableLongList(RecyclableLongList<T> source, int minBlockSize = RecyclableDefaults.BlockSize, long? expectedItemsCount = default, ArrayPool<T[]>? memoryBlocksPool = default, ArrayPool<T>? blockArrayPool = default)
|
||||
public RecyclableLongList(RecyclableLongList<T> source, int minBlockSize = RecyclableDefaults.BlockSize, long? expectedItemsCount = default)
|
||||
#pragma warning restore CS8618
|
||||
{
|
||||
_memoryBlocksPool = memoryBlocksPool ?? _defaultMemoryBlocksPool;
|
||||
minBlockSize = checked((int)BitOperations.RoundUpToPowerOf2((uint)minBlockSize));
|
||||
|
||||
if (expectedItemsCount > 0)
|
||||
{
|
||||
minBlockSize = checked((int)BitOperations.RoundUpToPowerOf2((uint)minBlockSize));
|
||||
Helpers.SetupBlockArrayPooling(this, minBlockSize, blockArrayPool);
|
||||
_capacity = Helpers.Resize(this, minBlockSize, _blockSizePow2BitShift, expectedItemsCount.Value);
|
||||
if (minBlockSize != _memoryBlocks![0].Length && _capacity > 0)
|
||||
{
|
||||
Helpers.SetupBlockArrayPooling(this, _memoryBlocks[0].Length, blockArrayPool);
|
||||
_blockSizeMinus1 = _blockSize - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
_blockSizeMinus1 = minBlockSize - 1;
|
||||
}
|
||||
Helpers.SetupBlockArrayPooling(this, minBlockSize);
|
||||
_capacity = Helpers.Resize(this, minBlockSize, _blockSizePow2BitShift, checked((long)BitOperations.RoundUpToPowerOf2((ulong)expectedItemsCount.Value)));
|
||||
_blockSizeMinus1 = minBlockSize - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
Helpers.SetupBlockArrayPooling(this, checked((int)BitOperations.RoundUpToPowerOf2((uint)minBlockSize)), blockArrayPool);
|
||||
Helpers.SetupBlockArrayPooling(this, minBlockSize);
|
||||
_blockSizeMinus1 = _blockSize - 1;
|
||||
_memoryBlocks = _emptyMemoryBlocksArray;
|
||||
}
|
||||
@@ -331,28 +287,20 @@ namespace Recyclable.Collections
|
||||
}
|
||||
|
||||
#pragma warning disable CS8618 // The reported properties / fields are set by SetupBlockArrayPooling
|
||||
public RecyclableLongList(List<T> source, int minBlockSize = RecyclableDefaults.BlockSize, long? expectedItemsCount = default, ArrayPool<T[]>? memoryBlocksPool = default, ArrayPool<T>? blockArrayPool = default)
|
||||
public RecyclableLongList(List<T> source, int minBlockSize = RecyclableDefaults.BlockSize, long? expectedItemsCount = default)
|
||||
#pragma warning restore CS8618
|
||||
{
|
||||
_memoryBlocksPool = memoryBlocksPool ?? _defaultMemoryBlocksPool;
|
||||
minBlockSize = checked((int)BitOperations.RoundUpToPowerOf2((uint)minBlockSize));
|
||||
|
||||
if (expectedItemsCount > 0)
|
||||
{
|
||||
minBlockSize = checked((int)BitOperations.RoundUpToPowerOf2((uint)minBlockSize));
|
||||
Helpers.SetupBlockArrayPooling(this, minBlockSize, blockArrayPool);
|
||||
_capacity = Helpers.Resize(this, minBlockSize, _blockSizePow2BitShift, expectedItemsCount.Value);
|
||||
if (minBlockSize != _memoryBlocks![0].Length && _capacity > 0)
|
||||
{
|
||||
Helpers.SetupBlockArrayPooling(this, _memoryBlocks[0].Length, blockArrayPool);
|
||||
_blockSizeMinus1 = _blockSize - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
_blockSizeMinus1 = minBlockSize - 1;
|
||||
}
|
||||
Helpers.SetupBlockArrayPooling(this, minBlockSize);
|
||||
_capacity = Helpers.Resize(this, minBlockSize, _blockSizePow2BitShift, checked((long)BitOperations.RoundUpToPowerOf2((ulong)expectedItemsCount.Value)));
|
||||
_blockSizeMinus1 = minBlockSize - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
Helpers.SetupBlockArrayPooling(this, checked((int)BitOperations.RoundUpToPowerOf2((uint)minBlockSize)), blockArrayPool);
|
||||
Helpers.SetupBlockArrayPooling(this, minBlockSize);
|
||||
_blockSizeMinus1 = _blockSize - 1;
|
||||
_memoryBlocks = _emptyMemoryBlocksArray;
|
||||
}
|
||||
@@ -361,28 +309,20 @@ namespace Recyclable.Collections
|
||||
}
|
||||
|
||||
#pragma warning disable CS8618 // The reported properties / fields are set by SetupBlockArrayPooling
|
||||
public RecyclableLongList(IList<T> source, int minBlockSize = RecyclableDefaults.BlockSize, long? expectedItemsCount = default, ArrayPool<T[]>? memoryBlocksPool = default, ArrayPool<T>? blockArrayPool = default)
|
||||
public RecyclableLongList(IList<T> source, int minBlockSize = RecyclableDefaults.BlockSize, long? expectedItemsCount = default)
|
||||
#pragma warning restore CS8618
|
||||
{
|
||||
_memoryBlocksPool = memoryBlocksPool ?? _defaultMemoryBlocksPool;
|
||||
minBlockSize = checked((int)BitOperations.RoundUpToPowerOf2((uint)minBlockSize));
|
||||
|
||||
if (expectedItemsCount > 0)
|
||||
{
|
||||
minBlockSize = checked((int)BitOperations.RoundUpToPowerOf2((uint)minBlockSize));
|
||||
Helpers.SetupBlockArrayPooling(this, minBlockSize, blockArrayPool);
|
||||
_capacity = Helpers.Resize(this, minBlockSize, _blockSizePow2BitShift, expectedItemsCount.Value);
|
||||
if (minBlockSize != _memoryBlocks![0].Length && _capacity > 0)
|
||||
{
|
||||
Helpers.SetupBlockArrayPooling(this, _memoryBlocks[0].Length, blockArrayPool);
|
||||
_blockSizeMinus1 = _blockSize - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
_blockSizeMinus1 = minBlockSize - 1;
|
||||
}
|
||||
Helpers.SetupBlockArrayPooling(this, minBlockSize);
|
||||
_capacity = Helpers.Resize(this, minBlockSize, _blockSizePow2BitShift, checked((long)BitOperations.RoundUpToPowerOf2((ulong)expectedItemsCount.Value)));
|
||||
_blockSizeMinus1 = minBlockSize - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
Helpers.SetupBlockArrayPooling(this, checked((int)BitOperations.RoundUpToPowerOf2((uint)minBlockSize)), blockArrayPool);
|
||||
Helpers.SetupBlockArrayPooling(this, minBlockSize);
|
||||
_blockSizeMinus1 = _blockSize - 1;
|
||||
_memoryBlocks = _emptyMemoryBlocksArray;
|
||||
}
|
||||
@@ -391,28 +331,20 @@ namespace Recyclable.Collections
|
||||
}
|
||||
|
||||
#pragma warning disable CS8618 // The reported properties / fields are set by SetupBlockArrayPooling
|
||||
public RecyclableLongList(IEnumerable<T> source, int minBlockSize = RecyclableDefaults.BlockSize, long? expectedItemsCount = default, ArrayPool<T[]>? memoryBlocksPool = default, ArrayPool<T>? blockArrayPool = default)
|
||||
public RecyclableLongList(IEnumerable<T> source, int minBlockSize = RecyclableDefaults.BlockSize, long? expectedItemsCount = default)
|
||||
#pragma warning restore CS8618
|
||||
{
|
||||
_memoryBlocksPool = memoryBlocksPool ?? _defaultMemoryBlocksPool;
|
||||
minBlockSize = checked((int)BitOperations.RoundUpToPowerOf2((uint)minBlockSize));
|
||||
|
||||
if (expectedItemsCount > 0)
|
||||
{
|
||||
minBlockSize = checked((int)BitOperations.RoundUpToPowerOf2((uint)minBlockSize));
|
||||
Helpers.SetupBlockArrayPooling(this, minBlockSize, blockArrayPool);
|
||||
_capacity = Helpers.Resize(this, minBlockSize, _blockSizePow2BitShift, expectedItemsCount.Value);
|
||||
if (minBlockSize != _memoryBlocks![0].Length && _capacity > 0)
|
||||
{
|
||||
Helpers.SetupBlockArrayPooling(this, _memoryBlocks[0].Length, blockArrayPool);
|
||||
_blockSizeMinus1 = _blockSize - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
_blockSizeMinus1 = minBlockSize - 1;
|
||||
}
|
||||
Helpers.SetupBlockArrayPooling(this, minBlockSize);
|
||||
_capacity = Helpers.Resize(this, minBlockSize, _blockSizePow2BitShift, checked((int)BitOperations.RoundUpToPowerOf2((uint)expectedItemsCount.Value)));
|
||||
_blockSizeMinus1 = minBlockSize - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
Helpers.SetupBlockArrayPooling(this, checked((int)BitOperations.RoundUpToPowerOf2((uint)minBlockSize)), blockArrayPool);
|
||||
Helpers.SetupBlockArrayPooling(this, minBlockSize);
|
||||
_blockSizeMinus1 = _blockSize - 1;
|
||||
_memoryBlocks = _emptyMemoryBlocksArray;
|
||||
}
|
||||
@@ -447,7 +379,7 @@ namespace Recyclable.Collections
|
||||
{
|
||||
if (_capacity < _longCount + 1)
|
||||
{
|
||||
_ = Helpers.EnsureCapacity(this, _longCount + 1);
|
||||
_capacity = Helpers.Resize(this, _blockSize, _blockSizePow2BitShift, checked((long)BitOperations.RoundUpToPowerOf2((ulong)(_longCount + 1))));
|
||||
}
|
||||
|
||||
_memoryBlocks[_nextItemBlockIndex][_nextItemIndex++] = item;
|
||||
@@ -480,7 +412,7 @@ namespace Recyclable.Collections
|
||||
long targetCapacity = _longCount + items.LongLength;
|
||||
if (_capacity < targetCapacity)
|
||||
{
|
||||
_ = Helpers.EnsureCapacity(this, targetCapacity);
|
||||
_capacity = Helpers.Resize(this, _blockSize, _blockSizePow2BitShift, checked((long)BitOperations.RoundUpToPowerOf2((ulong)targetCapacity)));
|
||||
}
|
||||
|
||||
int blockSize = _blockSize,
|
||||
@@ -529,7 +461,7 @@ namespace Recyclable.Collections
|
||||
long targetCapacity = _longCount + items.Count;
|
||||
if (_capacity < targetCapacity)
|
||||
{
|
||||
_ = Helpers.EnsureCapacity(this, targetCapacity);
|
||||
_capacity = Helpers.Resize(this, _blockSize, _blockSizePow2BitShift, checked((long)BitOperations.RoundUpToPowerOf2((ulong)targetCapacity)));
|
||||
}
|
||||
|
||||
int blockSize = _blockSize,
|
||||
@@ -570,7 +502,7 @@ namespace Recyclable.Collections
|
||||
long targetCapacity = _longCount + itemsSpan.Length;
|
||||
if (_capacity < targetCapacity)
|
||||
{
|
||||
_ = Helpers.EnsureCapacity(this, targetCapacity);
|
||||
_capacity = Helpers.Resize(this, _blockSize, _blockSizePow2BitShift, checked((long)BitOperations.RoundUpToPowerOf2((ulong)targetCapacity)));
|
||||
}
|
||||
|
||||
int blockSize = _blockSize,
|
||||
@@ -620,7 +552,7 @@ namespace Recyclable.Collections
|
||||
|
||||
if (_capacity < targetCapacity)
|
||||
{
|
||||
_ = Helpers.EnsureCapacity(this, targetCapacity);
|
||||
_capacity = Helpers.Resize(this, _blockSize, _blockSizePow2BitShift, checked((long)BitOperations.RoundUpToPowerOf2((ulong)targetCapacity)));
|
||||
}
|
||||
|
||||
int blockSize = _blockSize,
|
||||
@@ -691,7 +623,7 @@ namespace Recyclable.Collections
|
||||
long targetCapacity = _longCount + items.Count;
|
||||
if (_capacity < targetCapacity)
|
||||
{
|
||||
_ = Helpers.EnsureCapacity(this, targetCapacity);
|
||||
_capacity = Helpers.Resize(this, _blockSize, _blockSizePow2BitShift, checked((long)BitOperations.RoundUpToPowerOf2((ulong)targetCapacity)));
|
||||
}
|
||||
|
||||
int blockSize = _blockSize,
|
||||
@@ -739,7 +671,7 @@ namespace Recyclable.Collections
|
||||
long targetCapacity = _longCount + items.Count;
|
||||
if (_capacity < targetCapacity)
|
||||
{
|
||||
_ = Helpers.EnsureCapacity(this, targetCapacity);
|
||||
_capacity = Helpers.Resize(this, _blockSize, _blockSizePow2BitShift, checked((long)BitOperations.RoundUpToPowerOf2((ulong)targetCapacity)));
|
||||
}
|
||||
|
||||
int blockSize = _blockSize,
|
||||
@@ -748,7 +680,7 @@ namespace Recyclable.Collections
|
||||
|
||||
// We're better off to temporarily copy it to a fixed array,
|
||||
// than copying them item by item. We may run into OOMs, though.
|
||||
T[] itemsBuffer = items.Count >= RecyclableDefaults.MinPooledArrayLength ? _defaultBlockArrayPool.Rent(items.Count) : new T[items.Count];
|
||||
T[] itemsBuffer = items.Count >= RecyclableDefaults.MinPooledArrayLength ? RecyclableArrayPool<T>.RentShared((int)BitOperations.RoundUpToPowerOf2((uint)items.Count)) : new T[items.Count];
|
||||
try
|
||||
{
|
||||
items.CopyTo(itemsBuffer, 0);
|
||||
@@ -779,7 +711,7 @@ namespace Recyclable.Collections
|
||||
{
|
||||
if (items.Count >= RecyclableDefaults.MinPooledArrayLength)
|
||||
{
|
||||
_defaultBlockArrayPool.Return(itemsBuffer, NeedsClearing);
|
||||
RecyclableArrayPool<T>.ReturnShared(itemsBuffer, NeedsClearing);
|
||||
}
|
||||
|
||||
_version++;
|
||||
@@ -831,11 +763,10 @@ namespace Recyclable.Collections
|
||||
{
|
||||
T[][] memoryBlocks = _memoryBlocks;
|
||||
int memoryBlocksCount = _reservedBlockCount;
|
||||
ArrayPool<T> blockArrayPool = _blockArrayPool;
|
||||
int toRemoveIdx = 0;
|
||||
while (toRemoveIdx < memoryBlocksCount)
|
||||
{
|
||||
blockArrayPool.Return(memoryBlocks[toRemoveIdx++], NeedsClearing);
|
||||
RecyclableArrayPool<T>.ReturnShared(memoryBlocks[toRemoveIdx++], NeedsClearing);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -999,7 +930,7 @@ namespace Recyclable.Collections
|
||||
{
|
||||
if (_blockSize >= RecyclableDefaults.MinPooledArrayLength)
|
||||
{
|
||||
_blockArrayPool.Return(_memoryBlocks[index], NeedsClearing);
|
||||
RecyclableArrayPool<T>.ReturnShared(_memoryBlocks[index], NeedsClearing);
|
||||
_memoryBlocks[index] = _emptyBlockArray;
|
||||
}
|
||||
else
|
||||
@@ -1108,7 +1039,7 @@ namespace Recyclable.Collections
|
||||
if (_memoryBlocks.Length >= RecyclableDefaults.MinPooledArrayLength)
|
||||
{
|
||||
// If anything, it has been already cleared by .Clear(), Remove() or RemoveAt() methods, as the list was modified / disposed.
|
||||
_memoryBlocksPool.Return(_memoryBlocks, false);
|
||||
RecyclableArrayPool<T[]>.ReturnShared(_memoryBlocks, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -13,5 +13,10 @@ namespace Recyclable.Collections
|
||||
Contract.EnsuresOnThrow<ArgumentOutOfRangeException>(false);
|
||||
throw new ArgumentOutOfRangeException(argumentName, message);
|
||||
}
|
||||
|
||||
public static void ThrowWrongReturnedArraySizeException(int returnedLength, int blockSize)
|
||||
{
|
||||
throw new InvalidOperationException($"The array size {returnedLength} doesn't match the size {blockSize} of the pool buffer and cannot be returned to this pool.");
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user