Unit tests extended. Missing .ToRecyclableList() & .ToRecyclableLongList() variants added. Support for all major interfaces finished. README.md updated.

This commit is contained in:
mlemanczyk committed 2023-09-10 17:42:08 +02:00
1 parent 9cd2096783
commit a315ff80d5
8 files changed
+791 -183

No files matched your search

+13 -12
View File
@@ -126,18 +126,19 @@
1. ✅ `.Remove` / `.RemoveAt` / `.Clear` / `.Dispose` must clear reference when reference type
1. ✅ `.Clear` / `.Dispose` must return arrays to pools
1. ✅ `int` / `long` variants of `.Count` / `.LongCount`, `.IndexOf` / `.LongIndexOf`, `.Insert`, `.RemoveAt`, `this[]`
1. 👉 Add `.ToRecyclableList` / `.ToRecyclableLongList` variants for all supported collection types
1. 🅿️ `RecyclableList`
1. 🅿️ `RecyclableLongList`
1. 🅿️ `IList<T>`
1. 🅿️ `ICollection<T>`
1. 🅿️ `IEnumerable<T>`
1. 🅿️ `IEnumerable`
1. 🅿️ `IReadOnlyList<T>`
1. 🅿️ `IReadOnlyCollection<T>`
1. 🅿️ `IList`
1. 🅿️ `ICollection`
1. 🅿️ Release 0.0.5
1. ✅ Add `.ToRecyclableList` / `.ToRecyclableLongList` variants for all supported collection types
1. ✅ `Array`
1. ✅ `ICollection`
1. ✅ `ICollection<T>`
1. ✅ `IEnumerable`
1. ✅ `IEnumerable<T>`
1. ✅ `IReadOnlyList<T>`
1. ✅ `ReadOnlySpan<T>`
1. ✅ `RecyclableList`
1. ✅ `RecyclableLongList`
1. ✅ `Span<T>`
1. ✅ `T[]`
1. 👉 Release 0.0.5
1. 🅿️ Add support for `ulong` indexing
1. 🅿️ Convert `_memoryBlocks` to `Array` to allow `ulong` lengths
1. 🅿️ Convert block indexes from `int` to `ulong` or `long`
@@ -1,19 +1,44 @@
using System.Runtime.CompilerServices;
using System.Collections;
using System.Runtime.CompilerServices;
namespace Recyclable.Collections
{
public static class RecyclableListExtensions
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static RecyclableList<T> ToRecyclableList<T>(this Array values) => new(values);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static RecyclableList<T> ToRecyclableList<T>(this ICollection values) => new(values);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static RecyclableList<T> ToRecyclableList<T>(this ICollection<T> values) => new(values);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static RecyclableList<T> ToRecyclableList<T>(this IEnumerable values) => new(values);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static RecyclableList<T> ToRecyclableList<T>(this IEnumerable<T> values) => new(values);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static RecyclableList<T> ToRecyclableList<T>(this T[] values) => new(values);
public static RecyclableList<T> ToRecyclableList<T>(this IReadOnlyList<T> values) => new(values);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static RecyclableList<T> ToRecyclableList<T>(this List<T> values) => new(values);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static RecyclableList<T> ToRecyclableList<T>(this ReadOnlySpan<T> values) => new(values);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static RecyclableList<T> ToRecyclableList<T>(this RecyclableList<T> values) => new(values);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static RecyclableList<T> ToRecyclableList<T>(this RecyclableLongList<T> values) => new(values);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static RecyclableList<T> ToRecyclableList<T>(this Span<T> values) => new(values);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static RecyclableList<T> ToRecyclableList<T>(this T[] values) => new(values);
}
}
+168 -12
View File
@@ -19,13 +19,13 @@ namespace Recyclable.Collections
internal ulong _version;
public ulong Version => _version;
private IEnumerator<T> AddRangeEnumerated(IEnumerable<T> source, int growByCount)
private void AddRangeEnumerated(IEnumerable<T> items, int growByCount)
{
int targetItemIndex = _count;
Span<T> memorySpan;
int i;
var enumerator = source.GetEnumerator();
var enumerator = items.GetEnumerator();
int capacity = _capacity;
memorySpan = new(_memoryBlock);
@@ -55,15 +55,14 @@ namespace Recyclable.Collections
_capacity = capacity;
_count = targetItemIndex;
return enumerator;
}
private void AddRangeWithKnownCount(IEnumerable<T> source, int currentItemsCount, int requiredAdditionalCapacity)
private void AddRangeWithKnownCount(IEnumerable<T> items, int currentItemsCount, int requiredAdditionalCapacity)
{
_capacity = RecyclableListHelpers<T>.ResizeAndCopy(this, currentItemsCount, checked((int)BitOperations.RoundUpToPowerOf2((uint)(currentItemsCount + requiredAdditionalCapacity))));
Span<T> memorySpan = new(_memoryBlock);
foreach (var item in source)
foreach (var item in items)
{
memorySpan[currentItemsCount++] = item;
}
@@ -93,6 +92,30 @@ namespace Recyclable.Collections
}
}
public void AddRange(IReadOnlyList<T> items)
{
int sourceItemsCount = items.Count;
if (_capacity < _count + sourceItemsCount)
{
_capacity = RecyclableListHelpers<T>.ResizeAndCopy(this, _count, checked((int)BitOperations.RoundUpToPowerOf2((uint)(_count + sourceItemsCount))));
}
Span<T> memorySpan = new(_memoryBlock, _count, sourceItemsCount);
for (var sourceItemIndex = 0; sourceItemIndex < sourceItemsCount; sourceItemIndex++)
{
memorySpan[sourceItemIndex] = items[sourceItemIndex];
}
_count += sourceItemsCount;
}
public RecyclableList(in Array source)
{
_capacity = RecyclableDefaults.InitialCapacity;
_memoryBlock = new T[RecyclableDefaults.InitialCapacity];
AddRange(source);
}
public RecyclableList(RecyclableList<T> source)
{
_capacity = RecyclableDefaults.InitialCapacity;
@@ -121,6 +144,13 @@ namespace Recyclable.Collections
AddRange(source);
}
public RecyclableList(IReadOnlyList<T> source)
{
_capacity = RecyclableDefaults.InitialCapacity;
_memoryBlock = new T[RecyclableDefaults.InitialCapacity];
AddRange(source);
}
public RecyclableList(List<T> source)
{
_capacity = RecyclableDefaults.InitialCapacity;
@@ -128,13 +158,38 @@ namespace Recyclable.Collections
AddRange(source);
}
public RecyclableList(IList<T> source)
public RecyclableList(ICollection source)
{
_capacity = RecyclableDefaults.InitialCapacity;
_memoryBlock = new T[RecyclableDefaults.InitialCapacity];
AddRange(source);
}
public RecyclableList(ICollection<T> source)
{
_capacity = RecyclableDefaults.InitialCapacity;
_memoryBlock = new T[RecyclableDefaults.InitialCapacity];
AddRange(source);
}
public RecyclableList(IEnumerable source, int initialCapacity = RecyclableDefaults.InitialCapacity)
{
if (initialCapacity >= RecyclableDefaults.InitialCapacity)
{
_memoryBlock = initialCapacity >= RecyclableDefaults.MinPooledArrayLength
? RecyclableArrayPool<T>.RentShared(checked((int)BitOperations.RoundUpToPowerOf2((uint)initialCapacity)))
: new T[initialCapacity];
_capacity = _memoryBlock.Length;
}
else
{
_capacity = RecyclableDefaults.InitialCapacity;
_memoryBlock = new T[RecyclableDefaults.InitialCapacity];
}
AddRange(source, RecyclableDefaults.MinPooledArrayLength);
}
public RecyclableList(IEnumerable<T> source, int initialCapacity = RecyclableDefaults.InitialCapacity)
{
if (initialCapacity >= RecyclableDefaults.InitialCapacity)
@@ -153,6 +208,13 @@ namespace Recyclable.Collections
AddRange(source);
}
public RecyclableList(Span<T> source)
{
_capacity = RecyclableDefaults.InitialCapacity;
_memoryBlock = new T[RecyclableDefaults.InitialCapacity];
AddRange(source);
}
public T this[int index]
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -197,6 +259,19 @@ namespace Recyclable.Collections
_version++;
}
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
public void AddRange(in Array items)
{
if (_capacity < _count + items.Length)
{
_capacity = RecyclableListHelpers<T>.ResizeAndCopy(this, _count, checked((int)BitOperations.RoundUpToPowerOf2((uint)(_count + items.Length))));
}
Array.Copy(items, items.GetLowerBound(0), _memoryBlock, _count, items.LongLength);
_count += items.Length;
_version++;
}
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
public void AddRange(in T[] items)
{
@@ -223,6 +298,19 @@ namespace Recyclable.Collections
_version++;
}
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
public void AddRange(Span<T> items)
{
if (_capacity < _count + items.Length)
{
_capacity = RecyclableListHelpers<T>.ResizeAndCopy(this, _count, checked((int)BitOperations.RoundUpToPowerOf2((uint)(_count + items.Length))));
}
items.CopyTo(new Span<T>(_memoryBlock, _count, items.Length));
_count += items.Length;
_version++;
}
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
public void AddRange(List<T> items)
{
@@ -237,7 +325,20 @@ namespace Recyclable.Collections
}
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
public void AddRange(IList<T> items)
public void AddRange(ICollection items)
{
if (_capacity < _count + items.Count)
{
_capacity = RecyclableListHelpers<T>.ResizeAndCopy(this, _count, checked((int)BitOperations.RoundUpToPowerOf2((uint)(_count + items.Count))));
}
items.CopyTo(_memoryBlock, _count);
_count += items.Count;
_version++;
}
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
public void AddRange(ICollection<T> items)
{
if (_capacity < _count + items.Count)
{
@@ -313,24 +414,79 @@ namespace Recyclable.Collections
_version++;
}
public IEnumerator AddRange(IEnumerable source, int growByCount = RecyclableDefaults.MinPooledArrayLength)
{
int targetItemIndex = _count;
Span<T> memorySpan;
int i;
var enumerator = source.GetEnumerator();
int capacity = _capacity;
memorySpan = new(_memoryBlock);
if (enumerator.MoveNext())
{
int available = capacity - targetItemIndex;
do
{
if (targetItemIndex + growByCount > capacity)
{
capacity = RecyclableListHelpers<T>.ResizeAndCopy(this, targetItemIndex, checked((int)BitOperations.RoundUpToPowerOf2((uint)(targetItemIndex + growByCount))));
memorySpan = new(_memoryBlock);
available = capacity - targetItemIndex;
}
for (i = 0; i < available; i++)
{
memorySpan[targetItemIndex++] = (T)enumerator.Current;
if (!enumerator.MoveNext())
{
break;
}
}
}
while (i >= available);
}
_capacity = capacity;
_count = targetItemIndex;
return enumerator;
}
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
public void AddRange(IEnumerable<T> items, int growByCount = RecyclableDefaults.MinPooledArrayLength)
{
if (items is T[] sourceArray)
if (items is RecyclableList<T> sourceRecyclableList)
{
AddRange(sourceRecyclableList);
}
else if (items is RecyclableLongList<T> sourceRecyclableLongList)
{
AddRange(sourceRecyclableLongList);
}
else if (items is T[] sourceArray)
{
AddRange(sourceArray);
}
else if (items is Array sourceArrayWithObjects)
{
AddRange(sourceArrayWithObjects);
}
else if (items is List<T> sourceList)
{
AddRange(sourceList);
}
else if (items is RecyclableList<T> sourceRecyclableList)
else if (items is ICollection<T> sourceICollection)
{
AddRange(sourceRecyclableList);
AddRange(sourceICollection);
}
else if (items is IList<T> sourceIList)
else if (items is ICollection sourceICollectionWithObjects)
{
AddRange(sourceIList);
AddRange(sourceICollectionWithObjects);
}
else if (items is IReadOnlyList<T> sourceIReadOnlyList)
{
AddRange(sourceIReadOnlyList);
}
else if (items.TryGetNonEnumeratedCount(out var requiredAdditionalCapacity) && requiredAdditionalCapacity != 0)
{
@@ -1,19 +1,44 @@
using System.Runtime.CompilerServices;
using System.Collections;
using System.Runtime.CompilerServices;
namespace Recyclable.Collections
{
public static class RecyclableLongListExtensions
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static RecyclableLongList<T> ToRecyclableLongList<T>(this Array values, int blockSize = RecyclableDefaults.BlockSize) => new(values, blockSize);
public static RecyclableLongList<T> ToRecyclableLongList<T>(this Array values, int minBlockSize = RecyclableDefaults.BlockSize) => new(values, minBlockSize);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static RecyclableLongList<T> ToRecyclableLongList<T>(this IList<T> values, int blockSize = RecyclableDefaults.BlockSize) => new(values, blockSize);
public static RecyclableLongList<T> ToRecyclableLongList<T>(this ICollection values, int minBlockSize = RecyclableDefaults.BlockSize) => new(values, minBlockSize);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static RecyclableLongList<T> ToRecyclableLongList<T>(this List<T> values, int blockSize = RecyclableDefaults.BlockSize) => new(values, blockSize);
public static RecyclableLongList<T> ToRecyclableLongList<T>(this ICollection<T> values, int minBlockSize = RecyclableDefaults.BlockSize) => new(values, minBlockSize);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static RecyclableLongList<T> ToRecyclableLongList<T>(this IEnumerable values, int minBlockSize = RecyclableDefaults.BlockSize) => new(values, minBlockSize: minBlockSize);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static RecyclableLongList<T> ToRecyclableLongList<T>(this IEnumerable<T> values, int minBlockSize = RecyclableDefaults.BlockSize) => new(values, minBlockSize: minBlockSize);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static RecyclableLongList<T> ToRecyclableLongList<T>(this IReadOnlyList<T> values, int minBlockSize = RecyclableDefaults.BlockSize) => new(values, minBlockSize);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static RecyclableLongList<T> ToRecyclableLongList<T>(this List<T> values, int minBlockSize = RecyclableDefaults.BlockSize) => new(values, minBlockSize);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static RecyclableLongList<T> ToRecyclableLongList<T>(this ReadOnlySpan<T> values, int minBlockSize = RecyclableDefaults.BlockSize) => new(values, minBlockSize);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static RecyclableLongList<T> ToRecyclableLongList<T>(this RecyclableList<T> values, int minBlockSize = RecyclableDefaults.BlockSize) => new(values, minBlockSize);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static RecyclableLongList<T> ToRecyclableLongList<T>(this RecyclableLongList<T> values, int minBlockSize = RecyclableDefaults.BlockSize) => new(values, minBlockSize);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static RecyclableLongList<T> ToRecyclableLongList<T>(this Span<T> values, int minBlockSize = RecyclableDefaults.BlockSize) => new(values, minBlockSize);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static RecyclableLongList<T> ToRecyclableLongList<T>(this T[] values, int minBlockSize = RecyclableDefaults.BlockSize) => new(values, minBlockSize);
}
}
+359 -97
View File
@@ -60,12 +60,12 @@ namespace Recyclable.Collections
public int ReservedBlockCount => _reservedBlockCount;
public ulong Version => _version;
private void AddRangeEnumerated(IEnumerable<T> source)
private void AddRangeEnumerated(IEnumerable<T> items)
{
long i, copied = _longCount;
int blockSize = _blockSize, targetItemIdx = _nextItemIndex, targetBlockIdx = _nextItemBlockIndex;
using IEnumerator<T> enumerator = source.GetEnumerator();
using IEnumerator<T> enumerator = items.GetEnumerator();
if (!enumerator.MoveNext())
{
return;
@@ -134,7 +134,7 @@ namespace Recyclable.Collections
}
}
private void AddRangeWithKnownCount(IEnumerable<T> source, int requiredAdditionalCapacity)
private void AddRangeWithKnownCount(IEnumerable<T> items, int requiredAdditionalCapacity)
{
long copied = _longCount;
int blockSize = _blockSize;
@@ -158,7 +158,7 @@ namespace Recyclable.Collections
var memoryBlocksCount = _reservedBlockCount;
memoryBlocksSpan = new(_memoryBlocks, 0, memoryBlocksCount);
blockArraySpan = new(memoryBlocksSpan[targetBlockIdx], 0, blockSize);
foreach (var item in source)
foreach (var item in items)
{
blockArraySpan[targetItemIdx++] = item;
if (targetItemIdx == blockSize)
@@ -199,139 +199,126 @@ namespace Recyclable.Collections
}
}
public RecyclableLongList(in T[] source, int minBlockSize = RecyclableDefaults.BlockSize, long? expectedItemsCount = default)
public RecyclableLongList(in T[] source, int minBlockSize = RecyclableDefaults.BlockSize)
{
minBlockSize = checked((int)BitOperations.RoundUpToPowerOf2((uint)minBlockSize));
if (expectedItemsCount > 0)
{
Helpers.SetupBlockArrayPooling(this, minBlockSize);
_capacity = Helpers.Resize(this, minBlockSize, _blockSizePow2BitShift, checked((long)BitOperations.RoundUpToPowerOf2((ulong)expectedItemsCount.Value)));
_blockSizeMinus1 = minBlockSize - 1;
}
else
{
Helpers.SetupBlockArrayPooling(this, minBlockSize);
_blockSizeMinus1 = _blockSize - 1;
_memoryBlocks = _emptyMemoryBlocksArray;
}
Helpers.SetupBlockArrayPooling(this, minBlockSize);
_capacity = Helpers.Resize(this, minBlockSize, _blockSizePow2BitShift, checked((long)BitOperations.RoundUpToPowerOf2((ulong)source.LongLength)));
_blockSizeMinus1 = minBlockSize - 1;
AddRange(source);
}
public RecyclableLongList(in Array source, int minBlockSize = RecyclableDefaults.BlockSize, long? expectedItemsCount = default)
public RecyclableLongList(in Array source, int minBlockSize = RecyclableDefaults.BlockSize)
{
minBlockSize = checked((int)BitOperations.RoundUpToPowerOf2((uint)minBlockSize));
if (expectedItemsCount > 0)
{
Helpers.SetupBlockArrayPooling(this, minBlockSize);
_capacity = Helpers.Resize(this, minBlockSize, _blockSizePow2BitShift, checked((long)BitOperations.RoundUpToPowerOf2((ulong)expectedItemsCount.Value)));
_blockSizeMinus1 = minBlockSize - 1;
}
else
{
Helpers.SetupBlockArrayPooling(this, minBlockSize);
_blockSizeMinus1 = _blockSize - 1;
_memoryBlocks = _emptyMemoryBlocksArray;
}
Helpers.SetupBlockArrayPooling(this, minBlockSize);
_capacity = Helpers.Resize(this, minBlockSize, _blockSizePow2BitShift, checked((long)BitOperations.RoundUpToPowerOf2((ulong)source.LongLength)));
_blockSizeMinus1 = minBlockSize - 1;
AddRange(source);
}
public RecyclableLongList(ReadOnlySpan<T> source, int minBlockSize = RecyclableDefaults.BlockSize, long? expectedItemsCount = default)
public RecyclableLongList(IReadOnlyList<T> source, int minBlockSize = RecyclableDefaults.BlockSize)
{
minBlockSize = checked((int)BitOperations.RoundUpToPowerOf2((uint)minBlockSize));
if (expectedItemsCount > 0)
{
Helpers.SetupBlockArrayPooling(this, minBlockSize);
_capacity = Helpers.Resize(this, minBlockSize, _blockSizePow2BitShift, checked((long)BitOperations.RoundUpToPowerOf2((ulong)expectedItemsCount.Value)));
_blockSizeMinus1 = minBlockSize - 1;
}
else
{
Helpers.SetupBlockArrayPooling(this, minBlockSize);
_blockSizeMinus1 = _blockSize - 1;
_memoryBlocks = _emptyMemoryBlocksArray;
}
Helpers.SetupBlockArrayPooling(this, minBlockSize);
_capacity = Helpers.Resize(this, minBlockSize, _blockSizePow2BitShift, BitOperations.RoundUpToPowerOf2((uint)source.Count));
_blockSizeMinus1 = minBlockSize - 1;
AddRange(source);
}
public RecyclableLongList(RecyclableList<T> source, int minBlockSize = RecyclableDefaults.BlockSize, long? expectedItemsCount = default)
public RecyclableLongList(ReadOnlySpan<T> source, int minBlockSize = RecyclableDefaults.BlockSize)
{
minBlockSize = checked((int)BitOperations.RoundUpToPowerOf2((uint)minBlockSize));
if (expectedItemsCount > 0)
{
Helpers.SetupBlockArrayPooling(this, minBlockSize);
_capacity = Helpers.Resize(this, minBlockSize, _blockSizePow2BitShift, checked((long)BitOperations.RoundUpToPowerOf2((ulong)expectedItemsCount.Value)));
_blockSizeMinus1 = minBlockSize - 1;
}
else
{
Helpers.SetupBlockArrayPooling(this, minBlockSize);
_blockSizeMinus1 = _blockSize - 1;
_memoryBlocks = _emptyMemoryBlocksArray;
}
Helpers.SetupBlockArrayPooling(this, minBlockSize);
_capacity = Helpers.Resize(this, minBlockSize, _blockSizePow2BitShift, checked((long)BitOperations.RoundUpToPowerOf2((ulong)source.Length)));
_blockSizeMinus1 = minBlockSize - 1;
AddRange(source);
}
public RecyclableLongList(RecyclableLongList<T> source, int minBlockSize = RecyclableDefaults.BlockSize, long? expectedItemsCount = default)
public RecyclableLongList(RecyclableList<T> source, int minBlockSize = RecyclableDefaults.BlockSize)
{
minBlockSize = checked((int)BitOperations.RoundUpToPowerOf2((uint)minBlockSize));
if (expectedItemsCount > 0)
{
Helpers.SetupBlockArrayPooling(this, minBlockSize);
_capacity = Helpers.Resize(this, minBlockSize, _blockSizePow2BitShift, checked((long)BitOperations.RoundUpToPowerOf2((ulong)expectedItemsCount.Value)));
_blockSizeMinus1 = minBlockSize - 1;
}
else
{
Helpers.SetupBlockArrayPooling(this, minBlockSize);
_blockSizeMinus1 = _blockSize - 1;
_memoryBlocks = _emptyMemoryBlocksArray;
}
Helpers.SetupBlockArrayPooling(this, minBlockSize);
_capacity = Helpers.Resize(this, minBlockSize, _blockSizePow2BitShift, BitOperations.RoundUpToPowerOf2((uint)source.Count));
_blockSizeMinus1 = minBlockSize - 1;
AddRange(source);
}
public RecyclableLongList(List<T> source, int minBlockSize = RecyclableDefaults.BlockSize, long? expectedItemsCount = default)
public RecyclableLongList(RecyclableLongList<T> source, int minBlockSize = RecyclableDefaults.BlockSize)
{
minBlockSize = checked((int)BitOperations.RoundUpToPowerOf2((uint)minBlockSize));
if (expectedItemsCount > 0)
{
Helpers.SetupBlockArrayPooling(this, minBlockSize);
_capacity = Helpers.Resize(this, minBlockSize, _blockSizePow2BitShift, checked((long)BitOperations.RoundUpToPowerOf2((ulong)expectedItemsCount.Value)));
_blockSizeMinus1 = minBlockSize - 1;
}
else
{
Helpers.SetupBlockArrayPooling(this, minBlockSize);
_blockSizeMinus1 = _blockSize - 1;
_memoryBlocks = _emptyMemoryBlocksArray;
}
Helpers.SetupBlockArrayPooling(this, minBlockSize);
_capacity = Helpers.Resize(this, minBlockSize, _blockSizePow2BitShift, checked((long)BitOperations.RoundUpToPowerOf2((ulong)source.Count)));
_blockSizeMinus1 = minBlockSize - 1;
AddRange(source);
}
public RecyclableLongList(IList<T> source, int minBlockSize = RecyclableDefaults.BlockSize, long? expectedItemsCount = default)
public RecyclableLongList(Span<T> source, int minBlockSize = RecyclableDefaults.BlockSize)
{
minBlockSize = checked((int)BitOperations.RoundUpToPowerOf2((uint)minBlockSize));
Helpers.SetupBlockArrayPooling(this, minBlockSize);
_capacity = Helpers.Resize(this, minBlockSize, _blockSizePow2BitShift, checked((long)BitOperations.RoundUpToPowerOf2((ulong)source.Length)));
_blockSizeMinus1 = minBlockSize - 1;
AddRange(source);
}
public RecyclableLongList(List<T> source, int minBlockSize = RecyclableDefaults.BlockSize)
{
minBlockSize = checked((int)BitOperations.RoundUpToPowerOf2((uint)minBlockSize));
Helpers.SetupBlockArrayPooling(this, minBlockSize);
_capacity = Helpers.Resize(this, minBlockSize, _blockSizePow2BitShift, BitOperations.RoundUpToPowerOf2((uint)source.Count));
_blockSizeMinus1 = minBlockSize - 1;
AddRange(source);
}
public RecyclableLongList(ICollection source, int minBlockSize = RecyclableDefaults.BlockSize)
{
minBlockSize = checked((int)BitOperations.RoundUpToPowerOf2((uint)minBlockSize));
Helpers.SetupBlockArrayPooling(this, minBlockSize);
_capacity = Helpers.Resize(this, minBlockSize, _blockSizePow2BitShift, BitOperations.RoundUpToPowerOf2((uint)source.Count));
_blockSizeMinus1 = minBlockSize - 1;
AddRange(source);
}
public RecyclableLongList(ICollection<T> source, int minBlockSize = RecyclableDefaults.BlockSize)
{
minBlockSize = checked((int)BitOperations.RoundUpToPowerOf2((uint)minBlockSize));
Helpers.SetupBlockArrayPooling(this, minBlockSize);
_capacity = Helpers.Resize(this, minBlockSize, _blockSizePow2BitShift, BitOperations.RoundUpToPowerOf2((uint)source.Count));
_blockSizeMinus1 = minBlockSize - 1;
AddRange(source);
}
public RecyclableLongList(IEnumerable source, int minBlockSize = RecyclableDefaults.BlockSize, long? expectedItemsCount = default)
{
Helpers.SetupBlockArrayPooling(this, minBlockSize = checked((int)BitOperations.RoundUpToPowerOf2((uint)minBlockSize)));
if (expectedItemsCount > 0)
{
Helpers.SetupBlockArrayPooling(this, minBlockSize);
_capacity = Helpers.Resize(this, minBlockSize, _blockSizePow2BitShift, checked((long)BitOperations.RoundUpToPowerOf2((ulong)expectedItemsCount.Value)));
_capacity = Helpers.Resize(this, minBlockSize, _blockSizePow2BitShift, checked((int)BitOperations.RoundUpToPowerOf2((uint)expectedItemsCount.Value)));
_blockSizeMinus1 = minBlockSize - 1;
}
else
{
Helpers.SetupBlockArrayPooling(this, minBlockSize);
_blockSizeMinus1 = _blockSize - 1;
_memoryBlocks = _emptyMemoryBlocksArray;
}
@@ -423,7 +410,7 @@ namespace Recyclable.Collections
targetBlockIndex = _nextItemBlockIndex;
long fullBlockItemsCount = items.LongLength - blockSize,
sourceItemIndex = blockSize - _nextItemIndex;
sourceItemIndex = Math.Min(blockSize - _nextItemIndex, items.LongLength);
Span<T[]> memoryBlocksSpan = new(_memoryBlocks, 0, _reservedBlockCount);
@@ -439,11 +426,25 @@ namespace Recyclable.Collections
if ((blockSize = (int)(items.LongLength - sourceItemIndex)) > 0)
{
Array.Copy(items, sourceItemIndex, memoryBlocksSpan[targetBlockIndex], 0, blockSize);
_lastBlockWithData = targetBlockIndex;
_nextItemBlockIndex = targetBlockIndex;
_nextItemIndex = blockSize;
}
else
{
_lastBlockWithData = targetBlockIndex - 1;
if (_nextItemIndex + sourceItemIndex >= _blockSize)
{
_nextItemBlockIndex = targetBlockIndex;
_nextItemIndex = 0;
}
else
{
_nextItemIndex += (int)sourceItemIndex;
}
}
_nextItemIndex = blockSize;
_longCount = targetCapacity;
_lastBlockWithData = targetBlockIndex;
_version++;
}
@@ -690,6 +691,62 @@ namespace Recyclable.Collections
_version++;
}
public void AddRange(Span<T> items)
{
if (items.Length == 0)
{
return;
}
long targetCapacity = _longCount + items.Length;
if (_capacity < targetCapacity)
{
_capacity = Helpers.Resize(this, _blockSize, _blockSizePow2BitShift, checked((long)BitOperations.RoundUpToPowerOf2((ulong)targetCapacity)));
}
int blockSize = _blockSize,
targetBlockIndex = _nextItemBlockIndex,
memoryBlockCount = _reservedBlockCount;
Span<T[]> memoryBlocksSpan = new(_memoryBlocks, 0, memoryBlockCount);
Span<T> targetBlockArraySpan = new(memoryBlocksSpan[targetBlockIndex], _nextItemIndex, blockSize - _nextItemIndex);
while (items.Length >= targetBlockArraySpan.Length)
{
items[..targetBlockArraySpan.Length].CopyTo(targetBlockArraySpan);
items = items[targetBlockArraySpan.Length..];
if (items.Length == 0)
{
break;
}
targetBlockIndex++;
targetBlockArraySpan = new(memoryBlocksSpan[targetBlockIndex], 0, blockSize);
}
if (items.Length > 0)
{
items.CopyTo(targetBlockArraySpan);
if (_nextItemBlockIndex != targetBlockIndex)
{
_nextItemIndex = items.Length;
_nextItemBlockIndex = targetBlockIndex;
}
else
{
_nextItemIndex += items.Length;
}
}
else
{
_nextItemBlockIndex = targetBlockIndex + 1;
_nextItemIndex = 0;
}
_longCount = targetCapacity;
_lastBlockWithData = targetBlockIndex;
_version++;
}
public void AddRange(List<T> items)
{
if (items.Count == 0)
@@ -738,7 +795,7 @@ namespace Recyclable.Collections
_version++;
}
public void AddRange(IList<T> items)
public void AddRange(ICollection items)
{
if (items.Count == 0)
{
@@ -811,27 +868,186 @@ namespace Recyclable.Collections
}
}
public void AddRange(ICollection<T> items)
{
if (items.Count == 0)
{
return;
}
long targetCapacity = _longCount + items.Count;
if (_capacity < targetCapacity)
{
_capacity = Helpers.Resize(this, _blockSize, _blockSizePow2BitShift, checked((long)BitOperations.RoundUpToPowerOf2((ulong)targetCapacity)));
}
int blockSize = _blockSize,
targetBlockIndex = _nextItemBlockIndex,
memoryBlockCount = _reservedBlockCount;
// 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 ? RecyclableArrayPool<T>.RentShared((int)BitOperations.RoundUpToPowerOf2((uint)items.Count)) : new T[items.Count];
try
{
items.CopyTo(itemsBuffer, 0);
Span<T> itemsSpan = new(itemsBuffer, 0, items.Count);
Span<T[]> memoryBlocksSpan = new(_memoryBlocks, 0, memoryBlockCount);
Span<T> targetBlockArraySpan = new(memoryBlocksSpan[targetBlockIndex], _nextItemIndex, blockSize - _nextItemIndex);
while (targetBlockArraySpan.Length <= itemsSpan.Length)
{
itemsSpan[..targetBlockArraySpan.Length].CopyTo(targetBlockArraySpan);
itemsSpan = itemsSpan[targetBlockArraySpan.Length..];
targetBlockIndex++;
if (targetBlockIndex == memoryBlockCount)
{
break;
}
targetBlockArraySpan = new(memoryBlocksSpan[targetBlockIndex], 0, blockSize);
}
if (itemsSpan.Length > 0)
{
itemsSpan.CopyTo(targetBlockArraySpan);
if (_nextItemBlockIndex != targetBlockIndex)
{
_nextItemIndex = itemsSpan.Length;
_nextItemBlockIndex = targetBlockIndex;
}
else
{
_nextItemIndex += itemsSpan.Length;
}
}
else
{
_nextItemIndex = 0;
}
_longCount = targetCapacity;
_nextItemBlockIndex = targetBlockIndex;
_lastBlockWithData = targetBlockIndex - (itemsSpan.Length > 0 ? 0 : 1);
}
finally
{
if (items.Count >= RecyclableDefaults.MinPooledArrayLength)
{
RecyclableArrayPool<T>.ReturnShared(itemsBuffer, _needsClearing);
}
_version++;
}
}
public void AddRange(IEnumerable source)
{
long i, copied = _longCount;
int blockSize = _blockSize, targetItemIdx = _nextItemIndex, targetBlockIdx = _nextItemBlockIndex;
IEnumerator enumerator = source.GetEnumerator();
if (!enumerator.MoveNext())
{
return;
}
long capacity = _capacity;
long available = capacity - copied;
Span<T[]> memoryBlocksSpan = new(_memoryBlocks, 0, _reservedBlockCount);
Span<T> blockArraySpan;
var memoryBlocksCount = memoryBlocksSpan.Length;
while (true)
{
if (copied + blockSize > capacity)
{
capacity = Helpers.Resize(this, _blockSize, _blockSizePow2BitShift, checked((long)BitOperations.RoundUpToPowerOf2((ulong)(capacity + blockSize))));
memoryBlocksCount = _reservedBlockCount;
if (blockSize != _blockSize)
{
blockSize = _blockSize;
}
memoryBlocksSpan = new(_memoryBlocks, 0, memoryBlocksCount);
available = capacity - copied;
}
blockArraySpan = new(memoryBlocksSpan[targetBlockIdx], 0, blockSize);
for (i = 1; i <= available; i++)
{
blockArraySpan[targetItemIdx++] = (T)enumerator.Current;
if (!enumerator.MoveNext())
{
_lastBlockWithData = targetBlockIdx;
_longCount += copied + i - _longCount;
if (targetItemIdx < blockSize)
{
_nextItemBlockIndex = targetBlockIdx;
_nextItemIndex = targetItemIdx;
}
else
{
_nextItemBlockIndex = targetBlockIdx + 1;
_nextItemIndex = 0;
}
_capacity = capacity;
return;
}
if (targetItemIdx == blockSize)
{
targetBlockIdx++;
targetItemIdx = 0;
if (targetBlockIdx == memoryBlocksCount)
{
break;
}
blockArraySpan = new(memoryBlocksSpan[targetBlockIdx], 0, blockSize);
}
}
copied += available;
}
}
public void AddRange(IEnumerable<T> items)
{
if (items is RecyclableLongList<T> sourceRecyclableLongList)
{
AddRange(sourceRecyclableLongList);
}
else if (items is RecyclableList<T> sourceRecyclableList)
if (items is RecyclableList<T> sourceRecyclableList)
{
AddRange(sourceRecyclableList);
}
else if (items is RecyclableLongList<T> sourceRecyclableLongList)
{
AddRange(sourceRecyclableLongList);
}
else if (items is T[] sourceArray)
{
AddRange(sourceArray);
}
else if (items is Array sourceArrayWithObjects)
{
AddRange(sourceArrayWithObjects);
}
else if (items is List<T> sourceList)
{
AddRange(sourceList);
}
else if (items is IList<T> sourceIList)
else if (items is ICollection<T> sourceICollection)
{
AddRange(sourceIList);
AddRange(sourceICollection);
}
else if (items is ICollection sourceICollectionWithObjects)
{
AddRange(sourceICollectionWithObjects);
}
else if (items is IReadOnlyList<T> sourceIReadOnlyList)
{
AddRange(sourceIReadOnlyList);
}
else if (items.TryGetNonEnumeratedCount(out var requiredAdditionalCapacity))
{
@@ -845,6 +1061,52 @@ namespace Recyclable.Collections
}
}
public void AddRange(IReadOnlyList<T> items)
{
long copied = _longCount;
int blockSize = _blockSize;
int targetItemIdx = _nextItemIndex;
int targetBlockIdx = _nextItemBlockIndex;
Span<T[]> memoryBlocksSpan;
Span<T> blockArraySpan;
long sourceItemsCount = items.Count;
long requiredCapacity = copied + sourceItemsCount;
if (requiredCapacity == 0)
{
return;
}
if (_capacity < requiredCapacity)
{
_capacity = Helpers.Resize(this, _blockSize, _blockSizePow2BitShift, checked((long)BitOperations.RoundUpToPowerOf2((ulong)requiredCapacity)));
blockSize = _blockSize;
}
var memoryBlocksCount = _reservedBlockCount;
memoryBlocksSpan = new(_memoryBlocks, 0, memoryBlocksCount);
blockArraySpan = new(memoryBlocksSpan[targetBlockIdx], 0, blockSize);
for(var itemIndex = 0; itemIndex < sourceItemsCount; itemIndex++)
{
blockArraySpan[targetItemIdx++] = items[itemIndex];
if (targetItemIdx == blockSize)
{
targetItemIdx = 0;
if (++targetBlockIdx == memoryBlocksCount)
{
break;
}
blockArraySpan = new Span<T>(memoryBlocksSpan[targetBlockIdx]);
}
}
_longCount = requiredCapacity;
_nextItemBlockIndex = targetBlockIdx;
_nextItemIndex = targetItemIdx;
_lastBlockWithData = targetBlockIdx - (targetItemIdx > 0 ? 0 : 1);
}
public void Clear()
{
if (_longCount == 0)
@@ -1,6 +1,7 @@
using FluentAssertions;
using Recyclable.Collections;
using Recyclable.Collections.Linq;
using System.Collections;
#pragma warning disable xUnit1026, RCS1163, IDE0060, RCS1235
@@ -29,10 +30,34 @@ namespace Recyclable.CollectionsTests
using var list = new RecyclableList<long>();
// Act
if (testCase.Contains("ReadOnlySpan[", StringComparison.OrdinalIgnoreCase))
if (testCase.Contains("Array[", StringComparison.OrdinalIgnoreCase))
{
list.AddRange((Array)testData);
}
else if (testCase.Contains("ICollection[", StringComparison.OrdinalIgnoreCase))
{
list.AddRange((ICollection)testData);
}
else if (testCase.Contains("ICollection<T>[", StringComparison.OrdinalIgnoreCase))
{
list.AddRange((ICollection<long>)testData);
}
else if (testCase.Contains("IEnumerable[", StringComparison.OrdinalIgnoreCase))
{
list.AddRange((IEnumerable)testData);
}
else if (testCase.Contains("IReadOnlyList<T>[", StringComparison.OrdinalIgnoreCase))
{
list.AddRange((IReadOnlyList<long>)testData);
}
else if (testCase.Contains("ReadOnlySpan<T>[", StringComparison.OrdinalIgnoreCase))
{
list.AddRange(new ReadOnlySpan<long>((long[])testData));
}
else if (testCase.Contains("Span<T>[", StringComparison.OrdinalIgnoreCase))
{
list.AddRange(new Span<long>((long[])testData));
}
else if (testData is long[] testDataArray)
{
list.AddRange(testDataArray);
@@ -76,10 +101,34 @@ namespace Recyclable.CollectionsTests
using var list = new RecyclableList<long>();
// Act
if (testCase.Contains("ReadOnlySpan[", StringComparison.OrdinalIgnoreCase))
if (testCase.Contains("Array[", StringComparison.OrdinalIgnoreCase))
{
list.AddRange((Array)testData);
}
else if (testCase.Contains("ICollection[", StringComparison.OrdinalIgnoreCase))
{
list.AddRange((ICollection)testData);
}
else if (testCase.Contains("ICollection<T>[", StringComparison.OrdinalIgnoreCase))
{
list.AddRange((ICollection<long>)testData);
}
else if (testCase.Contains("IEnumerable[", StringComparison.OrdinalIgnoreCase))
{
list.AddRange((IEnumerable)testData);
}
else if (testCase.Contains("IReadOnlyList<T>[", StringComparison.OrdinalIgnoreCase))
{
list.AddRange((IReadOnlyList<long>)testData);
}
else if (testCase.Contains("ReadOnlySpan<T>[", StringComparison.OrdinalIgnoreCase))
{
list.AddRange(new ReadOnlySpan<long>((long[])testData));
}
else if (testCase.Contains("Span<T>[", StringComparison.OrdinalIgnoreCase))
{
list.AddRange(new Span<long>((long[])testData));
}
else if (testData is long[] testDataArray)
{
list.AddRange(testDataArray);
@@ -123,12 +172,43 @@ namespace Recyclable.CollectionsTests
using var list = new RecyclableList<long>();
// Act
if (testCase.Contains("ReadOnlySpan[", StringComparison.OrdinalIgnoreCase))
if (testCase.Contains("Array[", StringComparison.OrdinalIgnoreCase))
{
list.AddRange((Array)testData);
list.AddRange((Array)testData);
}
else if (testCase.Contains("ICollection[", StringComparison.OrdinalIgnoreCase))
{
list.AddRange((ICollection)testData);
list.AddRange((ICollection)testData);
}
else if (testCase.Contains("ICollection<T>[", StringComparison.OrdinalIgnoreCase))
{
list.AddRange((ICollection<long>)testData);
list.AddRange((ICollection<long>)testData);
}
else if (testCase.Contains("IEnumerable[", StringComparison.OrdinalIgnoreCase))
{
list.AddRange((IEnumerable)testData);
list.AddRange((IEnumerable)testData);
}
else if (testCase.Contains("IReadOnlyList<T>[", StringComparison.OrdinalIgnoreCase))
{
list.AddRange((IReadOnlyList<long>)testData);
list.AddRange((IReadOnlyList<long>)testData);
}
else if (testCase.Contains("ReadOnlySpan<T>[", StringComparison.OrdinalIgnoreCase))
{
var readOnlySpan = new ReadOnlySpan<long>((long[])testData);
list.AddRange(readOnlySpan);
list.AddRange(readOnlySpan);
}
else if (testCase.Contains("Span<T>[", StringComparison.OrdinalIgnoreCase))
{
var readOnlySpan = new Span<long>((long[])testData);
list.AddRange(readOnlySpan);
list.AddRange(readOnlySpan);
}
else if (testData is long[] testDataArray)
{
list.AddRange(testDataArray);
@@ -1,6 +1,7 @@
using MoreLinq;
using Open.Numeric.Primes;
using Recyclable.Collections;
using System.Collections;
using System.Numerics;
namespace Recyclable.CollectionsTests
@@ -78,23 +79,21 @@ namespace Recyclable.CollectionsTests
{
GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced, true, true);
IDisposable disposable;
switch (refType)
{
case false:
long[] testData = CreateTestData(itemsCount).ToArray();
yield return new object[] { $"int[{itemsCount}]", testData, itemsCount };
yield return new object[] { $"ReadOnlySpan[{itemsCount}]", testData, itemsCount };
//GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced, true, true);
yield return new object[] { $"List<int>(itemsCount: {itemsCount}", testData.ToList(), itemsCount };
//GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced, true, true);
yield return new object[] { $"RecyclableList<int>(itemsCount: {itemsCount})", disposable = testData.ToRecyclableList(), itemsCount };
//disposable.Dispose();
//GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced, true, true);
yield return new object[] { $"Array[{itemsCount}]", testData, itemsCount };
yield return new object[] { $"ICollection[{itemsCount}]", testData, itemsCount };
yield return new object[] { $"ICollection<T>[{itemsCount}]", testData, itemsCount };
yield return new object[] { $"IEnumerable[{itemsCount}]", testData, itemsCount };
yield return new object[] { $"IEnumerable<T>[{itemsCount}] without non-enumerated count", new EnumerableWithoutCount<long>(testData), itemsCount };
yield return new object[] { $"IList<T>[{itemsCount}]", new CustomIList<long>(testData), itemsCount };
yield return new object[] { $"IReadOnlyList<T>[{itemsCount}])", testData, itemsCount };
yield return new object[] { $"List<T>[{itemsCount}]", testData.ToList(), itemsCount };
yield return new object[] { $"ReadOnlySpan<T>[{itemsCount}]", testData, itemsCount };
yield return new object[] { $"RecyclableList<T>[{itemsCount}]", testData.ToRecyclableList(), itemsCount };
foreach (var sourceBlockSize in BlockSizeVariants)
{
@@ -105,39 +104,29 @@ namespace Recyclable.CollectionsTests
yield return new object[]
{
$"RecyclableLongList<int>(itemsCount: {itemsCount}, minBlockSize: {sourceBlockSize})",
disposable = testData.ToRecyclableLongList(sourceBlockSize),
$"RecyclableLongList<T>[itemsCount: {itemsCount}, minBlockSize: {sourceBlockSize}]",
testData.ToRecyclableLongList(sourceBlockSize),
itemsCount
};
//disposable.Dispose();
//GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced, true, true);
}
yield return new object[] { $"IList<int>(itemsCount: {itemsCount})", new CustomIList<long>(testData), itemsCount };
//GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced, true, true);
yield return new object[] { $"IEnumerable<int>(itemsCount: {itemsCount}) with non-enumerated count", testData, itemsCount };
//GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced, true, true);
yield return new object[] { $"IEnumerable<int>(itemsCount: {itemsCount}) without non-enumerated count", new EnumerableWithoutCount<long>(testData), itemsCount };
//GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced, true, true);
yield return new object[] { $"Span<T>[{itemsCount}]", testData, itemsCount };
yield return new object[] { $"T[{itemsCount}]", testData, itemsCount };
break;
case true:
IEnumerable<object> testRefData = CreateRefTestData(itemsCount).ToArray();
yield return new object[] { $"int[{itemsCount}]", testRefData, itemsCount };
//GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced, true, true);
yield return new object[] { $"List<int>(itemsCount: {itemsCount}", testRefData.ToList(), itemsCount };
//GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced, true, true);
yield return new object[] { $"RecyclableList<int>(itemsCount: {itemsCount})", disposable = testRefData.ToRecyclableList(), itemsCount };
//disposable.Dispose();
//GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced, true, true);
yield return new object[] { $"Array[{itemsCount}]", testRefData, itemsCount };
yield return new object[] { $"ICollection(itemsCount: {itemsCount}", testRefData, itemsCount };
yield return new object[] { $"ICollection<T>(itemsCount: {itemsCount}", testRefData, itemsCount };
yield return new object[] { $"IEnumerable(itemsCount: {itemsCount})", testRefData, itemsCount };
yield return new object[] { $"IEnumerable<T>(itemsCount: {itemsCount}) without non-enumerated count", new EnumerableWithoutCount<object>(testRefData), itemsCount };
yield return new object[] { $"IList<T>(itemsCount: {itemsCount})", new CustomIList<object>(testRefData), itemsCount };
yield return new object[] { $"IReadOnlyList<T>(itemsCount: {itemsCount})", testRefData, itemsCount };
yield return new object[] { $"List<T>(itemsCount: {itemsCount}", testRefData.ToList(), itemsCount };
yield return new object[] { $"ReadOnlySpan<T>[{itemsCount}]", testRefData, itemsCount };
yield return new object[] { $"RecyclableList<T>(itemsCount: {itemsCount})", testRefData.ToRecyclableList(), itemsCount };
foreach (var sourceBlockSize in BlockSizeVariants)
{
@@ -148,24 +137,14 @@ namespace Recyclable.CollectionsTests
yield return new object[]
{
$"RecyclableLongList<int>(itemsCount: {itemsCount}, minBlockSize: {sourceBlockSize})",
disposable = testRefData.ToRecyclableLongList(sourceBlockSize),
$"RecyclableLongList<T>(itemsCount: {itemsCount}, minBlockSize: {sourceBlockSize})",
testRefData.ToRecyclableLongList(sourceBlockSize),
itemsCount
};
//disposable.Dispose();
//GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced, true, true);
}
yield return new object[] { $"IList<int>(itemsCount: {itemsCount})", new CustomIList<object>(testRefData), itemsCount };
//GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced, true, true);
yield return new object[] { $"IEnumerable<int>(itemsCount: {itemsCount}) with non-enumerated count", testRefData, itemsCount };
//GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced, true, true);
yield return new object[] { $"IEnumerable<int>(itemsCount: {itemsCount}) without non-enumerated count", new EnumerableWithoutCount<object>(testRefData), itemsCount };
//GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced, true, true);
yield return new object[] { $"Span<T>[{itemsCount}]", testRefData, itemsCount };
yield return new object[] { $"T[{itemsCount}]", testRefData, itemsCount };
break;
}
}
@@ -1,6 +1,7 @@
using FluentAssertions;
using Recyclable.Collections;
using Recyclable.Collections.Linq;
using System.Collections;
using System.Numerics;
#pragma warning disable xUnit1026, RCS1163, IDE0060, RCS1235
@@ -41,10 +42,34 @@ namespace Recyclable.CollectionsTests
using var list = new RecyclableLongList<long>(minBlockSize: targetBlockSize);
// Act
if (testCase.Contains("ReadOnlySpan[", StringComparison.OrdinalIgnoreCase))
if (testCase.Contains("Array[", StringComparison.OrdinalIgnoreCase))
{
list.AddRange((Array)testData);
}
else if (testCase.Contains("ICollection[", StringComparison.OrdinalIgnoreCase))
{
list.AddRange((ICollection)testData);
}
else if (testCase.Contains("ICollection<T>[", StringComparison.OrdinalIgnoreCase))
{
list.AddRange((ICollection<long>)testData);
}
else if (testCase.Contains("IEnumerable[", StringComparison.OrdinalIgnoreCase))
{
list.AddRange((IEnumerable)testData);
}
else if (testCase.Contains("IReadOnlyList<T>[", StringComparison.OrdinalIgnoreCase))
{
list.AddRange((IReadOnlyList<long>)testData);
}
else if (testCase.Contains("ReadOnlySpan<T>[", StringComparison.OrdinalIgnoreCase))
{
list.AddRange(new ReadOnlySpan<long>((long[])testData));
}
else if (testCase.Contains("Span<T>[", StringComparison.OrdinalIgnoreCase))
{
list.AddRange(new Span<long>((long[])testData));
}
else if (testData is long[] testDataArray)
{
list.AddRange(testDataArray);
@@ -90,10 +115,34 @@ namespace Recyclable.CollectionsTests
using var list = new RecyclableLongList<long>();
// Act
if (testCase.Contains("ReadOnlySpan[", StringComparison.OrdinalIgnoreCase))
if (testCase.Contains("Array[", StringComparison.OrdinalIgnoreCase))
{
list.AddRange((Array)testData);
}
else if (testCase.Contains("ICollection[", StringComparison.OrdinalIgnoreCase))
{
list.AddRange((ICollection)testData);
}
else if (testCase.Contains("ICollection<T>[", StringComparison.OrdinalIgnoreCase))
{
list.AddRange((ICollection<long>)testData);
}
else if (testCase.Contains("IEnumerable[", StringComparison.OrdinalIgnoreCase))
{
list.AddRange((IEnumerable)testData);
}
else if (testCase.Contains("IReadOnlyList<T>[", StringComparison.OrdinalIgnoreCase))
{
list.AddRange((IReadOnlyList<long>)testData);
}
else if (testCase.Contains("ReadOnlySpan<T>[", StringComparison.OrdinalIgnoreCase))
{
list.AddRange(new ReadOnlySpan<long>((long[])testData));
}
else if (testCase.Contains("Span<T>[", StringComparison.OrdinalIgnoreCase))
{
list.AddRange(new Span<long>((long[])testData));
}
else if (testData is long[] testDataArray)
{
list.AddRange(testDataArray);
@@ -138,12 +187,43 @@ namespace Recyclable.CollectionsTests
using var list = new RecyclableLongList<long>(minBlockSize: targetBlockSize);
// Act
if (testCase.Contains("ReadOnlySpan[", StringComparison.OrdinalIgnoreCase))
if (testCase.Contains("Array[", StringComparison.OrdinalIgnoreCase))
{
list.AddRange((Array)testData);
list.AddRange((Array)testData);
}
else if (testCase.Contains("ICollection[", StringComparison.OrdinalIgnoreCase))
{
list.AddRange((ICollection)testData);
list.AddRange((ICollection)testData);
}
else if (testCase.Contains("ICollection<T>[", StringComparison.OrdinalIgnoreCase))
{
list.AddRange((ICollection<long>)testData);
list.AddRange((ICollection<long>)testData);
}
else if (testCase.Contains("IEnumerable[", StringComparison.OrdinalIgnoreCase))
{
list.AddRange((IEnumerable)testData);
list.AddRange((IEnumerable)testData);
}
else if (testCase.Contains("IReadOnlyList<T>[", StringComparison.OrdinalIgnoreCase))
{
list.AddRange((IReadOnlyList<long>)testData);
list.AddRange((IReadOnlyList<long>)testData);
}
else if (testCase.Contains("ReadOnlySpan<T>[", StringComparison.OrdinalIgnoreCase))
{
var readOnlySpan = new ReadOnlySpan<long>((long[])testData);
list.AddRange(readOnlySpan);
list.AddRange(readOnlySpan);
}
else if (testCase.Contains("Span<T>[", StringComparison.OrdinalIgnoreCase))
{
var readOnlySpan = new Span<long>((long[])testData);
list.AddRange(readOnlySpan);
list.AddRange(readOnlySpan);
}
else if (testData is long[] testDataArray)
{
list.AddRange(testDataArray);