Small cleanup
This commit is contained in:
1 parent
f928e1e35e
commit
96968d5452
11 files changed
+63
-64
No files matched your search
@@ -1,5 +1,4 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<TargetFrameworks>net6.0;net7.0</TargetFrameworks>
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
{
|
||||
public const int BlockIndexLimit = int.MaxValue;
|
||||
public const int BlockSize = 16_384;
|
||||
public const int Capacity = 1;
|
||||
public const int InitialCapacity = 4;
|
||||
public const long MinItemsCountForParallelization = 850_000;
|
||||
public const int MinPooledArrayLength = 37;
|
||||
|
||||
@@ -17,13 +17,14 @@ namespace Recyclable.Collections
|
||||
{
|
||||
Span<T> arrayMemory = destinationArray.AsSpan();
|
||||
arrayMemory = arrayMemory[destinationArrayIndex..];
|
||||
// TODO: Convert "/" & "%" to bit-shifting
|
||||
int startingArrayIndex = (int)(startingIndex / blockSize);
|
||||
startingIndex %= blockSize;
|
||||
if (arrays.Count > 0)
|
||||
if (arrays._count > 0)
|
||||
{
|
||||
ReadOnlySpan<T> sourceMemory = arrays[0].AsSpan();
|
||||
var maxToCopy = (int)Math.Min(blockSize - startingIndex, arrayMemory.Length);
|
||||
if (arrays.Count == 1)
|
||||
if (arrays._count == 1)
|
||||
{
|
||||
maxToCopy = Math.Min(maxToCopy, lastBlockSize);
|
||||
}
|
||||
@@ -33,7 +34,7 @@ namespace Recyclable.Collections
|
||||
arrayMemory = arrayMemory[maxToCopy..];
|
||||
}
|
||||
|
||||
for (var arrayIdx = startingArrayIndex + 1; arrayIdx < arrays.Count - 1 && arrayMemory.Length > 0; arrayIdx++)
|
||||
for (var arrayIdx = startingArrayIndex + 1; arrayIdx < arrays._count - 1 && arrayMemory.Length > 0; arrayIdx++)
|
||||
{
|
||||
ReadOnlySpan<T> sourceMemory = arrays[arrayIdx].AsSpan();
|
||||
var maxToCopy = Math.Min(blockSize, arrayMemory.Length);
|
||||
@@ -42,7 +43,7 @@ namespace Recyclable.Collections
|
||||
arrayMemory = arrayMemory[maxToCopy..];
|
||||
}
|
||||
|
||||
if (arrays.Count > 1 && arrayMemory.Length > 0)
|
||||
if (arrays._count > 1 && arrayMemory.Length > 0)
|
||||
{
|
||||
ReadOnlySpan<T> sourceMemory = arrays[^1].AsSpan();
|
||||
var maxToCopy = Math.Min(lastBlockSize, arrayMemory.Length);
|
||||
@@ -56,7 +57,7 @@ namespace Recyclable.Collections
|
||||
public static IEnumerable<T> Enumerate(RecyclableList<T[]> arrays, int chunkSize, long totalCount)
|
||||
{
|
||||
long currentCount = 0;
|
||||
for (var arrayIdx = 0; (arrayIdx < arrays.Count) && (currentCount < totalCount); arrayIdx++)
|
||||
for (var arrayIdx = 0; (arrayIdx < arrays._count) && (currentCount < totalCount); arrayIdx++)
|
||||
{
|
||||
var array = arrays[arrayIdx];
|
||||
currentCount += Math.Min(chunkSize, totalCount);
|
||||
@@ -86,7 +87,7 @@ namespace Recyclable.Collections
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static long LongIndexOf(RecyclableList<T[]> arrays, int blockSize, T item, IEqualityComparer<T> comparer)
|
||||
{
|
||||
for (var arrayIdx = 0; arrayIdx < arrays.Count; arrayIdx++)
|
||||
for (var arrayIdx = 0; arrayIdx < arrays._count; arrayIdx++)
|
||||
{
|
||||
var array = arrays[arrayIdx];
|
||||
Span<T> arrayMemory = array.AsSpan();
|
||||
|
||||
@@ -8,9 +8,9 @@ namespace Recyclable.Collections
|
||||
[Serializable]
|
||||
public sealed partial class RecyclableList<T> : IList<T>, IReadOnlyList<T>, IDisposable
|
||||
{
|
||||
private static readonly bool NeedsClearing = !typeof(T).IsValueType;
|
||||
private static readonly bool _needsClearing = !typeof(T).IsValueType;
|
||||
|
||||
public static explicit operator ReadOnlySpan<T>(RecyclableList<T> source) => new(source._memoryBlock, 0, source.Count);
|
||||
public static explicit operator ReadOnlySpan<T>(RecyclableList<T> source) => new(source._memoryBlock, 0, source._count);
|
||||
|
||||
#nullable disable
|
||||
internal T[] _memoryBlock;
|
||||
@@ -59,17 +59,17 @@ namespace Recyclable.Collections
|
||||
return enumerator;
|
||||
}
|
||||
|
||||
private void AddRangeWithKnownCount(IEnumerable<T> source, int targetItemIdx, int requiredAdditionalCapacity)
|
||||
private void AddRangeWithKnownCount(IEnumerable<T> source, int currentItemsCount, int requiredAdditionalCapacity)
|
||||
{
|
||||
_capacity = RecyclableListHelpers<T>.ResizeAndCopy(this, checked((int)BitOperations.RoundUpToPowerOf2((uint)(targetItemIdx + requiredAdditionalCapacity))));
|
||||
_capacity = RecyclableListHelpers<T>.ResizeAndCopy(this, checked((int)BitOperations.RoundUpToPowerOf2((uint)(currentItemsCount + requiredAdditionalCapacity))));
|
||||
|
||||
Span<T> memorySpan = new(_memoryBlock);
|
||||
foreach (var item in source)
|
||||
{
|
||||
memorySpan[targetItemIdx++] = item;
|
||||
memorySpan[currentItemsCount++] = item;
|
||||
}
|
||||
|
||||
_count = targetItemIdx;
|
||||
_count = currentItemsCount;
|
||||
}
|
||||
|
||||
public RecyclableList()
|
||||
@@ -136,7 +136,7 @@ namespace Recyclable.Collections
|
||||
AddRange(source);
|
||||
}
|
||||
|
||||
public RecyclableList(IEnumerable<T> source, int initialCapacity = RecyclableDefaults.Capacity)
|
||||
public RecyclableList(IEnumerable<T> source, int initialCapacity = RecyclableDefaults.InitialCapacity)
|
||||
{
|
||||
if (initialCapacity >= RecyclableDefaults.InitialCapacity)
|
||||
{
|
||||
@@ -271,7 +271,7 @@ namespace Recyclable.Collections
|
||||
return;
|
||||
}
|
||||
|
||||
var sourceItemsCount = items.LongCount;
|
||||
var sourceItemsCount = items._longCount;
|
||||
if (sourceItemsCount > int.MaxValue)
|
||||
{
|
||||
ThrowHelper.ThrowArgumentOutOfRangeException(nameof(items), $"The number of items exceeds the maximum capacity of {nameof(RecyclableList<T>)}, equal {int.MaxValue}, equal {int.MaxValue}. Please consider using {nameof(RecyclableLongList<T>)}, instead");
|
||||
@@ -292,7 +292,7 @@ namespace Recyclable.Collections
|
||||
itemsSpan;
|
||||
|
||||
int blockIndex,
|
||||
sourceBlockSize = items.BlockSize,
|
||||
sourceBlockSize = items._blockSize,
|
||||
lastBlockIndex = (int)(sourceItemsCount >> items._blockSizePow2BitShift) - 1;
|
||||
|
||||
for (blockIndex = 0; blockIndex <= lastBlockIndex; blockIndex++)
|
||||
@@ -307,9 +307,9 @@ namespace Recyclable.Collections
|
||||
itemsSpan = new(items._memoryBlocks[blockIndex], 0, (int)sourceItemsCount);
|
||||
itemsSpan.CopyTo(targetSpan);
|
||||
}
|
||||
else if (blockIndex <= items.LastBlockWithData)
|
||||
else if (blockIndex <= items._lastBlockWithData)
|
||||
{
|
||||
itemsSpan = new(items._memoryBlocks[blockIndex], 0, items.NextItemIndex);
|
||||
itemsSpan = new(items._memoryBlocks[blockIndex], 0, items._nextItemIndex);
|
||||
itemsSpan.CopyTo(targetSpan);
|
||||
}
|
||||
|
||||
@@ -358,7 +358,7 @@ namespace Recyclable.Collections
|
||||
return;
|
||||
}
|
||||
|
||||
if (NeedsClearing)
|
||||
if (_needsClearing)
|
||||
{
|
||||
Array.Clear(_memoryBlock, 0, _count);
|
||||
}
|
||||
@@ -408,7 +408,7 @@ namespace Recyclable.Collections
|
||||
Array.Copy(_memoryBlock, index + 1, _memoryBlock, index, _count - index);
|
||||
}
|
||||
|
||||
if (NeedsClearing)
|
||||
if (_needsClearing)
|
||||
{
|
||||
_memoryBlock[_count] = default;
|
||||
}
|
||||
@@ -435,7 +435,7 @@ namespace Recyclable.Collections
|
||||
Array.Copy(_memoryBlock, index + 1, _memoryBlock, index, _count - index);
|
||||
}
|
||||
|
||||
if (NeedsClearing)
|
||||
if (_needsClearing)
|
||||
{
|
||||
_memoryBlock[_count] = default;
|
||||
}
|
||||
@@ -457,7 +457,7 @@ namespace Recyclable.Collections
|
||||
_version++;
|
||||
if (_count != 0)
|
||||
{
|
||||
if (NeedsClearing)
|
||||
if (_needsClearing)
|
||||
{
|
||||
Array.Clear(_memoryBlock, 0, _count);
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ namespace Recyclable.Collections
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
if (NeedsClearing)
|
||||
if (_needsClearing)
|
||||
{
|
||||
_current = _default;
|
||||
}
|
||||
@@ -78,7 +78,7 @@ namespace Recyclable.Collections
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (NeedsClearing)
|
||||
if (_needsClearing)
|
||||
{
|
||||
_current = _default;
|
||||
}
|
||||
|
||||
@@ -196,7 +196,7 @@ namespace Recyclable.Collections
|
||||
// We can now return the old memory block for all arrays itself
|
||||
if (sourceBlockCount >= RecyclableDefaults.MinPooledArrayLength)
|
||||
{
|
||||
RecyclableArrayPool<T[]>.ReturnShared(list._memoryBlocks!, NeedsClearing);
|
||||
RecyclableArrayPool<T[]>.ReturnShared(list._memoryBlocks!, _needsClearing);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -86,7 +86,7 @@ namespace Recyclable.Collections
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
if (NeedsClearing)
|
||||
if (_needsClearing)
|
||||
{
|
||||
_current = _default;
|
||||
}
|
||||
@@ -97,7 +97,7 @@ namespace Recyclable.Collections
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (NeedsClearing)
|
||||
if (_needsClearing)
|
||||
{
|
||||
_current = _default;
|
||||
}
|
||||
|
||||
@@ -10,23 +10,32 @@ namespace Recyclable.Collections
|
||||
{
|
||||
public partial class RecyclableLongList<T> : IList<T>, IReadOnlyList<T>, IDisposable
|
||||
{
|
||||
#pragma warning disable CA1825
|
||||
private static readonly T[][] _emptyMemoryBlocksArray = new T[0][];
|
||||
private static readonly T[] _emptyBlockArray = new T[0];
|
||||
#pragma warning restore CA1825
|
||||
private static readonly bool _defaultIsNull = default(T) == null;
|
||||
private static readonly bool NeedsClearing = !typeof(T).IsValueType;
|
||||
private static readonly bool _needsClearing = !typeof(T).IsValueType;
|
||||
|
||||
internal int _blockSize;
|
||||
internal byte _blockSizePow2BitShift;
|
||||
internal int _blockSizeMinus1;
|
||||
internal int _nextItemBlockIndex;
|
||||
internal int _nextItemIndex;
|
||||
private int _reservedBlockCount;
|
||||
|
||||
internal long _capacity;
|
||||
internal int _lastBlockWithData = RecyclableDefaults.ItemNotFoundIndex;
|
||||
internal long _longCount;
|
||||
#nullable disable
|
||||
internal T[][] _memoryBlocks;
|
||||
#nullable restore
|
||||
internal int _nextItemBlockIndex;
|
||||
internal int _nextItemIndex;
|
||||
#pragma warning disable IDE0032
|
||||
internal int _reservedBlockCount;
|
||||
#pragma warning restore IDE0032
|
||||
internal ulong _version;
|
||||
|
||||
private long _capacity;
|
||||
public int BlockSize => _blockSize;
|
||||
public int BlockSizeMinus1 => _blockSizeMinus1;
|
||||
public byte BlockSizePow2BitShift => _blockSizePow2BitShift;
|
||||
public long Capacity
|
||||
{
|
||||
get => _capacity;
|
||||
@@ -44,20 +53,11 @@ namespace Recyclable.Collections
|
||||
|
||||
public int Count => checked((int)_longCount);
|
||||
public bool IsReadOnly => false;
|
||||
internal int _lastBlockWithData = RecyclableDefaults.ItemNotFoundIndex;
|
||||
public int LastBlockWithData => _lastBlockWithData;
|
||||
|
||||
internal long _longCount;
|
||||
public long LongCount => _longCount;
|
||||
|
||||
public int ReservedBlockCount => _reservedBlockCount;
|
||||
public int BlockSize => _blockSize;
|
||||
public int BlockSizeMinus1 => _blockSizeMinus1;
|
||||
public byte BlockSizePow2BitShift => _blockSizePow2BitShift;
|
||||
public int NextItemBlockIndex => _nextItemBlockIndex;
|
||||
public int NextItemIndex => _nextItemIndex;
|
||||
|
||||
internal ulong _version;
|
||||
public int ReservedBlockCount => _reservedBlockCount;
|
||||
public ulong Version => _version;
|
||||
|
||||
private void AddRangeEnumerated(IEnumerable<T> source, int growByCount)
|
||||
@@ -74,7 +74,7 @@ namespace Recyclable.Collections
|
||||
long capacity = _capacity;
|
||||
long available = capacity - copied;
|
||||
|
||||
Span<T[]> memoryBlocksSpan = new(_memoryBlocks, 0, ReservedBlockCount);
|
||||
Span<T[]> memoryBlocksSpan = new(_memoryBlocks, 0, _reservedBlockCount);
|
||||
Span<T> blockArraySpan;
|
||||
var memoryBlocksCount = memoryBlocksSpan.Length;
|
||||
while (true)
|
||||
@@ -155,7 +155,7 @@ namespace Recyclable.Collections
|
||||
blockSize = _blockSize;
|
||||
}
|
||||
|
||||
var memoryBlocksCount = ReservedBlockCount;
|
||||
var memoryBlocksCount = _reservedBlockCount;
|
||||
memoryBlocksSpan = new(_memoryBlocks, 0, memoryBlocksCount);
|
||||
blockArraySpan = new(memoryBlocksSpan[targetBlockIdx], 0, blockSize);
|
||||
foreach (var item in source)
|
||||
@@ -440,12 +440,12 @@ namespace Recyclable.Collections
|
||||
|
||||
public void AddRange(RecyclableList<T> items)
|
||||
{
|
||||
if (items.Count == 0)
|
||||
if (items._count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
long targetCapacity = _longCount + items.Count;
|
||||
long targetCapacity = _longCount + items._count;
|
||||
if (_capacity < targetCapacity)
|
||||
{
|
||||
_capacity = Helpers.Resize(this, _blockSize, _blockSizePow2BitShift, checked((long)BitOperations.RoundUpToPowerOf2((ulong)targetCapacity)));
|
||||
@@ -455,7 +455,7 @@ namespace Recyclable.Collections
|
||||
targetBlockIndex = _nextItemBlockIndex,
|
||||
memoryBlockCount = _reservedBlockCount;
|
||||
|
||||
Span<T> itemsSpan = new(items.AsArray, 0, items.Count);
|
||||
Span<T> itemsSpan = new(items._memoryBlock, 0, items._count);
|
||||
Span<T[]> memoryBlocksSpan = new(_memoryBlocks, 0, memoryBlockCount);
|
||||
Span<T> targetBlockArraySpan = new(memoryBlocksSpan[targetBlockIndex], _nextItemIndex, blockSize - _nextItemIndex);
|
||||
while (targetBlockArraySpan.Length <= itemsSpan.Length)
|
||||
@@ -529,12 +529,12 @@ namespace Recyclable.Collections
|
||||
|
||||
public void AddRange(RecyclableLongList<T> items)
|
||||
{
|
||||
if (items.LongCount == 0)
|
||||
if (items._longCount == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
long itemsCount = items.LongCount,
|
||||
long itemsCount = items._longCount,
|
||||
targetCapacity = _longCount + itemsCount;
|
||||
|
||||
if (_capacity < targetCapacity)
|
||||
@@ -698,7 +698,7 @@ namespace Recyclable.Collections
|
||||
{
|
||||
if (items.Count >= RecyclableDefaults.MinPooledArrayLength)
|
||||
{
|
||||
RecyclableArrayPool<T>.ReturnShared(itemsBuffer, NeedsClearing);
|
||||
RecyclableArrayPool<T>.ReturnShared(itemsBuffer, _needsClearing);
|
||||
}
|
||||
|
||||
_version++;
|
||||
@@ -753,7 +753,7 @@ namespace Recyclable.Collections
|
||||
int toRemoveIdx = 0;
|
||||
while (toRemoveIdx < memoryBlocksCount)
|
||||
{
|
||||
RecyclableArrayPool<T>.ReturnShared(memoryBlocks[toRemoveIdx++], NeedsClearing);
|
||||
RecyclableArrayPool<T>.ReturnShared(memoryBlocks[toRemoveIdx++], _needsClearing);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -970,7 +970,7 @@ namespace Recyclable.Collections
|
||||
_lastBlockWithData--;
|
||||
}
|
||||
|
||||
if (NeedsClearing)
|
||||
if (_needsClearing)
|
||||
{
|
||||
#nullable disable
|
||||
new Span<T>(_memoryBlocks[_nextItemBlockIndex])[_nextItemIndex] = default;
|
||||
@@ -988,7 +988,7 @@ namespace Recyclable.Collections
|
||||
{
|
||||
if (_blockSize >= RecyclableDefaults.MinPooledArrayLength)
|
||||
{
|
||||
RecyclableArrayPool<T>.ReturnShared(_memoryBlocks[index], NeedsClearing);
|
||||
RecyclableArrayPool<T>.ReturnShared(_memoryBlocks[index], _needsClearing);
|
||||
_memoryBlocks[index] = _emptyBlockArray;
|
||||
}
|
||||
else
|
||||
@@ -1038,7 +1038,7 @@ namespace Recyclable.Collections
|
||||
_lastBlockWithData--;
|
||||
}
|
||||
|
||||
if (NeedsClearing)
|
||||
if (_needsClearing)
|
||||
{
|
||||
#nullable disable
|
||||
new Span<T>(_memoryBlocks[_nextItemBlockIndex])[_nextItemIndex] = default;
|
||||
@@ -1076,7 +1076,7 @@ namespace Recyclable.Collections
|
||||
_lastBlockWithData--;
|
||||
}
|
||||
|
||||
if (NeedsClearing)
|
||||
if (_needsClearing)
|
||||
{
|
||||
#nullable disable
|
||||
new Span<T>(_memoryBlocks[_nextItemBlockIndex])[_nextItemIndex] = default;
|
||||
|
||||
@@ -144,11 +144,11 @@ namespace Recyclable.Collections
|
||||
try
|
||||
{
|
||||
// Remove in reversed order for performance savings
|
||||
while (Memory.Count > 0)
|
||||
while (Memory._count > 0)
|
||||
{
|
||||
try
|
||||
{
|
||||
RemoveBlock(Memory.Count - 1);
|
||||
RemoveBlock(Memory._count - 1);
|
||||
}
|
||||
#pragma warning disable RCS1075 // We want to try returning as many arrays, as possible, before the list is cleared.
|
||||
catch (Exception)
|
||||
|
||||
@@ -14,7 +14,7 @@ namespace Recyclable.Collections
|
||||
get => List._longCount;
|
||||
set => List._longCount = value;
|
||||
}
|
||||
public bool IsReadOnly => List.IsReadOnly;
|
||||
public bool IsReadOnly => false;
|
||||
|
||||
public T this[int index] { get => this[(long)index]; set => this[(long)index] = value; }
|
||||
public T this[long index] { get => List[index]; set => List[index] = value; }
|
||||
@@ -46,9 +46,9 @@ namespace Recyclable.Collections
|
||||
{
|
||||
var toRemove = List[LongCount - 1];
|
||||
LongCount--;
|
||||
if ((List.Capacity * _blockSize) - LongCount == _blockSize)
|
||||
if ((List._capacity * _blockSize) - LongCount == _blockSize)
|
||||
{
|
||||
List.RemoveBlock(List.ReservedBlockCount - 1);
|
||||
List.RemoveBlock(List._reservedBlockCount - 1);
|
||||
}
|
||||
|
||||
return toRemove;
|
||||
|
||||
@@ -89,7 +89,7 @@ namespace Recyclable.CollectionsTests
|
||||
}
|
||||
|
||||
// Validate
|
||||
_ = list.Capacity.Should().Be(4);
|
||||
_ = list.Capacity.Should().Be(RecyclableDefaults.InitialCapacity);
|
||||
_ = list.Count.Should().Be(0);
|
||||
_ = list.Should().BeEmpty();
|
||||
}
|
||||
@@ -138,7 +138,7 @@ namespace Recyclable.CollectionsTests
|
||||
}
|
||||
|
||||
// Validate
|
||||
var expectedData = testData.Concat(testData).ToRecyclableLongList();
|
||||
using var expectedData = testData.Concat(testData).ToRecyclableLongList();
|
||||
|
||||
if (itemsCount > 0)
|
||||
{
|
||||
|
||||
Reference in new issue
Block a user