Small cleanup

This commit is contained in:
mlemanczyk committed 2023-09-03 14:47:56 +02:00
1 parent f928e1e35e
commit 96968d5452
11 files changed
+63 -64

No files matched your search

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