Revert "Support for custom boundaries implemented. v1 - will be reverted due to 5x slower performance."
This reverts commit 22d8593e1f.
This commit is contained in:
1 parent
22d8593e1f
commit
2ff1aab655
12 files changed
+84
-184
No files matched your search
@@ -2,21 +2,23 @@ namespace Recyclable.Collections
|
|||||||
{
|
{
|
||||||
internal sealed class MemoryBucket<T>
|
internal sealed class MemoryBucket<T>
|
||||||
{
|
{
|
||||||
public MemoryBucket(Array memory, MemoryBucket<T> nextBucket)
|
public MemoryBucket(T[] memory, MemoryBucket<T> nextBucket)
|
||||||
{
|
{
|
||||||
_memory = memory;
|
_memory = memory;
|
||||||
_nextBucket = nextBucket;
|
_nextBucket = nextBucket;
|
||||||
}
|
}
|
||||||
|
|
||||||
public MemoryBucket(Array memory)
|
public MemoryBucket(T[] memory)
|
||||||
{
|
{
|
||||||
_memory = memory;
|
_memory = memory;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Array _memory;
|
#pragma warning disable RCS1085
|
||||||
public Array Memory { get => _memory; set => _memory = value; }
|
private T[] _memory;
|
||||||
|
public T[] Memory { get => _memory; set => _memory = value; }
|
||||||
|
|
||||||
private MemoryBucket<T>? _nextBucket;
|
private MemoryBucket<T>? _nextBucket;
|
||||||
public MemoryBucket<T>? NextBucket { get => _nextBucket; set => _nextBucket = value; }
|
public MemoryBucket<T>? NextBucket { get => _nextBucket; set => _nextBucket = value; }
|
||||||
|
#pragma warning restore RCS1085
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -39,7 +39,7 @@
|
|||||||
_ = Task.Run(ReleaseMemoryOnExcess);
|
_ = Task.Run(ReleaseMemoryOnExcess);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Array Rent()
|
public T[] Rent()
|
||||||
{
|
{
|
||||||
MemoryBucket<T>? bucket;
|
MemoryBucket<T>? bucket;
|
||||||
Enter();
|
Enter();
|
||||||
@@ -55,10 +55,10 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
Exit();
|
Exit();
|
||||||
return bucket != null ? bucket.Memory : Array.CreateInstance(typeof(T), _blockSize);
|
return bucket != null ? bucket.Memory : new T[_blockSize];
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ReturnUnchecked(Array array, bool clearArray)
|
public void ReturnUnchecked(T[] array, bool clearArray)
|
||||||
{
|
{
|
||||||
MemoryBucket<T> bucket = new(array);
|
MemoryBucket<T> bucket = new(array);
|
||||||
if (clearArray)
|
if (clearArray)
|
||||||
|
|||||||
@@ -4,95 +4,24 @@ namespace Recyclable.Collections.Pools
|
|||||||
{
|
{
|
||||||
public readonly struct RecyclableArrayPool<T>
|
public readonly struct RecyclableArrayPool<T>
|
||||||
{
|
{
|
||||||
private const int MaxArraySize = 32;
|
internal static readonly OneSizeArrayPool<T>[] _pools = new OneSizeArrayPool<T>[32];
|
||||||
internal static readonly OneSizeArrayPool<T>[] _pools = new OneSizeArrayPool<T>[MaxArraySize];
|
public static T[] RentShared(int blockSize) => _pools[31 - BitOperations.LeadingZeroCount((uint)blockSize)].Rent();
|
||||||
internal static readonly Dictionary<int, OneSizeArrayPool<T>[]> _poolsWithBoundaries = new();
|
|
||||||
|
|
||||||
public static Array RentShared(int blockSize, int lowerBound)
|
|
||||||
{
|
|
||||||
OneSizeArrayPool<T>[]? pools;
|
|
||||||
lock(_poolsWithBoundaries)
|
|
||||||
{
|
|
||||||
if (!_poolsWithBoundaries.TryGetValue(lowerBound, out pools))
|
|
||||||
{
|
|
||||||
pools = _poolsWithBoundaries[lowerBound] = new OneSizeArrayPool<T>[MaxArraySize];
|
|
||||||
InitializePools(pools);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return pools[31 - BitOperations.LeadingZeroCount((uint)blockSize)].Rent();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Array RentShared(int blockSize) => _pools[31 - BitOperations.LeadingZeroCount((uint)blockSize)].Rent();
|
|
||||||
public static T[] RentSharedAsTyped(int blockSize) => (T[])_pools[31 - BitOperations.LeadingZeroCount((uint)blockSize)].Rent();
|
|
||||||
|
|
||||||
public static void ReturnShared(in T[] memoryBlock, bool needsClearing)
|
public static void ReturnShared(in T[] memoryBlock, bool needsClearing)
|
||||||
{
|
=> _pools[31 - BitOperations.LeadingZeroCount((uint)memoryBlock.Length)].ReturnUnchecked(memoryBlock, needsClearing);
|
||||||
if (memoryBlock.GetLowerBound(0) == 0)
|
|
||||||
{
|
|
||||||
_pools[31 - BitOperations.LeadingZeroCount((uint)memoryBlock.Length)].ReturnUnchecked(memoryBlock, needsClearing);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
OneSizeArrayPool<T>[] pools;
|
|
||||||
lock(_poolsWithBoundaries)
|
|
||||||
{
|
|
||||||
pools = _poolsWithBoundaries[memoryBlock.GetLowerBound(0)];
|
|
||||||
}
|
|
||||||
|
|
||||||
pools[31 - BitOperations.LeadingZeroCount((uint)memoryBlock.Length)].ReturnUnchecked(memoryBlock, needsClearing);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void ReturnShared(in Array memoryBlock, bool needsClearing)
|
|
||||||
{
|
|
||||||
if (memoryBlock.GetLowerBound(0) == 0)
|
|
||||||
{
|
|
||||||
_pools[31 - BitOperations.LeadingZeroCount((uint)memoryBlock.Length)].ReturnUnchecked(memoryBlock, needsClearing);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
OneSizeArrayPool<T>[] pools;
|
|
||||||
lock(_poolsWithBoundaries)
|
|
||||||
{
|
|
||||||
pools = _poolsWithBoundaries[memoryBlock.GetLowerBound(0)];
|
|
||||||
}
|
|
||||||
|
|
||||||
pools[31 - BitOperations.LeadingZeroCount((uint)memoryBlock.Length)].ReturnUnchecked(memoryBlock, needsClearing);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ref OneSizeArrayPool<T> Shared(int blockSize)
|
public static ref OneSizeArrayPool<T> Shared(int blockSize)
|
||||||
=> ref _pools[31 - BitOperations.LeadingZeroCount((uint)blockSize)];
|
=> ref _pools[31 - BitOperations.LeadingZeroCount((uint)blockSize)];
|
||||||
|
|
||||||
public static ref OneSizeArrayPool<T> SharedWithBoundaries(int blockSize, int lowerBound)
|
|
||||||
{
|
|
||||||
OneSizeArrayPool<T>[]? pools;
|
|
||||||
lock(_poolsWithBoundaries)
|
|
||||||
{
|
|
||||||
if (!_poolsWithBoundaries.TryGetValue(lowerBound, out pools))
|
|
||||||
{
|
|
||||||
pools = _poolsWithBoundaries[lowerBound] = new OneSizeArrayPool<T>[MaxArraySize];
|
|
||||||
InitializePools(pools);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ref pools[31 - BitOperations.LeadingZeroCount((uint)blockSize)];
|
|
||||||
}
|
|
||||||
|
|
||||||
static RecyclableArrayPool()
|
static RecyclableArrayPool()
|
||||||
{
|
{
|
||||||
InitializePools(_pools);
|
var pools = _pools;
|
||||||
_ = Task.Run(CheckAndReportMemoryPressure);
|
for (var arraySize = 0; arraySize < 32; arraySize++)
|
||||||
}
|
|
||||||
|
|
||||||
private static void InitializePools(OneSizeArrayPool<T>[] pools)
|
|
||||||
{
|
|
||||||
for (var arraySize = 0; arraySize < MaxArraySize; arraySize++)
|
|
||||||
{
|
{
|
||||||
int blockSize = 1 << arraySize;
|
int blockSize = 1 << arraySize;
|
||||||
pools[arraySize] = new OneSizeArrayPool<T>(blockSize, 1000);
|
pools[arraySize] = new OneSizeArrayPool<T>(blockSize, 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_ = Task.Run(CheckAndReportMemoryPressure);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static readonly OneSizeArrayPool<T> Null = new(0, 0);
|
public static readonly OneSizeArrayPool<T> Null = new(0, 0);
|
||||||
|
|||||||
@@ -1,6 +1,10 @@
|
|||||||
|
using System;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Recyclable.Collections
|
namespace Recyclable.Collections
|
||||||
{
|
{
|
||||||
@@ -15,7 +19,7 @@ namespace Recyclable.Collections
|
|||||||
var enumerator = items.GetEnumerator();
|
var enumerator = items.GetEnumerator();
|
||||||
|
|
||||||
int capacity = list._capacity;
|
int capacity = list._capacity;
|
||||||
memorySpan = new((T[])list._memoryBlock);
|
memorySpan = new(list._memoryBlock);
|
||||||
if (enumerator.MoveNext())
|
if (enumerator.MoveNext())
|
||||||
{
|
{
|
||||||
int available = capacity - targetItemIndex;
|
int available = capacity - targetItemIndex;
|
||||||
@@ -24,7 +28,7 @@ namespace Recyclable.Collections
|
|||||||
if (targetItemIndex + growByCount > capacity)
|
if (targetItemIndex + growByCount > capacity)
|
||||||
{
|
{
|
||||||
capacity = RecyclableListHelpers<T>.ResizeAndCopy(list, targetItemIndex, checked((int)BitOperations.RoundUpToPowerOf2((uint)(targetItemIndex + growByCount))));
|
capacity = RecyclableListHelpers<T>.ResizeAndCopy(list, targetItemIndex, checked((int)BitOperations.RoundUpToPowerOf2((uint)(targetItemIndex + growByCount))));
|
||||||
memorySpan = new((T[])list._memoryBlock);
|
memorySpan = new(list._memoryBlock);
|
||||||
available = capacity - targetItemIndex;
|
available = capacity - targetItemIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -48,7 +52,7 @@ namespace Recyclable.Collections
|
|||||||
{
|
{
|
||||||
list._capacity = RecyclableListHelpers<T>.ResizeAndCopy(list, currentItemsCount, checked((int)BitOperations.RoundUpToPowerOf2((uint)(currentItemsCount + requiredAdditionalCapacity))));
|
list._capacity = RecyclableListHelpers<T>.ResizeAndCopy(list, currentItemsCount, checked((int)BitOperations.RoundUpToPowerOf2((uint)(currentItemsCount + requiredAdditionalCapacity))));
|
||||||
|
|
||||||
Span<T> memorySpan = new((T[])list._memoryBlock);
|
Span<T> memorySpan = new(list._memoryBlock);
|
||||||
foreach (var item in items)
|
foreach (var item in items)
|
||||||
{
|
{
|
||||||
memorySpan[currentItemsCount++] = item;
|
memorySpan[currentItemsCount++] = item;
|
||||||
@@ -78,7 +82,7 @@ namespace Recyclable.Collections
|
|||||||
list._capacity = RecyclableListHelpers<T>.ResizeAndCopy(list, list._count, checked((int)BitOperations.RoundUpToPowerOf2((uint)(list._count + items.Length))));
|
list._capacity = RecyclableListHelpers<T>.ResizeAndCopy(list, list._count, checked((int)BitOperations.RoundUpToPowerOf2((uint)(list._count + items.Length))));
|
||||||
}
|
}
|
||||||
|
|
||||||
new Span<T>(items).CopyTo(new Span<T>((T[])list._memoryBlock, list._count, items.Length));
|
new Span<T>(items).CopyTo(new Span<T>(list._memoryBlock, list._count, items.Length));
|
||||||
list._count += items.Length;
|
list._count += items.Length;
|
||||||
list._version++;
|
list._version++;
|
||||||
}
|
}
|
||||||
@@ -91,7 +95,7 @@ namespace Recyclable.Collections
|
|||||||
list._capacity = RecyclableListHelpers<T>.ResizeAndCopy(list, list._count, checked((int)BitOperations.RoundUpToPowerOf2((uint)(list._count + items.Length))));
|
list._capacity = RecyclableListHelpers<T>.ResizeAndCopy(list, list._count, checked((int)BitOperations.RoundUpToPowerOf2((uint)(list._count + items.Length))));
|
||||||
}
|
}
|
||||||
|
|
||||||
items.CopyTo(new Span<T>((T[])list._memoryBlock, list._count, items.Length));
|
items.CopyTo(new Span<T>(list._memoryBlock, list._count, items.Length));
|
||||||
list._count += items.Length;
|
list._count += items.Length;
|
||||||
list._version++;
|
list._version++;
|
||||||
}
|
}
|
||||||
@@ -104,7 +108,7 @@ namespace Recyclable.Collections
|
|||||||
list._capacity = RecyclableListHelpers<T>.ResizeAndCopy(list, list._count, checked((int)BitOperations.RoundUpToPowerOf2((uint)(list._count + items.Length))));
|
list._capacity = RecyclableListHelpers<T>.ResizeAndCopy(list, list._count, checked((int)BitOperations.RoundUpToPowerOf2((uint)(list._count + items.Length))));
|
||||||
}
|
}
|
||||||
|
|
||||||
items.CopyTo(new Span<T>((T[])list._memoryBlock, list._count, items.Length));
|
items.CopyTo(new Span<T>(list._memoryBlock, list._count, items.Length));
|
||||||
list._count += items.Length;
|
list._count += items.Length;
|
||||||
list._version++;
|
list._version++;
|
||||||
}
|
}
|
||||||
@@ -117,7 +121,7 @@ namespace Recyclable.Collections
|
|||||||
list._capacity = RecyclableListHelpers<T>.ResizeAndCopy(list, list._count, checked((int)BitOperations.RoundUpToPowerOf2((uint)(list._count + items.Count))));
|
list._capacity = RecyclableListHelpers<T>.ResizeAndCopy(list, list._count, checked((int)BitOperations.RoundUpToPowerOf2((uint)(list._count + items.Count))));
|
||||||
}
|
}
|
||||||
|
|
||||||
items.CopyTo((T[])list._memoryBlock, list._count);
|
items.CopyTo(list._memoryBlock, list._count);
|
||||||
list._count += items.Count;
|
list._count += items.Count;
|
||||||
list._version++;
|
list._version++;
|
||||||
}
|
}
|
||||||
@@ -143,7 +147,7 @@ namespace Recyclable.Collections
|
|||||||
list._capacity = RecyclableListHelpers<T>.ResizeAndCopy(list, list._count, checked((int)BitOperations.RoundUpToPowerOf2((uint)(list._count + items.Count))));
|
list._capacity = RecyclableListHelpers<T>.ResizeAndCopy(list, list._count, checked((int)BitOperations.RoundUpToPowerOf2((uint)(list._count + items.Count))));
|
||||||
}
|
}
|
||||||
|
|
||||||
items.CopyTo((T[])list._memoryBlock, list._count);
|
items.CopyTo(list._memoryBlock, list._count);
|
||||||
list._count += items.Count;
|
list._count += items.Count;
|
||||||
list._version++;
|
list._version++;
|
||||||
}
|
}
|
||||||
@@ -156,7 +160,7 @@ namespace Recyclable.Collections
|
|||||||
list._capacity = RecyclableListHelpers<T>.ResizeAndCopy(list, list._count, checked((int)BitOperations.RoundUpToPowerOf2((uint)(list._count + items._count))));
|
list._capacity = RecyclableListHelpers<T>.ResizeAndCopy(list, list._count, checked((int)BitOperations.RoundUpToPowerOf2((uint)(list._count + items._count))));
|
||||||
}
|
}
|
||||||
|
|
||||||
new Span<T>((T[])items._memoryBlock, 0, items._count).CopyTo(new Span<T>((T[])list._memoryBlock, list._count, items._count));
|
new Span<T>(items._memoryBlock, 0, items._count).CopyTo(new Span<T>(list._memoryBlock, list._count, items._count));
|
||||||
list._count += items._count;
|
list._count += items._count;
|
||||||
list._version++;
|
list._version++;
|
||||||
}
|
}
|
||||||
@@ -183,7 +187,7 @@ namespace Recyclable.Collections
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Avoid unnecessary range operator - pass as arguments instead.
|
// TODO: Avoid unnecessary range operator - pass as arguments instead.
|
||||||
Span<T> targetSpan = new Span<T>((T[])list._memoryBlock)[oldCount..],
|
Span<T> targetSpan = new Span<T>(list._memoryBlock)[oldCount..],
|
||||||
itemsSpan;
|
itemsSpan;
|
||||||
|
|
||||||
int blockIndex,
|
int blockIndex,
|
||||||
@@ -221,7 +225,7 @@ namespace Recyclable.Collections
|
|||||||
var enumerator = source.GetEnumerator();
|
var enumerator = source.GetEnumerator();
|
||||||
|
|
||||||
int capacity = list._capacity;
|
int capacity = list._capacity;
|
||||||
memorySpan = new((T[])list._memoryBlock);
|
memorySpan = new(list._memoryBlock);
|
||||||
if (enumerator.MoveNext())
|
if (enumerator.MoveNext())
|
||||||
{
|
{
|
||||||
int available = capacity - targetItemIndex;
|
int available = capacity - targetItemIndex;
|
||||||
@@ -230,7 +234,7 @@ namespace Recyclable.Collections
|
|||||||
if (targetItemIndex + growByCount > capacity)
|
if (targetItemIndex + growByCount > capacity)
|
||||||
{
|
{
|
||||||
capacity = RecyclableListHelpers<T>.ResizeAndCopy(list, targetItemIndex, checked((int)BitOperations.RoundUpToPowerOf2((uint)(targetItemIndex + growByCount))));
|
capacity = RecyclableListHelpers<T>.ResizeAndCopy(list, targetItemIndex, checked((int)BitOperations.RoundUpToPowerOf2((uint)(targetItemIndex + growByCount))));
|
||||||
memorySpan = new((T[])list._memoryBlock);
|
memorySpan = new(list._memoryBlock);
|
||||||
available = capacity - targetItemIndex;
|
available = capacity - targetItemIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -259,7 +263,7 @@ namespace Recyclable.Collections
|
|||||||
list._capacity = RecyclableListHelpers<T>.ResizeAndCopy(list, list._count, checked((int)BitOperations.RoundUpToPowerOf2((uint)(list._count + sourceItemsCount))));
|
list._capacity = RecyclableListHelpers<T>.ResizeAndCopy(list, list._count, checked((int)BitOperations.RoundUpToPowerOf2((uint)(list._count + sourceItemsCount))));
|
||||||
}
|
}
|
||||||
|
|
||||||
Span<T> memorySpan = new((T[])list._memoryBlock, list._count, sourceItemsCount);
|
Span<T> memorySpan = new(list._memoryBlock, list._count, sourceItemsCount);
|
||||||
for (var sourceItemIndex = 0; sourceItemIndex < sourceItemsCount; sourceItemIndex++)
|
for (var sourceItemIndex = 0; sourceItemIndex < sourceItemsCount; sourceItemIndex++)
|
||||||
{
|
{
|
||||||
memorySpan[sourceItemIndex] = items[sourceItemIndex];
|
memorySpan[sourceItemIndex] = items[sourceItemIndex];
|
||||||
|
|||||||
@@ -16,9 +16,9 @@ namespace Recyclable.Collections
|
|||||||
|
|
||||||
#nullable disable
|
#nullable disable
|
||||||
[Pure]
|
[Pure]
|
||||||
public readonly T Current => (T)_list._memoryBlock.GetValue(_currentItemIndex - 1);
|
public readonly T Current => _list._memoryBlock[_currentItemIndex - 1];
|
||||||
[Pure]
|
[Pure]
|
||||||
readonly object IEnumerator.Current => (T)_list._memoryBlock.GetValue(_currentItemIndex - 1);
|
readonly object IEnumerator.Current => _list._memoryBlock[_currentItemIndex - 1];
|
||||||
#nullable restore
|
#nullable restore
|
||||||
|
|
||||||
public bool MoveNext()
|
public bool MoveNext()
|
||||||
|
|||||||
@@ -108,23 +108,13 @@ namespace Recyclable.Collections
|
|||||||
{
|
{
|
||||||
// TODO: Measure performance
|
// TODO: Measure performance
|
||||||
// T[] newMemoryBlock = RecyclableListHelpers<T>._arrayPool.Rent(_capacity <<= 1);
|
// T[] newMemoryBlock = RecyclableListHelpers<T>._arrayPool.Rent(_capacity <<= 1);
|
||||||
Array oldMemoryBlock = list._memoryBlock;
|
T[] oldMemoryBlock = list._memoryBlock;
|
||||||
if (oldMemoryBlock.GetLowerBound(0) == 0)
|
|
||||||
{
|
|
||||||
list._memoryBlock = (list._capacity <<= 1) < RecyclableDefaults.MinPooledArrayLength
|
list._memoryBlock = (list._capacity <<= 1) < RecyclableDefaults.MinPooledArrayLength
|
||||||
? Array.CreateInstance(typeof(T), list._capacity)
|
? new T[list._capacity]
|
||||||
: RecyclableArrayPool<T>.RentShared(list._capacity);
|
: RecyclableArrayPool<T>.RentShared(list._capacity);
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
list._memoryBlock = (list._capacity <<= 1) < RecyclableDefaults.MinPooledArrayLength
|
|
||||||
? Array.CreateInstance(typeof(T), new[] { list._capacity }, new[] { oldMemoryBlock.GetLowerBound(0) })
|
|
||||||
: RecyclableArrayPool<T>.RentShared(list._capacity, oldMemoryBlock.GetLowerBound(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
// & WAS SLOWER WITHOUT
|
// & WAS SLOWER WITHOUT
|
||||||
Array.Copy(oldMemoryBlock, list._memoryBlock, list._count);
|
new Span<T>(oldMemoryBlock, 0, list._count).CopyTo(list._memoryBlock);
|
||||||
// new Span<T>((T[])oldMemoryBlock, 0, list._count).CopyTo((T[])list._memoryBlock);
|
|
||||||
|
|
||||||
if (oldMemoryBlock.Length >= RecyclableDefaults.MinPooledArrayLength)
|
if (oldMemoryBlock.Length >= RecyclableDefaults.MinPooledArrayLength)
|
||||||
{
|
{
|
||||||
@@ -141,7 +131,7 @@ namespace Recyclable.Collections
|
|||||||
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
|
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
|
||||||
public static int ResizeAndCopy(RecyclableList<T> sourceList, int oldSize, int newSize)
|
public static int ResizeAndCopy(RecyclableList<T> sourceList, int oldSize, int newSize)
|
||||||
{
|
{
|
||||||
T[] oldMemoryBlock = (T[])sourceList._memoryBlock;
|
T[] oldMemoryBlock = sourceList._memoryBlock;
|
||||||
sourceList._memoryBlock = newSize >= RecyclableDefaults.MinPooledArrayLength
|
sourceList._memoryBlock = newSize >= RecyclableDefaults.MinPooledArrayLength
|
||||||
? RecyclableArrayPool<T>.RentShared(newSize)
|
? RecyclableArrayPool<T>.RentShared(newSize)
|
||||||
: new T[newSize];
|
: new T[newSize];
|
||||||
@@ -149,7 +139,7 @@ namespace Recyclable.Collections
|
|||||||
// & WAS SLOWER WITHOUT
|
// & WAS SLOWER WITHOUT
|
||||||
|
|
||||||
// & WAS SLOWER AS ARRAY
|
// & WAS SLOWER AS ARRAY
|
||||||
new Span<T>(oldMemoryBlock, 0, oldSize).CopyTo((T[])sourceList._memoryBlock);
|
new Span<T>(oldMemoryBlock, 0, oldSize).CopyTo(sourceList._memoryBlock);
|
||||||
|
|
||||||
if (oldMemoryBlock.Length >= RecyclableDefaults.MinPooledArrayLength)
|
if (oldMemoryBlock.Length >= RecyclableDefaults.MinPooledArrayLength)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -27,18 +27,18 @@ namespace Recyclable.Collections
|
|||||||
|
|
||||||
object? IList.this[int index]
|
object? IList.this[int index]
|
||||||
{
|
{
|
||||||
get => _memoryBlock.GetValue(index);
|
get => _memoryBlock[index];
|
||||||
|
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
if (value is T typedValue)
|
if (value is T typedValue)
|
||||||
{
|
{
|
||||||
_memoryBlock.SetValue(typedValue, index);
|
new Span<T>(_memoryBlock)[index] = typedValue;
|
||||||
}
|
}
|
||||||
else if (value == null && _defaultIsNull)
|
else if (value == null && _defaultIsNull)
|
||||||
{
|
{
|
||||||
#nullable disable
|
#nullable disable
|
||||||
_memoryBlock.SetValue(default, index);
|
new Span<T>(_memoryBlock)[index] = default;
|
||||||
#nullable restore
|
#nullable restore
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -17,10 +17,10 @@ namespace Recyclable.Collections
|
|||||||
|
|
||||||
#nullable disable
|
#nullable disable
|
||||||
[Pure]
|
[Pure]
|
||||||
public readonly T Current => _enumeratorVersion == _list._version ? (T)_list._memoryBlock.GetValue(_currentItemIndex - 1) : throw new InvalidOperationException();
|
public readonly T Current => _enumeratorVersion == _list._version ? _list._memoryBlock[_currentItemIndex - 1] : throw new InvalidOperationException();
|
||||||
|
|
||||||
[Pure]
|
[Pure]
|
||||||
readonly object IEnumerator.Current => _enumeratorVersion == _list._version ? _list._memoryBlock.GetValue(_currentItemIndex - 1) : throw new InvalidOperationException();
|
readonly object IEnumerator.Current => _enumeratorVersion == _list._version ? _list._memoryBlock[_currentItemIndex - 1] : throw new InvalidOperationException();
|
||||||
#nullable restore
|
#nullable restore
|
||||||
|
|
||||||
public bool MoveNext()
|
public bool MoveNext()
|
||||||
|
|||||||
@@ -10,10 +10,10 @@ namespace Recyclable.Collections
|
|||||||
{
|
{
|
||||||
private static readonly bool _needsClearing = !typeof(T).IsValueType;
|
private static readonly bool _needsClearing = !typeof(T).IsValueType;
|
||||||
|
|
||||||
public static explicit operator ReadOnlySpan<T>(RecyclableList<T> source) => new((T[])source._memoryBlock, 0, source._count);
|
public static explicit operator ReadOnlySpan<T>(RecyclableList<T> source) => new(source._memoryBlock, 0, source._count);
|
||||||
|
|
||||||
#nullable disable
|
#nullable disable
|
||||||
internal Array _memoryBlock;
|
internal T[] _memoryBlock;
|
||||||
#nullable restore
|
#nullable restore
|
||||||
|
|
||||||
internal ulong _version;
|
internal ulong _version;
|
||||||
@@ -22,103 +22,85 @@ namespace Recyclable.Collections
|
|||||||
public RecyclableList()
|
public RecyclableList()
|
||||||
{
|
{
|
||||||
_capacity = RecyclableDefaults.InitialCapacity;
|
_capacity = RecyclableDefaults.InitialCapacity;
|
||||||
_memoryBlock = Array.CreateInstance(typeof(T), RecyclableDefaults.InitialCapacity);
|
_memoryBlock = new T[RecyclableDefaults.InitialCapacity];
|
||||||
}
|
}
|
||||||
|
|
||||||
public RecyclableList(int initialCapacity = RecyclableDefaults.InitialCapacity, int lowerBound = 0)
|
public RecyclableList(int initialCapacity)
|
||||||
{
|
|
||||||
if (lowerBound == 0)
|
|
||||||
{
|
{
|
||||||
if (initialCapacity >= RecyclableDefaults.InitialCapacity)
|
if (initialCapacity >= RecyclableDefaults.InitialCapacity)
|
||||||
{
|
{
|
||||||
_memoryBlock = initialCapacity >= RecyclableDefaults.MinPooledArrayLength
|
_memoryBlock = initialCapacity >= RecyclableDefaults.MinPooledArrayLength
|
||||||
? RecyclableArrayPool<T>.RentShared(checked((int)BitOperations.RoundUpToPowerOf2((uint)initialCapacity)))
|
? RecyclableArrayPool<T>.RentShared(checked((int)BitOperations.RoundUpToPowerOf2((uint)initialCapacity)))
|
||||||
: Array.CreateInstance(typeof(T), initialCapacity);
|
: new T[initialCapacity];
|
||||||
_capacity = _memoryBlock.Length;
|
_capacity = _memoryBlock.Length;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_memoryBlock = Array.CreateInstance(typeof(T), RecyclableDefaults.InitialCapacity);
|
_memoryBlock = new T[RecyclableDefaults.InitialCapacity];
|
||||||
_capacity = RecyclableDefaults.InitialCapacity;
|
_capacity = RecyclableDefaults.InitialCapacity;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
if (initialCapacity >= RecyclableDefaults.InitialCapacity)
|
|
||||||
{
|
|
||||||
_memoryBlock = initialCapacity >= RecyclableDefaults.MinPooledArrayLength
|
|
||||||
? RecyclableArrayPool<T>.RentShared(checked((int)BitOperations.RoundUpToPowerOf2((uint)initialCapacity)), lowerBound)
|
|
||||||
: Array.CreateInstance(typeof(T), new[] { initialCapacity }, new[] { lowerBound });
|
|
||||||
_capacity = _memoryBlock.Length;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_memoryBlock = Array.CreateInstance(typeof(T), new[] { RecyclableDefaults.InitialCapacity }, new[] { lowerBound });
|
|
||||||
_capacity = RecyclableDefaults.InitialCapacity;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public RecyclableList(in Array source)
|
public RecyclableList(in Array source)
|
||||||
{
|
{
|
||||||
_capacity = RecyclableDefaults.InitialCapacity;
|
_capacity = RecyclableDefaults.InitialCapacity;
|
||||||
_memoryBlock = Array.CreateInstance(typeof(T), RecyclableDefaults.InitialCapacity);
|
_memoryBlock = new T[RecyclableDefaults.InitialCapacity];
|
||||||
zRecyclableListAddRange.AddRange(this, source);
|
zRecyclableListAddRange.AddRange(this, source);
|
||||||
}
|
}
|
||||||
|
|
||||||
public RecyclableList(RecyclableList<T> source)
|
public RecyclableList(RecyclableList<T> source)
|
||||||
{
|
{
|
||||||
_capacity = RecyclableDefaults.InitialCapacity;
|
_capacity = RecyclableDefaults.InitialCapacity;
|
||||||
_memoryBlock = Array.CreateInstance(typeof(T), RecyclableDefaults.InitialCapacity);
|
_memoryBlock = new T[RecyclableDefaults.InitialCapacity];
|
||||||
zRecyclableListAddRange.AddRange(this, source);
|
zRecyclableListAddRange.AddRange(this, source);
|
||||||
}
|
}
|
||||||
|
|
||||||
public RecyclableList(RecyclableLongList<T> source)
|
public RecyclableList(RecyclableLongList<T> source)
|
||||||
{
|
{
|
||||||
_capacity = RecyclableDefaults.InitialCapacity;
|
_capacity = RecyclableDefaults.InitialCapacity;
|
||||||
_memoryBlock = Array.CreateInstance(typeof(T), RecyclableDefaults.InitialCapacity);
|
_memoryBlock = new T[RecyclableDefaults.InitialCapacity];
|
||||||
zRecyclableListAddRange.AddRange(this, source);
|
zRecyclableListAddRange.AddRange(this, source);
|
||||||
}
|
}
|
||||||
|
|
||||||
public RecyclableList(ReadOnlySpan<T> source)
|
public RecyclableList(ReadOnlySpan<T> source)
|
||||||
{
|
{
|
||||||
_capacity = RecyclableDefaults.InitialCapacity;
|
_capacity = RecyclableDefaults.InitialCapacity;
|
||||||
_memoryBlock = Array.CreateInstance(typeof(T), RecyclableDefaults.InitialCapacity);
|
_memoryBlock = new T[RecyclableDefaults.InitialCapacity];
|
||||||
zRecyclableListAddRange.AddRange(this, source);
|
zRecyclableListAddRange.AddRange(this, source);
|
||||||
}
|
}
|
||||||
|
|
||||||
public RecyclableList(in T[] source)
|
public RecyclableList(in T[] source)
|
||||||
{
|
{
|
||||||
_capacity = RecyclableDefaults.InitialCapacity;
|
_capacity = RecyclableDefaults.InitialCapacity;
|
||||||
_memoryBlock = Array.CreateInstance(typeof(T), RecyclableDefaults.InitialCapacity);
|
_memoryBlock = new T[RecyclableDefaults.InitialCapacity];
|
||||||
zRecyclableListAddRange.AddRange(this, source);
|
zRecyclableListAddRange.AddRange(this, source);
|
||||||
}
|
}
|
||||||
|
|
||||||
public RecyclableList(IReadOnlyList<T> source)
|
public RecyclableList(IReadOnlyList<T> source)
|
||||||
{
|
{
|
||||||
_capacity = RecyclableDefaults.InitialCapacity;
|
_capacity = RecyclableDefaults.InitialCapacity;
|
||||||
_memoryBlock = Array.CreateInstance(typeof(T), RecyclableDefaults.InitialCapacity);
|
_memoryBlock = new T[RecyclableDefaults.InitialCapacity];
|
||||||
zRecyclableListAddRange.AddRange(this, source);
|
zRecyclableListAddRange.AddRange(this, source);
|
||||||
}
|
}
|
||||||
|
|
||||||
public RecyclableList(List<T> source)
|
public RecyclableList(List<T> source)
|
||||||
{
|
{
|
||||||
_capacity = RecyclableDefaults.InitialCapacity;
|
_capacity = RecyclableDefaults.InitialCapacity;
|
||||||
_memoryBlock = Array.CreateInstance(typeof(T), RecyclableDefaults.InitialCapacity);
|
_memoryBlock = new T[RecyclableDefaults.InitialCapacity];
|
||||||
zRecyclableListAddRange.AddRange(this, source);
|
zRecyclableListAddRange.AddRange(this, source);
|
||||||
}
|
}
|
||||||
|
|
||||||
public RecyclableList(ICollection source)
|
public RecyclableList(ICollection source)
|
||||||
{
|
{
|
||||||
_capacity = RecyclableDefaults.InitialCapacity;
|
_capacity = RecyclableDefaults.InitialCapacity;
|
||||||
_memoryBlock = Array.CreateInstance(typeof(T), RecyclableDefaults.InitialCapacity);
|
_memoryBlock = new T[RecyclableDefaults.InitialCapacity];
|
||||||
zRecyclableListAddRange.AddRange(this, source);
|
zRecyclableListAddRange.AddRange(this, source);
|
||||||
}
|
}
|
||||||
|
|
||||||
public RecyclableList(ICollection<T> source)
|
public RecyclableList(ICollection<T> source)
|
||||||
{
|
{
|
||||||
_capacity = RecyclableDefaults.InitialCapacity;
|
_capacity = RecyclableDefaults.InitialCapacity;
|
||||||
_memoryBlock = Array.CreateInstance(typeof(T), RecyclableDefaults.InitialCapacity);
|
_memoryBlock = new T[RecyclableDefaults.InitialCapacity];
|
||||||
zRecyclableListAddRange.AddRange(this, source);
|
zRecyclableListAddRange.AddRange(this, source);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -128,13 +110,13 @@ namespace Recyclable.Collections
|
|||||||
{
|
{
|
||||||
_memoryBlock = initialCapacity >= RecyclableDefaults.MinPooledArrayLength
|
_memoryBlock = initialCapacity >= RecyclableDefaults.MinPooledArrayLength
|
||||||
? RecyclableArrayPool<T>.RentShared(checked((int)BitOperations.RoundUpToPowerOf2((uint)initialCapacity)))
|
? RecyclableArrayPool<T>.RentShared(checked((int)BitOperations.RoundUpToPowerOf2((uint)initialCapacity)))
|
||||||
: Array.CreateInstance(typeof(T), initialCapacity);
|
: new T[initialCapacity];
|
||||||
_capacity = _memoryBlock.Length;
|
_capacity = _memoryBlock.Length;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_capacity = RecyclableDefaults.InitialCapacity;
|
_capacity = RecyclableDefaults.InitialCapacity;
|
||||||
_memoryBlock = Array.CreateInstance(typeof(T), RecyclableDefaults.InitialCapacity);
|
_memoryBlock = new T[RecyclableDefaults.InitialCapacity];
|
||||||
}
|
}
|
||||||
|
|
||||||
zRecyclableListAddRange.AddRange(this, source, RecyclableDefaults.MinPooledArrayLength);
|
zRecyclableListAddRange.AddRange(this, source, RecyclableDefaults.MinPooledArrayLength);
|
||||||
@@ -146,13 +128,13 @@ namespace Recyclable.Collections
|
|||||||
{
|
{
|
||||||
_memoryBlock = initialCapacity >= RecyclableDefaults.MinPooledArrayLength
|
_memoryBlock = initialCapacity >= RecyclableDefaults.MinPooledArrayLength
|
||||||
? RecyclableArrayPool<T>.RentShared(checked((int)BitOperations.RoundUpToPowerOf2((uint)initialCapacity)))
|
? RecyclableArrayPool<T>.RentShared(checked((int)BitOperations.RoundUpToPowerOf2((uint)initialCapacity)))
|
||||||
: Array.CreateInstance(typeof(T), initialCapacity);
|
: new T[initialCapacity];
|
||||||
_capacity = _memoryBlock.Length;
|
_capacity = _memoryBlock.Length;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_capacity = RecyclableDefaults.InitialCapacity;
|
_capacity = RecyclableDefaults.InitialCapacity;
|
||||||
_memoryBlock = Array.CreateInstance(typeof(T), RecyclableDefaults.InitialCapacity);
|
_memoryBlock = new T[RecyclableDefaults.InitialCapacity];
|
||||||
}
|
}
|
||||||
|
|
||||||
zRecyclableListAddRange.AddRange(this, source);
|
zRecyclableListAddRange.AddRange(this, source);
|
||||||
@@ -161,23 +143,21 @@ namespace Recyclable.Collections
|
|||||||
public RecyclableList(Span<T> source)
|
public RecyclableList(Span<T> source)
|
||||||
{
|
{
|
||||||
_capacity = RecyclableDefaults.InitialCapacity;
|
_capacity = RecyclableDefaults.InitialCapacity;
|
||||||
_memoryBlock = Array.CreateInstance(typeof(T), RecyclableDefaults.InitialCapacity);
|
_memoryBlock = new T[RecyclableDefaults.InitialCapacity];
|
||||||
zRecyclableListAddRange.AddRange(this, source);
|
zRecyclableListAddRange.AddRange(this, source);
|
||||||
}
|
}
|
||||||
|
|
||||||
public T this[int index]
|
public T this[int index]
|
||||||
{
|
{
|
||||||
#nullable disable
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
get => (T)_memoryBlock.GetValue(index);
|
get => _memoryBlock[index];
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
_memoryBlock.SetValue(value, index);
|
_memoryBlock[index] = value;
|
||||||
_version++;
|
_version++;
|
||||||
}
|
}
|
||||||
#nullable restore
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal int _capacity;
|
internal int _capacity;
|
||||||
@@ -207,11 +187,11 @@ namespace Recyclable.Collections
|
|||||||
RecyclableListHelpers<T>.ResizeAndCopy(this);
|
RecyclableListHelpers<T>.ResizeAndCopy(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
_memoryBlock.SetValue(item, _count++);
|
_memoryBlock[_count++] = item;
|
||||||
_version++;
|
_version++;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Array AsArray => _memoryBlock;
|
public T[] AsArray => _memoryBlock;
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||||
public void Clear()
|
public void Clear()
|
||||||
@@ -250,10 +230,11 @@ namespace Recyclable.Collections
|
|||||||
|
|
||||||
if (index < oldCount)
|
if (index < oldCount)
|
||||||
{
|
{
|
||||||
Array.Copy(_memoryBlock, index, _memoryBlock, index + 1, oldCount -= index);
|
new Span<T>(_memoryBlock, index, oldCount -= index)
|
||||||
|
.CopyTo(new Span<T>(_memoryBlock, index + 1, oldCount));
|
||||||
}
|
}
|
||||||
|
|
||||||
_memoryBlock.SetValue(item, index);
|
_memoryBlock[index] = item;
|
||||||
_count++;
|
_count++;
|
||||||
_version++;
|
_version++;
|
||||||
}
|
}
|
||||||
@@ -272,7 +253,7 @@ namespace Recyclable.Collections
|
|||||||
|
|
||||||
if (_needsClearing)
|
if (_needsClearing)
|
||||||
{
|
{
|
||||||
_memoryBlock.SetValue(default, _count);
|
_memoryBlock[_count] = default;
|
||||||
}
|
}
|
||||||
|
|
||||||
_version++;
|
_version++;
|
||||||
@@ -299,7 +280,7 @@ namespace Recyclable.Collections
|
|||||||
|
|
||||||
if (_needsClearing)
|
if (_needsClearing)
|
||||||
{
|
{
|
||||||
_memoryBlock.SetValue(default, _count);
|
_memoryBlock[_count] = default;
|
||||||
}
|
}
|
||||||
|
|
||||||
_version++;
|
_version++;
|
||||||
|
|||||||
@@ -189,7 +189,7 @@ namespace Recyclable.Collections
|
|||||||
|
|
||||||
// We're better off to temporarily copy it to a fixed array,
|
// We're better off to temporarily copy it to a fixed array,
|
||||||
// than copying them item by item. We may run into OOMs, though.
|
// than copying them item by item. We may run into OOMs, though.
|
||||||
T[] itemsBuffer = items.Count >= RecyclableDefaults.MinPooledArrayLength ? (T[])RecyclableArrayPool<T>.RentShared((int)BitOperations.RoundUpToPowerOf2((uint)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];
|
||||||
items.CopyTo(itemsBuffer, 0);
|
items.CopyTo(itemsBuffer, 0);
|
||||||
|
|
||||||
Span<T> itemsSpan = new(itemsBuffer, 0, items.Count);
|
Span<T> itemsSpan = new(itemsBuffer, 0, items.Count);
|
||||||
@@ -255,7 +255,7 @@ namespace Recyclable.Collections
|
|||||||
|
|
||||||
// We're better off to temporarily copy it to a fixed array,
|
// We're better off to temporarily copy it to a fixed array,
|
||||||
// than copying them item by item. We may run into OOMs, though.
|
// than copying them item by item. We may run into OOMs, though.
|
||||||
T[] itemsBuffer = items.Count >= RecyclableDefaults.MinPooledArrayLength ? (T[])RecyclableArrayPool<T>.RentShared((int)BitOperations.RoundUpToPowerOf2((uint)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];
|
||||||
|
|
||||||
items.CopyTo(itemsBuffer, 0);
|
items.CopyTo(itemsBuffer, 0);
|
||||||
|
|
||||||
@@ -590,7 +590,7 @@ namespace Recyclable.Collections
|
|||||||
targetList._capacity = RecyclableLongList<T>.Helpers.Resize(targetList, targetList._blockSize, targetList._blockSizePow2BitShift, checked((long)BitOperations.RoundUpToPowerOf2((ulong)targetCapacity)));
|
targetList._capacity = RecyclableLongList<T>.Helpers.Resize(targetList, targetList._blockSize, targetList._blockSizePow2BitShift, checked((long)BitOperations.RoundUpToPowerOf2((ulong)targetCapacity)));
|
||||||
}
|
}
|
||||||
|
|
||||||
Span<T> itemsSpan = new((T[])items._memoryBlock, 0, items._count);
|
Span<T> itemsSpan = new(items._memoryBlock, 0, items._count);
|
||||||
Span<T[]> targetMemoryBlocksSpan = new(targetList._memoryBlocks);
|
Span<T[]> targetMemoryBlocksSpan = new(targetList._memoryBlocks);
|
||||||
Span<T> targetBlockArraySpan = new(targetMemoryBlocksSpan[targetBlockIndex], targetList._nextItemIndex, targetList._blockSize - targetList._nextItemIndex);
|
Span<T> targetBlockArraySpan = new(targetMemoryBlocksSpan[targetBlockIndex], targetList._nextItemIndex, targetList._blockSize - targetList._nextItemIndex);
|
||||||
|
|
||||||
|
|||||||
@@ -150,7 +150,7 @@ namespace Recyclable.Collections
|
|||||||
if (requiredBlockCount > sourceBlockCount)
|
if (requiredBlockCount > sourceBlockCount)
|
||||||
{
|
{
|
||||||
// Allocate new memory block for all arrays
|
// Allocate new memory block for all arrays
|
||||||
newMemoryBlocks = requiredBlockCount >= RecyclableDefaults.MinPooledArrayLength ? (T[][])RecyclableArrayPool<T[]>.RentShared(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
|
// Copy arrays from the old memory block for all arrays
|
||||||
if (sourceBlockCount > 0)
|
if (sourceBlockCount > 0)
|
||||||
@@ -179,7 +179,7 @@ namespace Recyclable.Collections
|
|||||||
ref OneSizeArrayPool<T> blockArrayPool = ref RecyclableArrayPool<T>.Shared(minBlockSize);
|
ref OneSizeArrayPool<T> blockArrayPool = ref RecyclableArrayPool<T>.Shared(minBlockSize);
|
||||||
while (blockIndex >= 0 && newMemoryBlocks[blockIndex] == null)
|
while (blockIndex >= 0 && newMemoryBlocks[blockIndex] == null)
|
||||||
{
|
{
|
||||||
newMemoryBlocks[blockIndex--] = (T[])blockArrayPool.Rent();
|
newMemoryBlocks[blockIndex--] = blockArrayPool.Rent();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -338,13 +338,13 @@ namespace Recyclable.CollectionsTests
|
|||||||
|
|
||||||
// Arrange
|
// Arrange
|
||||||
using var list = new RecyclableList<object>(testData, itemsCount);
|
using var list = new RecyclableList<object>(testData, itemsCount);
|
||||||
_ = ((object[])list.AsArray)[..itemsCount].Should().AllSatisfy(x => x.Should().NotBeNull());
|
_ = list.AsArray[..itemsCount].Should().AllSatisfy(x => x.Should().NotBeNull());
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
list.Clear();
|
list.Clear();
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
_ = ((object[])list.AsArray)[..itemsCount].Should().AllSatisfy(x => x.Should().BeNull());
|
_ = list.AsArray[..itemsCount].Should().AllSatisfy(x => x.Should().BeNull());
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
@@ -393,12 +393,6 @@ namespace Recyclable.CollectionsTests
|
|||||||
_ = list.Should().Equal(testData);
|
_ = list.Should().Equal(testData);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void ConstructorShouldCreateArrayWithCustomBoundaries()
|
|
||||||
{
|
|
||||||
using var list = new RecyclableList<long>(-10);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
[MemberData(nameof(RecyclableLongListTestData.SourceDataVariants), MemberType = typeof(RecyclableLongListTestData))]
|
[MemberData(nameof(RecyclableLongListTestData.SourceDataVariants), MemberType = typeof(RecyclableLongListTestData))]
|
||||||
public void ConstructorSourceShouldInitializeList(string testCase, IEnumerable<long> testData, int itemsCount)
|
public void ConstructorSourceShouldInitializeList(string testCase, IEnumerable<long> testData, int itemsCount)
|
||||||
@@ -481,14 +475,14 @@ namespace Recyclable.CollectionsTests
|
|||||||
// Arrange
|
// Arrange
|
||||||
using var list = new RecyclableList<object>(testData, itemsCount);
|
using var list = new RecyclableList<object>(testData, itemsCount);
|
||||||
var listArray = list.AsArray;
|
var listArray = list.AsArray;
|
||||||
_ = ((object[])list.AsArray)[..itemsCount].Should().NotBeNull();
|
_ = list.AsArray[..itemsCount].Should().NotBeNull();
|
||||||
_ = ((object[])listArray)[..itemsCount].Should().AllSatisfy(x => x.Should().NotBeNull());
|
_ = listArray[..itemsCount].Should().AllSatisfy(x => x.Should().NotBeNull());
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
list.Dispose();
|
list.Dispose();
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
_ = ((object[])listArray)[..itemsCount].Should().AllSatisfy(x => x.Should().BeNull());
|
_ = listArray[..itemsCount].Should().AllSatisfy(x => x.Should().BeNull());
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|||||||
Reference in new issue
Block a user