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;
|
||||
|
||||
public static explicit operator ReadOnlySpan<T>(RecyclableList<T> source) => new(source._memoryBlock, 0, source.Count);
|
||||
|
||||
private static void ThrowArgumentOutOfRangeException(in string message)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(message, (Exception?)null);
|
||||
@@ -92,6 +94,20 @@ namespace Recyclable.Collections
|
||||
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
|
||||
public RecyclableList(in T[] source)
|
||||
#pragma warning restore CS8618
|
||||
@@ -188,6 +204,26 @@ namespace Recyclable.Collections
|
||||
_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)]
|
||||
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
|
||||
public RecyclableLongList(IEnumerable<T> source, int minBlockSize = RecyclableDefaults.BlockSize, long? expectedItemsCount = default, ArrayPool<T[]>? memoryBlocksPool = default, ArrayPool<T>? blockArrayPool = default)
|
||||
#pragma warning restore CS8618
|
||||
@@ -576,6 +756,53 @@ namespace Recyclable.Collections
|
||||
_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)
|
||||
{
|
||||
if (items.LongCount == 0)
|
||||
|
||||
Reference in new issue
Block a user