Added support for ReadOnlySpan<T>

This commit is contained in:
mlemanczyk committed 2023-06-11 21:55:40 +02:00
1 parent b0a61e5aae
commit 1f00a431fb
2 files changed
+263

No files matched your search

+36
View File
@@ -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)