Revert "Support for custom boundaries implemented. v1 - will be reverted due to 5x slower performance."

This reverts commit 22d8593e1f.
This commit is contained in:
mlemanczyk committed 2023-09-17 13:15:17 +02:00
1 parent 22d8593e1f
commit 2ff1aab655
12 files changed
+92 -192

No files matched your search

+6 -4
View File
@@ -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()
+34 -53
View File
@@ -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]