Added support for ReadOnlySpan<T>
This commit is contained in:
1 parent
b0a61e5aae
commit
1f00a431fb
2 files changed
+263
No files matched your search
@@ -12,6 +12,8 @@ namespace Recyclable.Collections
|
|||||||
|
|
||||||
protected T[] _memoryBlock;
|
protected T[] _memoryBlock;
|
||||||
|
|
||||||
|
public static explicit operator ReadOnlySpan<T>(RecyclableList<T> source) => new(source._memoryBlock, 0, source.Count);
|
||||||
|
|
||||||
private static void ThrowArgumentOutOfRangeException(in string message)
|
private static void ThrowArgumentOutOfRangeException(in string message)
|
||||||
{
|
{
|
||||||
throw new ArgumentOutOfRangeException(message, (Exception?)null);
|
throw new ArgumentOutOfRangeException(message, (Exception?)null);
|
||||||
@@ -92,6 +94,20 @@ namespace Recyclable.Collections
|
|||||||
AddRange(source);
|
AddRange(source);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#pragma warning disable CS8618 // _memory will be initialized when the 1st item is added
|
||||||
|
public RecyclableList(RecyclableLongList<T> source)
|
||||||
|
#pragma warning restore CS8618
|
||||||
|
{
|
||||||
|
AddRange(source);
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma warning disable CS8618 // _memory will be initialized when the 1st item is added
|
||||||
|
public RecyclableList(ReadOnlySpan<T> source)
|
||||||
|
#pragma warning restore CS8618
|
||||||
|
{
|
||||||
|
AddRange(source);
|
||||||
|
}
|
||||||
|
|
||||||
#pragma warning disable CS8618 // _memory will be initialized when the 1st item is added
|
#pragma warning disable CS8618 // _memory will be initialized when the 1st item is added
|
||||||
public RecyclableList(in T[] source)
|
public RecyclableList(in T[] source)
|
||||||
#pragma warning restore CS8618
|
#pragma warning restore CS8618
|
||||||
@@ -188,6 +204,26 @@ namespace Recyclable.Collections
|
|||||||
_count = targetCapacity;
|
_count = targetCapacity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
|
||||||
|
public void AddRange(ReadOnlySpan<T> itemsSpan)
|
||||||
|
{
|
||||||
|
if (itemsSpan.Length == 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int sourceItemsCount = itemsSpan.Length;
|
||||||
|
int targetCapacity = _count + sourceItemsCount;
|
||||||
|
if (_capacity < targetCapacity)
|
||||||
|
{
|
||||||
|
_ = EnsureCapacity(this, targetCapacity);
|
||||||
|
}
|
||||||
|
|
||||||
|
var targetSpan = new Span<T>(_memoryBlock, _count, sourceItemsCount);
|
||||||
|
itemsSpan.CopyTo(targetSpan);
|
||||||
|
_count = targetCapacity;
|
||||||
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
|
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)]
|
||||||
public void AddRange(List<T> items)
|
public void AddRange(List<T> items)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -417,6 +417,186 @@ namespace Recyclable.Collections
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#pragma warning disable CS8618 // It's set by SetupBlockArrayPooling
|
||||||
|
public RecyclableLongList(in T[] source, int minBlockSize = RecyclableDefaults.BlockSize, long? expectedItemsCount = default, ArrayPool<T[]>? memoryBlocksPool = default, ArrayPool<T>? blockArrayPool = default)
|
||||||
|
#pragma warning restore CS8618
|
||||||
|
{
|
||||||
|
_memoryBlocksPool = memoryBlocksPool ?? _defaultMemoryBlocksPool;
|
||||||
|
if (expectedItemsCount > 0)
|
||||||
|
{
|
||||||
|
minBlockSize = checked((int)BitOperations.RoundUpToPowerOf2((uint)minBlockSize));
|
||||||
|
SetupBlockArrayPooling(this, minBlockSize, blockArrayPool);
|
||||||
|
_capacity = Resize(this, minBlockSize, _blockSizePow2BitShift, expectedItemsCount.Value);
|
||||||
|
if (minBlockSize != _memoryBlocks![0].Length && _capacity > 0)
|
||||||
|
{
|
||||||
|
SetupBlockArrayPooling(this, _memoryBlocks[0].Length, blockArrayPool);
|
||||||
|
_blockSizeMinus1 = _blockSize - 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_blockSizeMinus1 = minBlockSize - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SetupBlockArrayPooling(this, checked((int)BitOperations.RoundUpToPowerOf2((uint)minBlockSize)), blockArrayPool);
|
||||||
|
_blockSizeMinus1 = _blockSize - 1;
|
||||||
|
_memoryBlocks = _emptyMemoryBlocksArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
AddRange(source);
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma warning disable CS8618 // It's set by SetupBlockArrayPooling
|
||||||
|
public RecyclableLongList(ReadOnlySpan<T> source, int minBlockSize = RecyclableDefaults.BlockSize, long? expectedItemsCount = default, ArrayPool<T[]>? memoryBlocksPool = default, ArrayPool<T>? blockArrayPool = default)
|
||||||
|
#pragma warning restore CS8618
|
||||||
|
{
|
||||||
|
_memoryBlocksPool = memoryBlocksPool ?? _defaultMemoryBlocksPool;
|
||||||
|
if (expectedItemsCount > 0)
|
||||||
|
{
|
||||||
|
minBlockSize = checked((int)BitOperations.RoundUpToPowerOf2((uint)minBlockSize));
|
||||||
|
SetupBlockArrayPooling(this, minBlockSize, blockArrayPool);
|
||||||
|
_capacity = Resize(this, minBlockSize, _blockSizePow2BitShift, expectedItemsCount.Value);
|
||||||
|
if (minBlockSize != _memoryBlocks![0].Length && _capacity > 0)
|
||||||
|
{
|
||||||
|
SetupBlockArrayPooling(this, _memoryBlocks[0].Length, blockArrayPool);
|
||||||
|
_blockSizeMinus1 = _blockSize - 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_blockSizeMinus1 = minBlockSize - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SetupBlockArrayPooling(this, checked((int)BitOperations.RoundUpToPowerOf2((uint)minBlockSize)), blockArrayPool);
|
||||||
|
_blockSizeMinus1 = _blockSize - 1;
|
||||||
|
_memoryBlocks = _emptyMemoryBlocksArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
AddRange(source);
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma warning disable CS8618 // It's set by SetupBlockArrayPooling
|
||||||
|
public RecyclableLongList(RecyclableList<T> source, int minBlockSize = RecyclableDefaults.BlockSize, long? expectedItemsCount = default, ArrayPool<T[]>? memoryBlocksPool = default, ArrayPool<T>? blockArrayPool = default)
|
||||||
|
#pragma warning restore CS8618
|
||||||
|
{
|
||||||
|
_memoryBlocksPool = memoryBlocksPool ?? _defaultMemoryBlocksPool;
|
||||||
|
if (expectedItemsCount > 0)
|
||||||
|
{
|
||||||
|
minBlockSize = checked((int)BitOperations.RoundUpToPowerOf2((uint)minBlockSize));
|
||||||
|
SetupBlockArrayPooling(this, minBlockSize, blockArrayPool);
|
||||||
|
_capacity = Resize(this, minBlockSize, _blockSizePow2BitShift, expectedItemsCount.Value);
|
||||||
|
if (minBlockSize != _memoryBlocks![0].Length && _capacity > 0)
|
||||||
|
{
|
||||||
|
SetupBlockArrayPooling(this, _memoryBlocks[0].Length, blockArrayPool);
|
||||||
|
_blockSizeMinus1 = _blockSize - 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_blockSizeMinus1 = minBlockSize - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SetupBlockArrayPooling(this, checked((int)BitOperations.RoundUpToPowerOf2((uint)minBlockSize)), blockArrayPool);
|
||||||
|
_blockSizeMinus1 = _blockSize - 1;
|
||||||
|
_memoryBlocks = _emptyMemoryBlocksArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
AddRange(source);
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma warning disable CS8618 // It's set by SetupBlockArrayPooling
|
||||||
|
public RecyclableLongList(RecyclableLongList<T> source, int minBlockSize = RecyclableDefaults.BlockSize, long? expectedItemsCount = default, ArrayPool<T[]>? memoryBlocksPool = default, ArrayPool<T>? blockArrayPool = default)
|
||||||
|
#pragma warning restore CS8618
|
||||||
|
{
|
||||||
|
_memoryBlocksPool = memoryBlocksPool ?? _defaultMemoryBlocksPool;
|
||||||
|
if (expectedItemsCount > 0)
|
||||||
|
{
|
||||||
|
minBlockSize = checked((int)BitOperations.RoundUpToPowerOf2((uint)minBlockSize));
|
||||||
|
SetupBlockArrayPooling(this, minBlockSize, blockArrayPool);
|
||||||
|
_capacity = Resize(this, minBlockSize, _blockSizePow2BitShift, expectedItemsCount.Value);
|
||||||
|
if (minBlockSize != _memoryBlocks![0].Length && _capacity > 0)
|
||||||
|
{
|
||||||
|
SetupBlockArrayPooling(this, _memoryBlocks[0].Length, blockArrayPool);
|
||||||
|
_blockSizeMinus1 = _blockSize - 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_blockSizeMinus1 = minBlockSize - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SetupBlockArrayPooling(this, checked((int)BitOperations.RoundUpToPowerOf2((uint)minBlockSize)), blockArrayPool);
|
||||||
|
_blockSizeMinus1 = _blockSize - 1;
|
||||||
|
_memoryBlocks = _emptyMemoryBlocksArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
AddRange(source);
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma warning disable CS8618 // It's set by SetupBlockArrayPooling
|
||||||
|
public RecyclableLongList(List<T> source, int minBlockSize = RecyclableDefaults.BlockSize, long? expectedItemsCount = default, ArrayPool<T[]>? memoryBlocksPool = default, ArrayPool<T>? blockArrayPool = default)
|
||||||
|
#pragma warning restore CS8618
|
||||||
|
{
|
||||||
|
_memoryBlocksPool = memoryBlocksPool ?? _defaultMemoryBlocksPool;
|
||||||
|
if (expectedItemsCount > 0)
|
||||||
|
{
|
||||||
|
minBlockSize = checked((int)BitOperations.RoundUpToPowerOf2((uint)minBlockSize));
|
||||||
|
SetupBlockArrayPooling(this, minBlockSize, blockArrayPool);
|
||||||
|
_capacity = Resize(this, minBlockSize, _blockSizePow2BitShift, expectedItemsCount.Value);
|
||||||
|
if (minBlockSize != _memoryBlocks![0].Length && _capacity > 0)
|
||||||
|
{
|
||||||
|
SetupBlockArrayPooling(this, _memoryBlocks[0].Length, blockArrayPool);
|
||||||
|
_blockSizeMinus1 = _blockSize - 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_blockSizeMinus1 = minBlockSize - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SetupBlockArrayPooling(this, checked((int)BitOperations.RoundUpToPowerOf2((uint)minBlockSize)), blockArrayPool);
|
||||||
|
_blockSizeMinus1 = _blockSize - 1;
|
||||||
|
_memoryBlocks = _emptyMemoryBlocksArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
AddRange(source);
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma warning disable CS8618 // It's set by SetupBlockArrayPooling
|
||||||
|
public RecyclableLongList(IList<T> source, int minBlockSize = RecyclableDefaults.BlockSize, long? expectedItemsCount = default, ArrayPool<T[]>? memoryBlocksPool = default, ArrayPool<T>? blockArrayPool = default)
|
||||||
|
#pragma warning restore CS8618
|
||||||
|
{
|
||||||
|
_memoryBlocksPool = memoryBlocksPool ?? _defaultMemoryBlocksPool;
|
||||||
|
if (expectedItemsCount > 0)
|
||||||
|
{
|
||||||
|
minBlockSize = checked((int)BitOperations.RoundUpToPowerOf2((uint)minBlockSize));
|
||||||
|
SetupBlockArrayPooling(this, minBlockSize, blockArrayPool);
|
||||||
|
_capacity = Resize(this, minBlockSize, _blockSizePow2BitShift, expectedItemsCount.Value);
|
||||||
|
if (minBlockSize != _memoryBlocks![0].Length && _capacity > 0)
|
||||||
|
{
|
||||||
|
SetupBlockArrayPooling(this, _memoryBlocks[0].Length, blockArrayPool);
|
||||||
|
_blockSizeMinus1 = _blockSize - 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_blockSizeMinus1 = minBlockSize - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SetupBlockArrayPooling(this, checked((int)BitOperations.RoundUpToPowerOf2((uint)minBlockSize)), blockArrayPool);
|
||||||
|
_blockSizeMinus1 = _blockSize - 1;
|
||||||
|
_memoryBlocks = _emptyMemoryBlocksArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
AddRange(source);
|
||||||
|
}
|
||||||
|
|
||||||
#pragma warning disable CS8618 // It's set by SetupBlockArrayPooling
|
#pragma warning disable CS8618 // It's set by SetupBlockArrayPooling
|
||||||
public RecyclableLongList(IEnumerable<T> source, int minBlockSize = RecyclableDefaults.BlockSize, long? expectedItemsCount = default, ArrayPool<T[]>? memoryBlocksPool = default, ArrayPool<T>? blockArrayPool = default)
|
public RecyclableLongList(IEnumerable<T> source, int minBlockSize = RecyclableDefaults.BlockSize, long? expectedItemsCount = default, ArrayPool<T[]>? memoryBlocksPool = default, ArrayPool<T>? blockArrayPool = default)
|
||||||
#pragma warning restore CS8618
|
#pragma warning restore CS8618
|
||||||
@@ -576,6 +756,53 @@ namespace Recyclable.Collections
|
|||||||
_lastBlockWithData = targetBlockIndex - (itemsSpan.Length > 0 ? 0 : 1);
|
_lastBlockWithData = targetBlockIndex - (itemsSpan.Length > 0 ? 0 : 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void AddRange(ReadOnlySpan<T> itemsSpan)
|
||||||
|
{
|
||||||
|
if (itemsSpan.Length == 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
long targetCapacity = _longCount + itemsSpan.Length;
|
||||||
|
if (_capacity < targetCapacity)
|
||||||
|
{
|
||||||
|
_ = EnsureCapacity(this, 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 (itemsSpan.Length >= targetBlockArraySpan.Length)
|
||||||
|
{
|
||||||
|
itemsSpan[..targetBlockArraySpan.Length].CopyTo(targetBlockArraySpan);
|
||||||
|
itemsSpan = itemsSpan[targetBlockArraySpan.Length..];
|
||||||
|
if (itemsSpan.Length == 0)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
targetBlockIndex++;
|
||||||
|
targetBlockArraySpan = new(memoryBlocksSpan[targetBlockIndex], 0, blockSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (itemsSpan.Length > 0)
|
||||||
|
{
|
||||||
|
itemsSpan.CopyTo(targetBlockArraySpan);
|
||||||
|
_nextItemBlockIndex = targetBlockIndex;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_nextItemBlockIndex = targetBlockIndex + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
_nextItemIndex = itemsSpan.Length;
|
||||||
|
_longCount = targetCapacity;
|
||||||
|
_lastBlockWithData = targetBlockIndex;
|
||||||
|
}
|
||||||
|
|
||||||
public void AddRange(RecyclableLongList<T> items)
|
public void AddRange(RecyclableLongList<T> items)
|
||||||
{
|
{
|
||||||
if (items.LongCount == 0)
|
if (items.LongCount == 0)
|
||||||
|
|||||||
Reference in new issue
Block a user