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
+92
-192
No files matched your search
@@ -2,21 +2,23 @@ namespace Recyclable.Collections
|
||||
{
|
||||
internal sealed class MemoryBucket<T>
|
||||
{
|
||||
public MemoryBucket(Array memory, MemoryBucket<T> nextBucket)
|
||||
public MemoryBucket(T[] memory, MemoryBucket<T> nextBucket)
|
||||
{
|
||||
_memory = memory;
|
||||
_nextBucket = nextBucket;
|
||||
}
|
||||
|
||||
public MemoryBucket(Array memory)
|
||||
public MemoryBucket(T[] memory)
|
||||
{
|
||||
_memory = memory;
|
||||
}
|
||||
|
||||
private Array _memory;
|
||||
public Array Memory { get => _memory; set => _memory = value; }
|
||||
#pragma warning disable RCS1085
|
||||
private T[] _memory;
|
||||
public T[] Memory { get => _memory; set => _memory = value; }
|
||||
|
||||
private MemoryBucket<T>? _nextBucket;
|
||||
public MemoryBucket<T>? NextBucket { get => _nextBucket; set => _nextBucket = value; }
|
||||
#pragma warning restore RCS1085
|
||||
}
|
||||
}
|
||||
@@ -39,7 +39,7 @@
|
||||
_ = Task.Run(ReleaseMemoryOnExcess);
|
||||
}
|
||||
|
||||
public Array Rent()
|
||||
public T[] Rent()
|
||||
{
|
||||
MemoryBucket<T>? bucket;
|
||||
Enter();
|
||||
@@ -55,10 +55,10 @@
|
||||
}
|
||||
|
||||
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);
|
||||
if (clearArray)
|
||||
|
||||
@@ -4,95 +4,24 @@ namespace Recyclable.Collections.Pools
|
||||
{
|
||||
public readonly struct RecyclableArrayPool<T>
|
||||
{
|
||||
private const int MaxArraySize = 32;
|
||||
internal static readonly OneSizeArrayPool<T>[] _pools = new OneSizeArrayPool<T>[MaxArraySize];
|
||||
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();
|
||||
|
||||
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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
=> _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)];
|
||||
|
||||
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()
|
||||
{
|
||||
InitializePools(_pools);
|
||||
_ = Task.Run(CheckAndReportMemoryPressure);
|
||||
}
|
||||
|
||||
private static void InitializePools(OneSizeArrayPool<T>[] pools)
|
||||
{
|
||||
for (var arraySize = 0; arraySize < MaxArraySize; arraySize++)
|
||||
var pools = _pools;
|
||||
for (var arraySize = 0; arraySize < 32; arraySize++)
|
||||
{
|
||||
int blockSize = 1 << arraySize;
|
||||
pools[arraySize] = new OneSizeArrayPool<T>(blockSize, 1000);
|
||||
}
|
||||
|
||||
_ = Task.Run(CheckAndReportMemoryPressure);
|
||||
}
|
||||
|
||||
public static readonly OneSizeArrayPool<T> Null = new(0, 0);
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Recyclable.Collections
|
||||
{
|
||||
public static class zRecyclableListAddRange
|
||||
public static class zRecyclableListAddRange
|
||||
{
|
||||
private static void AddRangeEnumerated<T>(this RecyclableList<T> list, IEnumerable<T> items, int growByCount)
|
||||
{
|
||||
@@ -15,7 +19,7 @@ namespace Recyclable.Collections
|
||||
var enumerator = items.GetEnumerator();
|
||||
|
||||
int capacity = list._capacity;
|
||||
memorySpan = new((T[])list._memoryBlock);
|
||||
memorySpan = new(list._memoryBlock);
|
||||
if (enumerator.MoveNext())
|
||||
{
|
||||
int available = capacity - targetItemIndex;
|
||||
@@ -24,7 +28,7 @@ namespace Recyclable.Collections
|
||||
if (targetItemIndex + growByCount > capacity)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -48,7 +52,7 @@ namespace Recyclable.Collections
|
||||
{
|
||||
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)
|
||||
{
|
||||
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))));
|
||||
}
|
||||
|
||||
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._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))));
|
||||
}
|
||||
|
||||
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._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))));
|
||||
}
|
||||
|
||||
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._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))));
|
||||
}
|
||||
|
||||
items.CopyTo((T[])list._memoryBlock, list._count);
|
||||
items.CopyTo(list._memoryBlock, list._count);
|
||||
list._count += items.Count;
|
||||
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))));
|
||||
}
|
||||
|
||||
items.CopyTo((T[])list._memoryBlock, list._count);
|
||||
items.CopyTo(list._memoryBlock, list._count);
|
||||
list._count += items.Count;
|
||||
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))));
|
||||
}
|
||||
|
||||
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._version++;
|
||||
}
|
||||
@@ -183,7 +187,7 @@ namespace Recyclable.Collections
|
||||
}
|
||||
|
||||
// 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;
|
||||
|
||||
int blockIndex,
|
||||
@@ -221,7 +225,7 @@ namespace Recyclable.Collections
|
||||
var enumerator = source.GetEnumerator();
|
||||
|
||||
int capacity = list._capacity;
|
||||
memorySpan = new((T[])list._memoryBlock);
|
||||
memorySpan = new(list._memoryBlock);
|
||||
if (enumerator.MoveNext())
|
||||
{
|
||||
int available = capacity - targetItemIndex;
|
||||
@@ -230,7 +234,7 @@ namespace Recyclable.Collections
|
||||
if (targetItemIndex + growByCount > capacity)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -259,7 +263,7 @@ namespace Recyclable.Collections
|
||||
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++)
|
||||
{
|
||||
memorySpan[sourceItemIndex] = items[sourceItemIndex];
|
||||
|
||||
@@ -16,9 +16,9 @@ namespace Recyclable.Collections
|
||||
|
||||
#nullable disable
|
||||
[Pure]
|
||||
public readonly T Current => (T)_list._memoryBlock.GetValue(_currentItemIndex - 1);
|
||||
public readonly T Current => _list._memoryBlock[_currentItemIndex - 1];
|
||||
[Pure]
|
||||
readonly object IEnumerator.Current => (T)_list._memoryBlock.GetValue(_currentItemIndex - 1);
|
||||
readonly object IEnumerator.Current => _list._memoryBlock[_currentItemIndex - 1];
|
||||
#nullable restore
|
||||
|
||||
public bool MoveNext()
|
||||
|
||||
@@ -108,23 +108,13 @@ namespace Recyclable.Collections
|
||||
{
|
||||
// TODO: Measure performance
|
||||
// T[] newMemoryBlock = RecyclableListHelpers<T>._arrayPool.Rent(_capacity <<= 1);
|
||||
Array oldMemoryBlock = list._memoryBlock;
|
||||
if (oldMemoryBlock.GetLowerBound(0) == 0)
|
||||
{
|
||||
list._memoryBlock = (list._capacity <<= 1) < RecyclableDefaults.MinPooledArrayLength
|
||||
? Array.CreateInstance(typeof(T), 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));
|
||||
}
|
||||
T[] oldMemoryBlock = list._memoryBlock;
|
||||
list._memoryBlock = (list._capacity <<= 1) < RecyclableDefaults.MinPooledArrayLength
|
||||
? new T[list._capacity]
|
||||
: RecyclableArrayPool<T>.RentShared(list._capacity);
|
||||
|
||||
// & WAS SLOWER WITHOUT
|
||||
Array.Copy(oldMemoryBlock, list._memoryBlock, list._count);
|
||||
// new Span<T>((T[])oldMemoryBlock, 0, list._count).CopyTo((T[])list._memoryBlock);
|
||||
new Span<T>(oldMemoryBlock, 0, list._count).CopyTo(list._memoryBlock);
|
||||
|
||||
if (oldMemoryBlock.Length >= RecyclableDefaults.MinPooledArrayLength)
|
||||
{
|
||||
@@ -141,7 +131,7 @@ namespace Recyclable.Collections
|
||||
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
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
|
||||
? RecyclableArrayPool<T>.RentShared(newSize)
|
||||
: new T[newSize];
|
||||
@@ -149,7 +139,7 @@ namespace Recyclable.Collections
|
||||
// & WAS SLOWER WITHOUT
|
||||
|
||||
// & 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)
|
||||
{
|
||||
|
||||
@@ -27,18 +27,18 @@ namespace Recyclable.Collections
|
||||
|
||||
object? IList.this[int index]
|
||||
{
|
||||
get => _memoryBlock.GetValue(index);
|
||||
get => _memoryBlock[index];
|
||||
|
||||
set
|
||||
{
|
||||
if (value is T typedValue)
|
||||
{
|
||||
_memoryBlock.SetValue(typedValue, index);
|
||||
new Span<T>(_memoryBlock)[index] = typedValue;
|
||||
}
|
||||
else if (value == null && _defaultIsNull)
|
||||
{
|
||||
#nullable disable
|
||||
_memoryBlock.SetValue(default, index);
|
||||
new Span<T>(_memoryBlock)[index] = default;
|
||||
#nullable restore
|
||||
}
|
||||
else
|
||||
|
||||
@@ -17,10 +17,10 @@ namespace Recyclable.Collections
|
||||
|
||||
#nullable disable
|
||||
[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]
|
||||
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
|
||||
|
||||
public bool MoveNext()
|
||||
|
||||
@@ -10,10 +10,10 @@ namespace Recyclable.Collections
|
||||
{
|
||||
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
|
||||
internal Array _memoryBlock;
|
||||
internal T[] _memoryBlock;
|
||||
#nullable restore
|
||||
|
||||
internal ulong _version;
|
||||
@@ -22,103 +22,85 @@ namespace Recyclable.Collections
|
||||
public RecyclableList()
|
||||
{
|
||||
_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
|
||||
? RecyclableArrayPool<T>.RentShared(checked((int)BitOperations.RoundUpToPowerOf2((uint)initialCapacity)))
|
||||
: Array.CreateInstance(typeof(T), initialCapacity);
|
||||
_capacity = _memoryBlock.Length;
|
||||
}
|
||||
else
|
||||
{
|
||||
_memoryBlock = Array.CreateInstance(typeof(T), RecyclableDefaults.InitialCapacity);
|
||||
_capacity = RecyclableDefaults.InitialCapacity;
|
||||
}
|
||||
_memoryBlock = initialCapacity >= RecyclableDefaults.MinPooledArrayLength
|
||||
? RecyclableArrayPool<T>.RentShared(checked((int)BitOperations.RoundUpToPowerOf2((uint)initialCapacity)))
|
||||
: new T[initialCapacity];
|
||||
_capacity = _memoryBlock.Length;
|
||||
}
|
||||
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;
|
||||
}
|
||||
_memoryBlock = new T[RecyclableDefaults.InitialCapacity];
|
||||
_capacity = RecyclableDefaults.InitialCapacity;
|
||||
}
|
||||
}
|
||||
|
||||
public RecyclableList(in Array source)
|
||||
{
|
||||
_capacity = RecyclableDefaults.InitialCapacity;
|
||||
_memoryBlock = Array.CreateInstance(typeof(T), RecyclableDefaults.InitialCapacity);
|
||||
_memoryBlock = new T[RecyclableDefaults.InitialCapacity];
|
||||
zRecyclableListAddRange.AddRange(this, source);
|
||||
}
|
||||
|
||||
public RecyclableList(RecyclableList<T> source)
|
||||
{
|
||||
_capacity = RecyclableDefaults.InitialCapacity;
|
||||
_memoryBlock = Array.CreateInstance(typeof(T), RecyclableDefaults.InitialCapacity);
|
||||
_memoryBlock = new T[RecyclableDefaults.InitialCapacity];
|
||||
zRecyclableListAddRange.AddRange(this, source);
|
||||
}
|
||||
|
||||
public RecyclableList(RecyclableLongList<T> source)
|
||||
{
|
||||
_capacity = RecyclableDefaults.InitialCapacity;
|
||||
_memoryBlock = Array.CreateInstance(typeof(T), RecyclableDefaults.InitialCapacity);
|
||||
_memoryBlock = new T[RecyclableDefaults.InitialCapacity];
|
||||
zRecyclableListAddRange.AddRange(this, source);
|
||||
}
|
||||
|
||||
public RecyclableList(ReadOnlySpan<T> source)
|
||||
{
|
||||
_capacity = RecyclableDefaults.InitialCapacity;
|
||||
_memoryBlock = Array.CreateInstance(typeof(T), RecyclableDefaults.InitialCapacity);
|
||||
_memoryBlock = new T[RecyclableDefaults.InitialCapacity];
|
||||
zRecyclableListAddRange.AddRange(this, source);
|
||||
}
|
||||
|
||||
public RecyclableList(in T[] source)
|
||||
{
|
||||
_capacity = RecyclableDefaults.InitialCapacity;
|
||||
_memoryBlock = Array.CreateInstance(typeof(T), RecyclableDefaults.InitialCapacity);
|
||||
_memoryBlock = new T[RecyclableDefaults.InitialCapacity];
|
||||
zRecyclableListAddRange.AddRange(this, source);
|
||||
}
|
||||
|
||||
public RecyclableList(IReadOnlyList<T> source)
|
||||
{
|
||||
_capacity = RecyclableDefaults.InitialCapacity;
|
||||
_memoryBlock = Array.CreateInstance(typeof(T), RecyclableDefaults.InitialCapacity);
|
||||
_memoryBlock = new T[RecyclableDefaults.InitialCapacity];
|
||||
zRecyclableListAddRange.AddRange(this, source);
|
||||
}
|
||||
|
||||
public RecyclableList(List<T> source)
|
||||
{
|
||||
_capacity = RecyclableDefaults.InitialCapacity;
|
||||
_memoryBlock = Array.CreateInstance(typeof(T), RecyclableDefaults.InitialCapacity);
|
||||
_memoryBlock = new T[RecyclableDefaults.InitialCapacity];
|
||||
zRecyclableListAddRange.AddRange(this, source);
|
||||
}
|
||||
|
||||
public RecyclableList(ICollection source)
|
||||
{
|
||||
_capacity = RecyclableDefaults.InitialCapacity;
|
||||
_memoryBlock = Array.CreateInstance(typeof(T), RecyclableDefaults.InitialCapacity);
|
||||
_memoryBlock = new T[RecyclableDefaults.InitialCapacity];
|
||||
zRecyclableListAddRange.AddRange(this, source);
|
||||
}
|
||||
|
||||
public RecyclableList(ICollection<T> source)
|
||||
{
|
||||
_capacity = RecyclableDefaults.InitialCapacity;
|
||||
_memoryBlock = Array.CreateInstance(typeof(T), RecyclableDefaults.InitialCapacity);
|
||||
_memoryBlock = new T[RecyclableDefaults.InitialCapacity];
|
||||
zRecyclableListAddRange.AddRange(this, source);
|
||||
}
|
||||
|
||||
@@ -128,13 +110,13 @@ namespace Recyclable.Collections
|
||||
{
|
||||
_memoryBlock = initialCapacity >= RecyclableDefaults.MinPooledArrayLength
|
||||
? RecyclableArrayPool<T>.RentShared(checked((int)BitOperations.RoundUpToPowerOf2((uint)initialCapacity)))
|
||||
: Array.CreateInstance(typeof(T), initialCapacity);
|
||||
: new T[initialCapacity];
|
||||
_capacity = _memoryBlock.Length;
|
||||
}
|
||||
else
|
||||
{
|
||||
_capacity = RecyclableDefaults.InitialCapacity;
|
||||
_memoryBlock = Array.CreateInstance(typeof(T), RecyclableDefaults.InitialCapacity);
|
||||
_memoryBlock = new T[RecyclableDefaults.InitialCapacity];
|
||||
}
|
||||
|
||||
zRecyclableListAddRange.AddRange(this, source, RecyclableDefaults.MinPooledArrayLength);
|
||||
@@ -146,13 +128,13 @@ namespace Recyclable.Collections
|
||||
{
|
||||
_memoryBlock = initialCapacity >= RecyclableDefaults.MinPooledArrayLength
|
||||
? RecyclableArrayPool<T>.RentShared(checked((int)BitOperations.RoundUpToPowerOf2((uint)initialCapacity)))
|
||||
: Array.CreateInstance(typeof(T), initialCapacity);
|
||||
: new T[initialCapacity];
|
||||
_capacity = _memoryBlock.Length;
|
||||
}
|
||||
else
|
||||
{
|
||||
_capacity = RecyclableDefaults.InitialCapacity;
|
||||
_memoryBlock = Array.CreateInstance(typeof(T), RecyclableDefaults.InitialCapacity);
|
||||
_memoryBlock = new T[RecyclableDefaults.InitialCapacity];
|
||||
}
|
||||
|
||||
zRecyclableListAddRange.AddRange(this, source);
|
||||
@@ -161,23 +143,21 @@ namespace Recyclable.Collections
|
||||
public RecyclableList(Span<T> source)
|
||||
{
|
||||
_capacity = RecyclableDefaults.InitialCapacity;
|
||||
_memoryBlock = Array.CreateInstance(typeof(T), RecyclableDefaults.InitialCapacity);
|
||||
_memoryBlock = new T[RecyclableDefaults.InitialCapacity];
|
||||
zRecyclableListAddRange.AddRange(this, source);
|
||||
}
|
||||
|
||||
public T this[int index]
|
||||
{
|
||||
#nullable disable
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get => (T)_memoryBlock.GetValue(index);
|
||||
get => _memoryBlock[index];
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
set
|
||||
{
|
||||
_memoryBlock.SetValue(value, index);
|
||||
_memoryBlock[index] = value;
|
||||
_version++;
|
||||
}
|
||||
#nullable restore
|
||||
}
|
||||
|
||||
internal int _capacity;
|
||||
@@ -207,11 +187,11 @@ namespace Recyclable.Collections
|
||||
RecyclableListHelpers<T>.ResizeAndCopy(this);
|
||||
}
|
||||
|
||||
_memoryBlock.SetValue(item, _count++);
|
||||
_memoryBlock[_count++] = item;
|
||||
_version++;
|
||||
}
|
||||
|
||||
public Array AsArray => _memoryBlock;
|
||||
public T[] AsArray => _memoryBlock;
|
||||
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
public void Clear()
|
||||
@@ -250,10 +230,11 @@ namespace Recyclable.Collections
|
||||
|
||||
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++;
|
||||
_version++;
|
||||
}
|
||||
@@ -272,7 +253,7 @@ namespace Recyclable.Collections
|
||||
|
||||
if (_needsClearing)
|
||||
{
|
||||
_memoryBlock.SetValue(default, _count);
|
||||
_memoryBlock[_count] = default;
|
||||
}
|
||||
|
||||
_version++;
|
||||
@@ -299,7 +280,7 @@ namespace Recyclable.Collections
|
||||
|
||||
if (_needsClearing)
|
||||
{
|
||||
_memoryBlock.SetValue(default, _count);
|
||||
_memoryBlock[_count] = default;
|
||||
}
|
||||
|
||||
_version++;
|
||||
|
||||
@@ -189,7 +189,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 ? (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);
|
||||
|
||||
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,
|
||||
// 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);
|
||||
|
||||
@@ -590,7 +590,7 @@ namespace Recyclable.Collections
|
||||
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> targetBlockArraySpan = new(targetMemoryBlocksSpan[targetBlockIndex], targetList._nextItemIndex, targetList._blockSize - targetList._nextItemIndex);
|
||||
|
||||
|
||||
@@ -150,7 +150,7 @@ namespace Recyclable.Collections
|
||||
if (requiredBlockCount > sourceBlockCount)
|
||||
{
|
||||
// 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
|
||||
if (sourceBlockCount > 0)
|
||||
@@ -179,7 +179,7 @@ namespace Recyclable.Collections
|
||||
ref OneSizeArrayPool<T> blockArrayPool = ref RecyclableArrayPool<T>.Shared(minBlockSize);
|
||||
while (blockIndex >= 0 && newMemoryBlocks[blockIndex] == null)
|
||||
{
|
||||
newMemoryBlocks[blockIndex--] = (T[])blockArrayPool.Rent();
|
||||
newMemoryBlocks[blockIndex--] = blockArrayPool.Rent();
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
@@ -338,13 +338,13 @@ namespace Recyclable.CollectionsTests
|
||||
|
||||
// Arrange
|
||||
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
|
||||
list.Clear();
|
||||
|
||||
// Assert
|
||||
_ = ((object[])list.AsArray)[..itemsCount].Should().AllSatisfy(x => x.Should().BeNull());
|
||||
_ = list.AsArray[..itemsCount].Should().AllSatisfy(x => x.Should().BeNull());
|
||||
}
|
||||
|
||||
[Theory]
|
||||
@@ -393,12 +393,6 @@ namespace Recyclable.CollectionsTests
|
||||
_ = list.Should().Equal(testData);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ConstructorShouldCreateArrayWithCustomBoundaries()
|
||||
{
|
||||
using var list = new RecyclableList<long>(-10);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(RecyclableLongListTestData.SourceDataVariants), MemberType = typeof(RecyclableLongListTestData))]
|
||||
public void ConstructorSourceShouldInitializeList(string testCase, IEnumerable<long> testData, int itemsCount)
|
||||
@@ -481,14 +475,14 @@ namespace Recyclable.CollectionsTests
|
||||
// Arrange
|
||||
using var list = new RecyclableList<object>(testData, itemsCount);
|
||||
var listArray = list.AsArray;
|
||||
_ = ((object[])list.AsArray)[..itemsCount].Should().NotBeNull();
|
||||
_ = ((object[])listArray)[..itemsCount].Should().AllSatisfy(x => x.Should().NotBeNull());
|
||||
_ = list.AsArray[..itemsCount].Should().NotBeNull();
|
||||
_ = listArray[..itemsCount].Should().AllSatisfy(x => x.Should().NotBeNull());
|
||||
|
||||
// Act
|
||||
list.Dispose();
|
||||
|
||||
// Assert
|
||||
_ = ((object[])listArray)[..itemsCount].Should().AllSatisfy(x => x.Should().BeNull());
|
||||
_ = listArray[..itemsCount].Should().AllSatisfy(x => x.Should().BeNull());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
||||
Reference in new issue
Block a user