RecyclableLongListExtensions & ListExtensions cleaned up

This commit is contained in:
mlemanczyk committed 2023-06-17 13:09:19 +02:00
1 parent 45edb9d8fb
commit c5406b04b7
17 files changed
+640 -682

No files matched your search

+13 -2
View File
@@ -93,6 +93,17 @@
1. 🅿️ `Remove`
1. 🅿️ `RemoveAt`
1. 🅿️ `RemoveBlock`
1. 🅿️ Add `.ToRecyclableList` / `.ToRecyclableLongList` variants for all supported collection types
1. 🅿️ `RecyclableList`
1. 🅿️ `RecyclableLongList`
1. 🅿️ `IList<T>`
1. 🅿️ `ICollection<T>`
1. 🅿️ `IEnumerable<T>`
1. 🅿️ `IEnumerable`
1. 🅿️ `IReadOnlyList<T>`
1. 🅿️ `IReadOnlyCollection<T>`
1. 🅿️ `IList`
1. 🅿️ `ICollection`
1. 🅿️ Release 0.0.3-beta
1. 🅿️ Add support for `ulong` indexing
1. 🅿️ Convert `_memoryBlocks` to `Array` to allow `ulong` lengths
@@ -155,8 +166,8 @@
1. 🅿️ `RecyclableLongListExtensions.CopyTo`
1. 🅿️ Cleanup
1. 🅿️ Replace `LastBlockWithData` property with `_lastBlockWithData` field
1. 🅿️ Cleanup `RecyclableLongListExtensions`
1. 🅿️ `ListExtensions`
1. ✅ Cleanup `RecyclableLongListExtensions`
1. ✅ `ListExtensions`
1. 🅿️ `MathUtils`
1. 🅿️ Optimize
1. 🅿️ `ListExtensions`
@@ -775,9 +775,9 @@ namespace Recyclable.Collections.Benchmarks.POC
return lastBlockIndex < memoryBlocksSpan.Length && Array.IndexOf(memoryBlocksSpan[lastBlockIndex], item, 0, _nextItemIndex) >= 0;
}
public void CopyTo(T[] array, int arrayIndex) => _memoryBlocks.CopyTo(0, _blockSize, _longCount, array, arrayIndex);
public void CopyTo(T[] array, int arrayIndex) => RecyclableLongList<T>.RecyclableLongListHelpers.CopyTo(_memoryBlocks, 0, _blockSize, _longCount, array, arrayIndex);
public IEnumerator<T> GetEnumerator() => _memoryBlocks.Enumerate(_blockSize, LongCount).GetEnumerator();
public IEnumerator<T> GetEnumerator() => RecyclableLongList<T>.RecyclableLongListHelpers.Enumerate(_memoryBlocks, _blockSize, LongCount).GetEnumerator();
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public int IndexOf(T item) => _longCount == 0
@@ -847,7 +847,7 @@ namespace Recyclable.Collections.Benchmarks.POC
DoRemoveAt(index);
}
IEnumerator IEnumerable.GetEnumerator() => _memoryBlocks.Enumerate(_blockSize, LongCount).GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => RecyclableLongList<T>.RecyclableLongListHelpers.Enumerate(_memoryBlocks, _blockSize, LongCount).GetEnumerator();
~RecyclableLongListV1()
{
@@ -1675,9 +1675,9 @@ namespace Recyclable.Collections.Benchmarks.POC
return lastBlockIndex < memoryBlocksSpan.Length && Array.IndexOf(memoryBlocksSpan[lastBlockIndex], item, 0, _nextItemIndex) >= 0;
}
public void CopyTo(T[] array, int arrayIndex) => _memoryBlocks.CopyTo(0, _blockSize, _longCount, array, arrayIndex);
public void CopyTo(T[] array, int arrayIndex) => RecyclableLongList<T>.RecyclableLongListHelpers.CopyTo(_memoryBlocks, 0, _blockSize, _longCount, array, arrayIndex);
public IEnumerator<T> GetEnumerator() => _memoryBlocks.Enumerate(_blockSize, LongCount).GetEnumerator();
public IEnumerator<T> GetEnumerator() => RecyclableLongList<T>.RecyclableLongListHelpers.Enumerate(_memoryBlocks, _blockSize, LongCount).GetEnumerator();
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public int IndexOf(T item) => _longCount == 0
@@ -1816,7 +1816,7 @@ namespace Recyclable.Collections.Benchmarks.POC
}
}
IEnumerator IEnumerable.GetEnumerator() => _memoryBlocks.Enumerate(_blockSize, LongCount).GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => RecyclableLongList<T>.RecyclableLongListHelpers.Enumerate(_memoryBlocks, _blockSize, LongCount).GetEnumerator();
~RecyclableLongListV2()
{
@@ -2638,9 +2638,9 @@ namespace Recyclable.Collections.Benchmarks.POC
return lastBlockIndex < memoryBlocksSpan.Length && Array.IndexOf(memoryBlocksSpan[lastBlockIndex], item, 0, _nextItemIndex) >= 0;
}
public void CopyTo(T[] array, int arrayIndex) => _memoryBlocks.CopyTo(0, _blockSize, _longCount, array, arrayIndex);
public void CopyTo(T[] array, int arrayIndex) => RecyclableLongList<T>.RecyclableLongListHelpers.CopyTo(_memoryBlocks, 0, _blockSize, _longCount, array, arrayIndex);
public IEnumerator<T> GetEnumerator() => _memoryBlocks.Enumerate(_blockSize, LongCount).GetEnumerator();
public IEnumerator<T> GetEnumerator() => RecyclableLongList<T>.RecyclableLongListHelpers.Enumerate(_memoryBlocks, _blockSize, LongCount).GetEnumerator();
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public int IndexOf(T item) => _longCount == 0
@@ -2779,7 +2779,7 @@ namespace Recyclable.Collections.Benchmarks.POC
}
}
IEnumerator IEnumerable.GetEnumerator() => _memoryBlocks.Enumerate(_blockSize, LongCount).GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => RecyclableLongList<T>.RecyclableLongListHelpers.Enumerate(_memoryBlocks, _blockSize, LongCount).GetEnumerator();
~RecyclableLongListV3()
{
@@ -1068,9 +1068,9 @@ namespace Recyclable.Collections.Benchmarks.POC
return lastBlockIndex < memoryBlocksSpan.Length && Array.IndexOf(memoryBlocksSpan[lastBlockIndex], item, 0, _nextItemIndex) >= 0;
}
public void CopyTo(T[] array, int arrayIndex) => _memoryBlocks.CopyTo(0, _blockSize, _longCount, array, arrayIndex);
public void CopyTo(T[] array, int arrayIndex) => RecyclableLongList<T>.RecyclableLongListHelpers.CopyTo(_memoryBlocks, 0, _blockSize, _longCount, array, arrayIndex);
public IEnumerator<T> GetEnumerator() => _memoryBlocks.Enumerate(_blockSize, LongCount).GetEnumerator();
public IEnumerator<T> GetEnumerator() => RecyclableLongList<T>.RecyclableLongListHelpers.Enumerate(_memoryBlocks, _blockSize, LongCount).GetEnumerator();
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public int IndexOf(T item) => _longCount == 0
@@ -1217,7 +1217,7 @@ namespace Recyclable.Collections.Benchmarks.POC
}
}
IEnumerator IEnumerable.GetEnumerator() => _memoryBlocks.Enumerate(_blockSize, LongCount).GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => RecyclableLongList<T>.RecyclableLongListHelpers.Enumerate(_memoryBlocks, _blockSize, LongCount).GetEnumerator();
~RecyclableLongListIndexOfV1()
{
@@ -2213,9 +2213,9 @@ namespace Recyclable.Collections.Benchmarks.POC
return lastBlockIndex < memoryBlocksSpan.Length && Array.IndexOf(memoryBlocksSpan[lastBlockIndex], item, 0, _nextItemIndex) >= 0;
}
public void CopyTo(T[] array, int arrayIndex) => _memoryBlocks.CopyTo(0, _blockSize, _longCount, array, arrayIndex);
public void CopyTo(T[] array, int arrayIndex) => RecyclableLongList<T>.RecyclableLongListHelpers.CopyTo(_memoryBlocks, 0, _blockSize, _longCount, array, arrayIndex);
public IEnumerator<T> GetEnumerator() => _memoryBlocks.Enumerate(_blockSize, LongCount).GetEnumerator();
public IEnumerator<T> GetEnumerator() => RecyclableLongList<T>.RecyclableLongListHelpers.Enumerate(_memoryBlocks, _blockSize, LongCount).GetEnumerator();
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public int IndexOf(T item) => _longCount == 0
@@ -2362,7 +2362,7 @@ namespace Recyclable.Collections.Benchmarks.POC
}
}
IEnumerator IEnumerable.GetEnumerator() => _memoryBlocks.Enumerate(_blockSize, LongCount).GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => RecyclableLongList<T>.RecyclableLongListHelpers.Enumerate(_memoryBlocks, _blockSize, LongCount).GetEnumerator();
~RecyclableLongListIndexOfV2()
{
@@ -3330,9 +3330,9 @@ namespace Recyclable.Collections.Benchmarks.POC
return lastBlockIndex < memoryBlocksSpan.Length && Array.IndexOf(memoryBlocksSpan[lastBlockIndex], item, 0, _nextItemIndex) >= 0;
}
public void CopyTo(T[] array, int arrayIndex) => _memoryBlocks.CopyTo(0, _blockSize, _longCount, array, arrayIndex);
public void CopyTo(T[] array, int arrayIndex) => RecyclableLongList<T>.RecyclableLongListHelpers.CopyTo(_memoryBlocks, 0, _blockSize, _longCount, array, arrayIndex);
public IEnumerator<T> GetEnumerator() => _memoryBlocks.Enumerate(_blockSize, LongCount).GetEnumerator();
public IEnumerator<T> GetEnumerator() => RecyclableLongList<T>.RecyclableLongListHelpers.Enumerate(_memoryBlocks, _blockSize, LongCount).GetEnumerator();
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public int IndexOf(T item) => _longCount == 0
@@ -3476,7 +3476,7 @@ namespace Recyclable.Collections.Benchmarks.POC
}
}
IEnumerator IEnumerable.GetEnumerator() => _memoryBlocks.Enumerate(_blockSize, LongCount).GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => RecyclableLongList<T>.RecyclableLongListHelpers.Enumerate(_memoryBlocks, _blockSize, LongCount).GetEnumerator();
~RecyclableLongListIndexOfV3()
{
@@ -4484,9 +4484,9 @@ namespace Recyclable.Collections.Benchmarks.POC
return lastBlockIndex < memoryBlocksSpan.Length && Array.IndexOf(memoryBlocksSpan[lastBlockIndex], item, 0, _nextItemIndex) >= 0;
}
public void CopyTo(T[] array, int arrayIndex) => _memoryBlocks.CopyTo(0, _blockSize, _longCount, array, arrayIndex);
public void CopyTo(T[] array, int arrayIndex) => RecyclableLongList<T>.RecyclableLongListHelpers.CopyTo(_memoryBlocks, 0, _blockSize, _longCount, array, arrayIndex);
public IEnumerator<T> GetEnumerator() => _memoryBlocks.Enumerate(_blockSize, LongCount).GetEnumerator();
public IEnumerator<T> GetEnumerator() => RecyclableLongList<T>.RecyclableLongListHelpers.Enumerate(_memoryBlocks, _blockSize, LongCount).GetEnumerator();
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public int IndexOf(T item) => _longCount == 0
@@ -4630,7 +4630,7 @@ namespace Recyclable.Collections.Benchmarks.POC
}
}
IEnumerator IEnumerable.GetEnumerator() => _memoryBlocks.Enumerate(_blockSize, LongCount).GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => RecyclableLongList<T>.RecyclableLongListHelpers.Enumerate(_memoryBlocks, _blockSize, LongCount).GetEnumerator();
~RecyclableLongListIndexOfV4()
{
-211
View File
@@ -1,211 +0,0 @@
using System.Runtime.CompilerServices;
namespace Recyclable.Collections
{
// The source code was taken from https://codereview.stackexchange.com/questions/205407/quicksort-without-recursion.
// It was only beautified for .Net 6.0+.
internal static class ListExtensions
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool Contains<T>(this RecyclableList<T[]> arrays, T item) => arrays.Any(x => x.Contains(item));
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void CopyTo<T>(this RecyclableList<T[]> arrays, long startingIndex, int blockSize, int lastBlockSize, T[] destinationArray, int destinationArrayIndex)
{
Span<T> arrayMemory = destinationArray.AsSpan();
arrayMemory = arrayMemory[destinationArrayIndex..];
int startingArrayIndex = (int)(startingIndex / blockSize);
startingIndex %= blockSize;
if (arrays.Count > 0)
{
ReadOnlySpan<T> sourceMemory = arrays[0].AsSpan();
var maxToCopy = (int)Math.Min(blockSize - startingIndex, arrayMemory.Length);
if (arrays.Count == 1)
{
maxToCopy = (int)Math.Min(maxToCopy, lastBlockSize);
}
sourceMemory = sourceMemory[(int)startingIndex..maxToCopy];
sourceMemory.CopyTo(arrayMemory);
arrayMemory = arrayMemory[maxToCopy..];
}
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);
sourceMemory = sourceMemory[..maxToCopy];
sourceMemory.CopyTo(arrayMemory);
arrayMemory = arrayMemory[maxToCopy..];
}
if (arrays.Count > 1 && arrayMemory.Length > 0)
{
ReadOnlySpan<T> sourceMemory = arrays[^1].AsSpan();
var maxToCopy = Math.Min(lastBlockSize, arrayMemory.Length);
sourceMemory = sourceMemory[..maxToCopy];
sourceMemory.CopyTo(arrayMemory);
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static IEnumerable<T> Enumerate<T>(this RecyclableList<T[]> arrays, int chunkSize, long totalCount)
{
long currentCount = 0;
for (var arrayIdx = 0; (arrayIdx < arrays.Count) && (currentCount < totalCount); arrayIdx++)
{
var array = arrays[arrayIdx];
currentCount += Math.Min(chunkSize, totalCount);
switch (currentCount < totalCount)
{
case true:
for (var valueIdx = 0; valueIdx < chunkSize; valueIdx++)
{
yield return array[valueIdx];
}
break;
case false:
var partialCount = (int)(totalCount % chunkSize);
int maxCount = partialCount > 0 ? partialCount : chunkSize;
for (var valueIdx = 0; valueIdx < maxCount; valueIdx++)
{
yield return array[valueIdx];
}
break;
}
}
}
public static void InsertionSort<T>(this IList<T> values, int startIndex, int endIndex, IComparer<T> comparer)
{
var left = startIndex;
while (left < endIndex)
{
int right = left;
T? temp = values[++left];
while (right >= startIndex && 0 < comparer.Compare(values[right], temp))
{
values[right + 1] = values[right--];
}
values[right + 1] = temp;
}
}
public static void InsertionSort<T>(this IList<T> values, IComparer<T> comparer)
{
values.InsertionSort(0, values.Count - 1, comparer);
}
public static void InsertionSort<T>(this IList<T> values)
{
values.InsertionSort(Comparer<T>.Default);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static long LongIndexOf<T>(this RecyclableList<T[]> arrays, int blockSize, T item, IEqualityComparer<T> comparer)
{
for (var arrayIdx = 0; arrayIdx < arrays.Count; arrayIdx++)
{
var array = arrays[arrayIdx];
Span<T> arrayMemory = array.AsSpan();
for (int memoryIdx = 0; memoryIdx < arrayMemory.Length; memoryIdx++)
{
if (comparer.Equals(arrayMemory[memoryIdx], item))
{
return (arrayIdx * (long)blockSize) + memoryIdx;
}
}
}
return -1;
}
public static void QuickSort<T>(this IList<T> values, int startIndex, int endIndex, IComparer<T> comparer, IRandomNumberGenerator randomNumberGenerator)
{
var range = (startIndex, endIndex);
var stack = new Stack<(int, int)>();
do
{
startIndex = range.startIndex;
endIndex = range.endIndex;
if (endIndex - startIndex + 1 < 31)
{
values.InsertionSort(startIndex, endIndex, comparer);
continue;
}
var pivot = values.SampleMedian(startIndex, endIndex, comparer, randomNumberGenerator);
var left = startIndex;
var right = endIndex;
while (left <= right)
{
while (0 > comparer.Compare(values[left], pivot))
{
left++;
}
while (0 > comparer.Compare(pivot, values[right]))
{
right--;
}
if (left <= right)
{
values.Swap(left++, right--);
}
}
if (startIndex < right)
{
stack.Push((startIndex, right));
}
if (left < endIndex)
{
stack.Push((left, endIndex));
}
}
while (stack.TryPop(out range));
}
public static void QuickSort<T>(this IList<T> values, IComparer<T> comparer, IRandomNumberGenerator randomNumberGenerator)
=> values.QuickSort(0, values.Count - 1, comparer, randomNumberGenerator);
public static void QuickSort<T>(this IList<T> values)
=> values.QuickSort(Comparer<T>.Default, new SystemRandomNumberGenerator());
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static T SampleMedian<T>(this IList<T> values, int startIndex, int endIndex, IComparer<T> comparer, IRandomNumberGenerator randomNumberGenerator)
{
var left = randomNumberGenerator.NextInt32(startIndex, endIndex);
var middle = randomNumberGenerator.NextInt32(startIndex, endIndex);
var right = randomNumberGenerator.NextInt32(startIndex, endIndex);
if (0 > comparer.Compare(values[right], values[left]))
{
values.Swap(right, left);
}
if (0 > comparer.Compare(values[middle], values[left]))
{
values.Swap(middle, left);
}
if (0 > comparer.Compare(values[right], values[middle]))
{
values.Swap(right, middle);
}
return values[middle];
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void Swap<T>(this IList<T> values, int xIndex, int yIndex)
=> (values[yIndex], values[xIndex]) = (values[xIndex], values[yIndex]);
}
}
@@ -0,0 +1,19 @@
using System.Runtime.CompilerServices;
namespace Recyclable.Collections
{
public static class RecyclableListExtensions
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static RecyclableList<T> ToRecyclableList<T>(this IEnumerable<T> values) => new(values);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static RecyclableList<T> ToRecyclableList<T>(this T[] values) => new(values);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static RecyclableList<T> ToRecyclableList<T>(this List<T> values) => new(values);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static RecyclableList<T> ToRecyclableList<T>(this RecyclableList<T> values) => new(values);
}
}
@@ -0,0 +1,216 @@
using System.Runtime.CompilerServices;
namespace Recyclable.Collections
{
public partial class RecyclableList<T>
{
internal static class RecyclableListHelpers
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool Contains<T>(RecyclableList<T[]> arrays, T item) => arrays.Any(x => x.Contains(item));
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void CopyTo(RecyclableList<T[]> arrays, long startingIndex, int blockSize, int lastBlockSize, T[] destinationArray, int destinationArrayIndex)
{
Span<T> arrayMemory = destinationArray.AsSpan();
arrayMemory = arrayMemory[destinationArrayIndex..];
int startingArrayIndex = (int)(startingIndex / blockSize);
startingIndex %= blockSize;
if (arrays.Count > 0)
{
ReadOnlySpan<T> sourceMemory = arrays[0].AsSpan();
var maxToCopy = (int)Math.Min(blockSize - startingIndex, arrayMemory.Length);
if (arrays.Count == 1)
{
maxToCopy = (int)Math.Min(maxToCopy, lastBlockSize);
}
sourceMemory = sourceMemory[(int)startingIndex..maxToCopy];
sourceMemory.CopyTo(arrayMemory);
arrayMemory = arrayMemory[maxToCopy..];
}
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);
sourceMemory = sourceMemory[..maxToCopy];
sourceMemory.CopyTo(arrayMemory);
arrayMemory = arrayMemory[maxToCopy..];
}
if (arrays.Count > 1 && arrayMemory.Length > 0)
{
ReadOnlySpan<T> sourceMemory = arrays[^1].AsSpan();
var maxToCopy = Math.Min(lastBlockSize, arrayMemory.Length);
sourceMemory = sourceMemory[..maxToCopy];
sourceMemory.CopyTo(arrayMemory);
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
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++)
{
var array = arrays[arrayIdx];
currentCount += Math.Min(chunkSize, totalCount);
switch (currentCount < totalCount)
{
case true:
for (var valueIdx = 0; valueIdx < chunkSize; valueIdx++)
{
yield return array[valueIdx];
}
break;
case false:
var partialCount = (int)(totalCount % chunkSize);
int maxCount = partialCount > 0 ? partialCount : chunkSize;
for (var valueIdx = 0; valueIdx < maxCount; valueIdx++)
{
yield return array[valueIdx];
}
break;
}
}
}
public static void InsertionSort(IList<T> values, int startIndex, int endIndex, IComparer<T> comparer)
{
var left = startIndex;
while (left < endIndex)
{
int right = left;
T? temp = values[++left];
while (right >= startIndex && 0 < comparer.Compare(values[right], temp))
{
values[right + 1] = values[right--];
}
values[right + 1] = temp;
}
}
public static void InsertionSort(IList<T> values, IComparer<T> comparer)
{
InsertionSort(values, 0, values.Count - 1, comparer);
}
public static void InsertionSort(IList<T> values)
{
InsertionSort(values, Comparer<T>.Default);
}
[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++)
{
var array = arrays[arrayIdx];
Span<T> arrayMemory = array.AsSpan();
for (int memoryIdx = 0; memoryIdx < arrayMemory.Length; memoryIdx++)
{
if (comparer.Equals(arrayMemory[memoryIdx], item))
{
return (arrayIdx * (long)blockSize) + memoryIdx;
}
}
}
return -1;
}
// The source code was taken from https://codereview.stackexchange.com/questions/205407/quicksort-without-recursion.
// It was only beautified for .Net 6.0+.
public static void QuickSort(IList<T> values, int startIndex, int endIndex, IComparer<T> comparer, IRandomNumberGenerator randomNumberGenerator)
{
var range = (startIndex, endIndex);
var stack = new Stack<(int, int)>();
do
{
startIndex = range.startIndex;
endIndex = range.endIndex;
if (endIndex - startIndex + 1 < 31)
{
InsertionSort(values, startIndex, endIndex, comparer);
continue;
}
var pivot = SampleMedian(values, startIndex, endIndex, comparer, randomNumberGenerator);
var left = startIndex;
var right = endIndex;
while (left <= right)
{
while (0 > comparer.Compare(values[left], pivot))
{
left++;
}
while (0 > comparer.Compare(pivot, values[right]))
{
right--;
}
if (left <= right)
{
Swap(values, left++, right--);
}
}
if (startIndex < right)
{
stack.Push((startIndex, right));
}
if (left < endIndex)
{
stack.Push((left, endIndex));
}
}
while (stack.TryPop(out range));
}
public static void QuickSort(IList<T> values, IComparer<T> comparer, IRandomNumberGenerator randomNumberGenerator)
=> QuickSort(values, 0, values.Count - 1, comparer, randomNumberGenerator);
public static void QuickSort(IList<T> values)
=> QuickSort(values, Comparer<T>.Default, new SystemRandomNumberGenerator());
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static T SampleMedian(IList<T> values, int startIndex, int endIndex, IComparer<T> comparer, IRandomNumberGenerator randomNumberGenerator)
{
var left = randomNumberGenerator.NextInt32(startIndex, endIndex);
var middle = randomNumberGenerator.NextInt32(startIndex, endIndex);
var right = randomNumberGenerator.NextInt32(startIndex, endIndex);
if (0 > comparer.Compare(values[right], values[left]))
{
Swap(values, right, left);
}
if (0 > comparer.Compare(values[middle], values[left]))
{
Swap(values, middle, left);
}
if (0 > comparer.Compare(values[right], values[middle]))
{
Swap(values, right, middle);
}
return values[middle];
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void Swap(IList<T> values, int xIndex, int yIndex)
=> (values[yIndex], values[xIndex]) = (values[xIndex], values[yIndex]);
}
}
}
@@ -0,0 +1,118 @@
using System.Collections;
namespace Recyclable.Collections
{
public partial class RecyclableList<T> : IList
{
public bool IsFixedSize => false;
public bool IsSynchronized => false;
private object? _syncRoot;
public object SyncRoot
{
get
{
if (_syncRoot == null)
{
_ = Interlocked.CompareExchange(ref _syncRoot, new object(), null);
}
return _syncRoot;
}
}
object? IList.this[int index]
{
get => _memoryBlock[index];
set
{
if (value is T typedValue)
{
new Span<T>(_memoryBlock)[index] = typedValue;
}
else if (value == null && _defaultIsNull)
{
#nullable disable
new Span<T>(_memoryBlock)[index] = default;
#nullable restore
}
else
{
ThrowArgumentOutOfRangeException(nameof(value), $"Argument is invalid. {(value != null ? "List element type is incompatible with the given value" : "Element is null and the list doesn't allow null values.")}");
}
}
}
public int Add(object? value)
{
if (value is T typeValue)
{
Add(typeValue);
return _count - 1;
}
else if (value == null && _defaultIsNull)
{
Add(null);
return _count - 1;
}
else
{
ThrowArgumentOutOfRangeException(nameof(value), $"Argument is invalid. {(value != null ? "List element type is incompatible with the given value" : "Element is null and the list doesn't allow null values.")}");
return RecyclableDefaults.ItemNotFoundIndex;
}
}
public bool Contains(object? value) => value is T typeValue
? Contains(typeValue)
#nullable disable
: value == null && _defaultIsNull && Contains(default);
#nullable restore
public int IndexOf(object? value) => value is T typeValue
? IndexOf(typeValue)
: value == null && _defaultIsNull
#nullable disable
? IndexOf(default)
#nullable restore
: RecyclableDefaults.ItemNotFoundIndex;
public void Insert(int index, object? value)
{
if (value is T typeValue)
{
Insert(index, typeValue);
}
else if (value == null && _defaultIsNull)
{
#nullable disable
Insert(index, default);
#nullable restore
}
else
{
ThrowArgumentOutOfRangeException(nameof(value), $"Argument is invalid. {(value != null ? "List element type is incompatible with the given value" : "Element is null and the list doesn't allow null values.")}");
}
}
public void Remove(object? value)
{
if (value is T typeValue)
{
_ = Remove(typeValue);
}
else if (value == null && _defaultIsNull)
{
#nullable disable
_ = Remove(default);
#nullable restore
}
else
{
ThrowArgumentOutOfRangeException(nameof(value), $"Argument is invalid. {(value != null ? "List element type is incompatible with the given value" : "Element is null and the list doesn't allow null values.")}");
}
}
public void CopyTo(Array array, int index) => Array.Copy(_memoryBlock, 0, array, index, _count);
}
}
+6 -117
View File
@@ -4,7 +4,7 @@ using System.Runtime.CompilerServices;
namespace Recyclable.Collections
{
public class RecyclableList<T> : IList<T>, IReadOnlyList<T>, IList, IDisposable
public partial class RecyclableList<T> : IList<T>, IReadOnlyList<T>, IDisposable
{
private static readonly ArrayPool<T> _arrayPool = ArrayPool<T>.Create();
private static readonly bool _defaultIsNull = default(T) == null;
@@ -517,124 +517,13 @@ namespace Recyclable.Collections
{
Clear();
_capacity = 0;
_memoryBlock.ReturnToPool(_arrayPool, NeedsClearing);
if (_count is >= RecyclableDefaults.MinPooledArrayLength)
{
_arrayPool.Return(_memoryBlock, NeedsClearing);
}
GC.SuppressFinalize(this);
}
}
#region IList implementation
public bool IsFixedSize => false;
public bool IsSynchronized => false;
private object? _syncRoot;
public object SyncRoot
{
get
{
if (_syncRoot == null)
{
_ = Interlocked.CompareExchange(ref _syncRoot, new object(), null);
}
return _syncRoot;
}
}
object? IList.this[int index]
{
get => _memoryBlock[index];
set
{
if (value is T typedValue)
{
new Span<T>(_memoryBlock)[index] = typedValue;
}
else if (value == null && _defaultIsNull)
{
#nullable disable
new Span<T>(_memoryBlock)[index] = default;
#nullable restore
}
else
{
ThrowArgumentOutOfRangeException(nameof(value), $"Argument is invalid. {(value != null ? "List element type is incompatible with the given value" : "Element is null and the list doesn't allow null values.")}");
}
}
}
public int Add(object? value)
{
if (value is T typeValue)
{
Add(typeValue);
return _count - 1;
}
else if (value == null && _defaultIsNull)
{
Add(null);
return _count - 1;
}
else
{
ThrowArgumentOutOfRangeException(nameof(value), $"Argument is invalid. {(value != null ? "List element type is incompatible with the given value" : "Element is null and the list doesn't allow null values.")}");
return RecyclableDefaults.ItemNotFoundIndex;
}
}
public bool Contains(object? value) => value is T typeValue
? Contains(typeValue)
#nullable disable
: value == null && _defaultIsNull && Contains(default);
#nullable restore
public int IndexOf(object? value) => value is T typeValue
? IndexOf(typeValue)
: value == null && _defaultIsNull
#nullable disable
? IndexOf(default)
#nullable restore
: RecyclableDefaults.ItemNotFoundIndex;
public void Insert(int index, object? value)
{
if (value is T typeValue)
{
Insert(index, typeValue);
}
else if (value == null && _defaultIsNull)
{
#nullable disable
Insert(index, default);
#nullable restore
}
else
{
ThrowArgumentOutOfRangeException(nameof(value), $"Argument is invalid. {(value != null ? "List element type is incompatible with the given value" : "Element is null and the list doesn't allow null values.")}");
}
}
public void Remove(object? value)
{
if (value is T typeValue)
{
_ = Remove( typeValue);
}
else if (value == null && _defaultIsNull)
{
#nullable disable
_ = Remove(default);
#nullable restore
}
else
{
ThrowArgumentOutOfRangeException(nameof(value), $"Argument is invalid. {(value != null ? "List element type is incompatible with the given value" : "Element is null and the list doesn't allow null values.")}");
}
}
public void CopyTo(Array array, int index) => Array.Copy(_memoryBlock, 0, array, index, _count);
#endregion
}
}
@@ -0,0 +1,16 @@
using System.Runtime.CompilerServices;
namespace Recyclable.Collections
{
public static class RecyclableLongListExtensions
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static RecyclableLongList<T> ToRecyclableLongList<T>(this IList<T> values, int blockSize = RecyclableDefaults.BlockSize) => new(values, blockSize);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static RecyclableLongList<T> ToRecyclableLongList<T>(this List<T> values, int blockSize = RecyclableDefaults.BlockSize) => new(values, blockSize);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static RecyclableLongList<T> ToRecyclableLongList<T>(this IEnumerable<T> values, int minBlockSize = RecyclableDefaults.BlockSize) => new(values, minBlockSize: minBlockSize);
}
}
@@ -0,0 +1,90 @@
namespace Recyclable.Collections
{
public partial class RecyclableLongList<T>
{
internal class RecyclableLongListHelpers
{
public static void CopyTo(T[][] sourceMemoryBlocks, long startingIndex, int blockSize, long itemsCount, T[] destinationArray, int destinationArrayIndex)
{
if (itemsCount <= 0)
{
return;
}
Span<T> sourceBlockMemory;
Span<T> destinationArrayMemory;
int startingBlockIndex = (int)(startingIndex / blockSize);
int lastBlockIndex = (int)((itemsCount / blockSize) + (itemsCount % blockSize > 0 ? 1 : 0)) - 1;
Span<T[]> sourceMemoryBlocksSpan = new(sourceMemoryBlocks, startingBlockIndex, lastBlockIndex + 1);
destinationArrayMemory = new Span<T>(destinationArray, destinationArrayIndex, (int)Math.Min(destinationArray.Length - destinationArrayIndex, itemsCount));
int memoryBlockIndex;
for (memoryBlockIndex = 0; memoryBlockIndex < lastBlockIndex; memoryBlockIndex++)
{
sourceBlockMemory = new(sourceMemoryBlocksSpan[memoryBlockIndex], 0, blockSize);
sourceBlockMemory.CopyTo(destinationArrayMemory);
destinationArrayMemory = destinationArrayMemory[blockSize..];
}
if (itemsCount - (lastBlockIndex * blockSize) > 0)
{
sourceBlockMemory = new(sourceMemoryBlocksSpan[lastBlockIndex], 0, (int)(itemsCount - (lastBlockIndex * blockSize)));
sourceBlockMemory.CopyTo(destinationArrayMemory);
}
}
public static void CopyTo(T[][] sourceMemoryBlocks, long startingIndex, int blockSize, long itemsCount, Array destinationArray, int destinationArrayIndex)
{
if (itemsCount <= 0)
{
return;
}
int startingBlockIndex = (int)(startingIndex / blockSize);
int lastBlockIndex = (int)((itemsCount / blockSize) + (itemsCount % blockSize > 0 ? 1 : 0)) - 1;
var destinationIndex = destinationArrayIndex;
Span<T[]> sourceMemoryBlocksSpan = new(sourceMemoryBlocks, startingBlockIndex, lastBlockIndex + 1);
for (int memoryBlockIndex = 0; memoryBlockIndex < lastBlockIndex; memoryBlockIndex++)
{
Array.ConstrainedCopy(sourceMemoryBlocksSpan[memoryBlockIndex], 0, destinationArray, destinationIndex, blockSize);
destinationIndex += blockSize;
}
if (itemsCount - destinationIndex > 0)
{
Array.ConstrainedCopy(sourceMemoryBlocksSpan[lastBlockIndex], 0, destinationArray, destinationIndex, (int)(itemsCount - destinationIndex));
}
}
public static IEnumerable<T> Enumerate(T[][] arrays, int chunkSize, long totalCount)
{
long currentCount = 0;
for (var arrayIdx = 0; arrayIdx < arrays.Length && currentCount < totalCount; arrayIdx++)
{
var array = arrays[arrayIdx];
currentCount += chunkSize;
switch (currentCount < totalCount)
{
case true:
for (var valueIdx = 0; valueIdx < chunkSize; valueIdx++)
{
yield return array[valueIdx];
}
break;
case false:
var partialCount = (int)(totalCount % chunkSize);
int maxCount = partialCount > 0 ? partialCount : chunkSize;
for (var valueIdx = 0; valueIdx < maxCount; valueIdx++)
{
yield return array[valueIdx];
}
break;
}
}
}
}
}
}
@@ -0,0 +1,118 @@
using System.Collections;
namespace Recyclable.Collections
{
public partial class RecyclableLongList<T> : IList
{
public bool IsFixedSize => false;
public bool IsSynchronized => false;
private object? _syncRoot;
public object SyncRoot
{
get
{
if (_syncRoot == null)
{
_ = Interlocked.CompareExchange(ref _syncRoot, new object(), null);
}
return _syncRoot;
}
}
object? IList.this[int index]
{
get => _memoryBlocks[index >> _blockSizePow2BitShift][index & _blockSizeMinus1];
set
{
if (value is T typedValue)
{
new Span<T>(_memoryBlocks[index >> _blockSizePow2BitShift])[index & _blockSizeMinus1] = typedValue;
}
else if (value == null && _defaultIsNull)
{
#nullable disable
new Span<T>(_memoryBlocks[index >> _blockSizePow2BitShift])[index & _blockSizeMinus1] = default;
#nullable restore
}
else
{
ThrowArgumentOutOfRangeException(nameof(value), $"Argument is invalid. {(value != null ? "List element type is incompatible with the given value" : "Element is null and the list doesn't allow null values.")}");
}
}
}
public int Add(object? value)
{
if (value is T typeValue)
{
Add(typeValue);
return (int)(_longCount - 1);
}
else if (value == null && _defaultIsNull)
{
Add(null);
return (int)(_longCount - 1);
}
else
{
ThrowArgumentOutOfRangeException(nameof(value), $"Argument is invalid. {(value != null ? "List element type is incompatible with the given value" : "Element is null and the list doesn't allow null values.")}");
return RecyclableDefaults.ItemNotFoundIndex;
}
}
public bool Contains(object? value) => value is T typeValue
? Contains(typeValue)
#nullable disable
: value == null && _defaultIsNull && Contains(default);
#nullable restore
public int IndexOf(object? value) => value is T typeValue
? IndexOf(typeValue)
: value == null && _defaultIsNull
#nullable disable
? IndexOf(default)
#nullable restore
: RecyclableDefaults.ItemNotFoundIndex;
public void Insert(int index, object? value)
{
if (value is T typeValue)
{
Insert(index, typeValue);
}
else if (value == null && _defaultIsNull)
{
#nullable disable
Insert(index, default);
#nullable restore
}
else
{
ThrowArgumentOutOfRangeException(nameof(value), $"Argument is invalid. {(value != null ? "List element type is incompatible with the given value" : "Element is null and the list doesn't allow null values.")}");
}
}
public void Remove(object? value)
{
if (value is T typeValue)
{
_ = Remove(typeValue);
}
else if (value == null && _defaultIsNull)
{
#nullable disable
_ = Remove(default);
#nullable restore
}
else
{
ThrowArgumentOutOfRangeException(nameof(value), $"Argument is invalid. {(value != null ? "List element type is incompatible with the given value" : "Element is null and the list doesn't allow null values.")}");
}
}
public void CopyTo(Array array, int index) => RecyclableLongList<T>.RecyclableLongListHelpers.CopyTo(_memoryBlocks, 0, _blockSize, _longCount, array, index);
}
}
+4 -119
View File
@@ -9,7 +9,7 @@ using Recyclable.Collections.Pools;
namespace Recyclable.Collections
{
public partial class RecyclableLongList<T> : IList<T>, IReadOnlyList<T>, IList, IDisposable
public partial class RecyclableLongList<T> : IList<T>, IReadOnlyList<T>, IDisposable
{
private static readonly ArrayPool<T[]> _defaultMemoryBlocksPool = ArrayPool<T[]>.Create();
private static readonly ArrayPool<T> _defaultBlockArrayPool = ArrayPool<T>.Create();
@@ -1073,9 +1073,9 @@ namespace Recyclable.Collections
return Array.IndexOf(memoryBlocksSpan[lastBlockIndex], item, 0, _nextItemIndex > 0 ? _nextItemIndex : _blockSize) >= 0;
}
public void CopyTo(T[] array, int arrayIndex) => _memoryBlocks.CopyTo(0, _blockSize, _longCount, array, arrayIndex);
public void CopyTo(T[] array, int arrayIndex) => RecyclableLongList<T>.RecyclableLongListHelpers.CopyTo(_memoryBlocks, 0, _blockSize, _longCount, array, arrayIndex);
public IEnumerator<T> GetEnumerator() => _memoryBlocks.Enumerate(_blockSize, LongCount).GetEnumerator();
public IEnumerator<T> GetEnumerator() => RecyclableLongList<T>.RecyclableLongListHelpers.Enumerate(_memoryBlocks, _blockSize, LongCount).GetEnumerator();
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
public int IndexOf(T item)
@@ -1296,7 +1296,7 @@ namespace Recyclable.Collections
}
}
IEnumerator IEnumerable.GetEnumerator() => _memoryBlocks.Enumerate(_blockSize, LongCount).GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => RecyclableLongList<T>.RecyclableLongListHelpers.Enumerate(_memoryBlocks, _blockSize, LongCount).GetEnumerator();
~RecyclableLongList()
{
@@ -1318,120 +1318,5 @@ namespace Recyclable.Collections
GC.SuppressFinalize(this);
}
}
#region IList implementation
public bool IsFixedSize => false;
public bool IsSynchronized => false;
private object? _syncRoot;
public object SyncRoot
{
get
{
if (_syncRoot == null)
{
_ = Interlocked.CompareExchange(ref _syncRoot, new object(), null);
}
return _syncRoot;
}
}
object? IList.this[int index]
{
get => _memoryBlocks[index >> _blockSizePow2BitShift][index & _blockSizeMinus1];
set
{
if (value is T typedValue)
{
new Span<T>(_memoryBlocks[index >> _blockSizePow2BitShift])[index & _blockSizeMinus1] = typedValue;
}
else if (value == null && _defaultIsNull)
{
#nullable disable
new Span<T>(_memoryBlocks[index >> _blockSizePow2BitShift])[index & _blockSizeMinus1] = default;
#nullable restore
}
else
{
ThrowArgumentOutOfRangeException(nameof(value), $"Argument is invalid. {(value != null ? "List element type is incompatible with the given value" : "Element is null and the list doesn't allow null values.")}");
}
}
}
public int Add(object? value)
{
if (value is T typeValue)
{
Add(typeValue);
return (int)(_longCount - 1);
}
else if (value == null && _defaultIsNull)
{
Add(null);
return (int)(_longCount - 1);
}
else
{
ThrowArgumentOutOfRangeException(nameof(value), $"Argument is invalid. { (value != null ? "List element type is incompatible with the given value" : "Element is null and the list doesn't allow null values.") }");
return RecyclableDefaults.ItemNotFoundIndex;
}
}
public bool Contains(object? value) => value is T typeValue
? Contains(typeValue)
#nullable disable
: value == null && _defaultIsNull && Contains(default);
#nullable restore
public int IndexOf(object? value) => value is T typeValue
? IndexOf(typeValue)
: value == null && _defaultIsNull
#nullable disable
? IndexOf(default)
#nullable restore
: RecyclableDefaults.ItemNotFoundIndex;
public void Insert(int index, object? value)
{
if (value is T typeValue)
{
Insert(index, typeValue);
}
else if (value == null && _defaultIsNull)
{
#nullable disable
Insert(index, default);
#nullable restore
}
else
{
ThrowArgumentOutOfRangeException(nameof(value), $"Argument is invalid. {(value != null ? "List element type is incompatible with the given value" : "Element is null and the list doesn't allow null values.")}");
}
}
public void Remove(object? value)
{
if (value is T typeValue)
{
_ = Remove(typeValue);
}
else if (value == null && _defaultIsNull)
{
#nullable disable
_ = Remove(default);
#nullable restore
}
else
{
ThrowArgumentOutOfRangeException(nameof(value), $"Argument is invalid. {(value != null ? "List element type is incompatible with the given value" : "Element is null and the list doesn't allow null values.")}");
}
}
public void CopyTo(Array array, int index) => _memoryBlocks.CopyTo(0, _blockSize, _longCount, array, index);
#endregion
}
}
@@ -1,200 +0,0 @@
using System.Buffers;
using System.Runtime.CompilerServices;
namespace Recyclable.Collections
{
internal static class RecyclableLongListExtensions
{
private const int _minPooledArraySize = RecyclableDefaults.MinPooledArrayLength;
public static void CopyTo<T>(this T[][] sourceMemoryBlocks, long startingIndex, int blockSize, long itemsCount, T[] destinationArray, int destinationArrayIndex)
{
if (itemsCount <= 0)
{
return;
}
Span<T> sourceBlockMemory;
Span<T> destinationArrayMemory;
int startingBlockIndex = (int)(startingIndex / blockSize);
int lastBlockIndex = (int)((itemsCount / blockSize) + (itemsCount % blockSize > 0 ? 1 : 0)) - 1;
Span<T[]> sourceMemoryBlocksSpan = new(sourceMemoryBlocks, startingBlockIndex, lastBlockIndex + 1);
destinationArrayMemory = new Span<T>(destinationArray, destinationArrayIndex, (int)Math.Min(destinationArray.Length - destinationArrayIndex, itemsCount));
int memoryBlockIndex;
for (memoryBlockIndex = 0; memoryBlockIndex < lastBlockIndex; memoryBlockIndex++)
{
sourceBlockMemory = new(sourceMemoryBlocksSpan[memoryBlockIndex], 0, blockSize);
sourceBlockMemory.CopyTo(destinationArrayMemory);
destinationArrayMemory = destinationArrayMemory[blockSize..];
}
if (itemsCount - (lastBlockIndex * blockSize) > 0)
{
sourceBlockMemory = new(sourceMemoryBlocksSpan[lastBlockIndex], 0, (int)(itemsCount - (lastBlockIndex * blockSize)));
sourceBlockMemory.CopyTo(destinationArrayMemory);
}
}
public static void CopyTo<T>(this T[][] sourceMemoryBlocks, long startingIndex, int blockSize, long itemsCount, Array destinationArray, int destinationArrayIndex)
{
if (itemsCount <= 0)
{
return;
}
int startingBlockIndex = (int)(startingIndex / blockSize);
int lastBlockIndex = (int)((itemsCount / blockSize) + (itemsCount % blockSize > 0 ? 1 : 0)) - 1;
var destinationIndex = destinationArrayIndex;
Span<T[]> sourceMemoryBlocksSpan = new(sourceMemoryBlocks, startingBlockIndex, lastBlockIndex + 1);
for (int memoryBlockIndex = 0; memoryBlockIndex < lastBlockIndex; memoryBlockIndex++)
{
Array.ConstrainedCopy(sourceMemoryBlocksSpan[memoryBlockIndex], 0, destinationArray, destinationIndex, blockSize);
destinationIndex += blockSize;
}
if (itemsCount - destinationIndex > 0)
{
Array.ConstrainedCopy(sourceMemoryBlocksSpan[lastBlockIndex], 0, destinationArray, destinationIndex, (int)(itemsCount - destinationIndex));
}
}
//[MethodImpl(MethodImplOptions.AggressiveInlining)]
//public static bool Contains<T>(this RecyclableLongList<T[]> arrays, T item) => arrays.Any(x => x.Contains(item));
public static IEnumerable<T> Enumerate<T>(this T[][] arrays, int chunkSize, long totalCount)
{
long currentCount = 0;
for (var arrayIdx = 0; arrayIdx < arrays.Length && currentCount < totalCount; arrayIdx++)
{
var array = arrays[arrayIdx];
currentCount += chunkSize;
switch (currentCount < totalCount)
{
case true:
for (var valueIdx = 0; valueIdx < chunkSize; valueIdx++)
{
yield return array[valueIdx];
}
break;
case false:
var partialCount = (int)(totalCount % chunkSize);
int maxCount = partialCount > 0 ? partialCount : chunkSize;
for (var valueIdx = 0; valueIdx < maxCount; valueIdx++)
{
yield return array[valueIdx];
}
break;
}
}
}
//[MethodImpl(MethodImplOptions.AggressiveInlining)]
//public static T LimitTo<T>(this T value, T maxValue, IComparer<T> comparer)
// => comparer.Compare(value, maxValue) > 0 ? maxValue : value;
//[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static long LongIndexOf<T>(this RecyclableLongList<T> arrays, long itemsCount, T itemToFind, IEqualityComparer<T> comparer)
{
for (var itemIdx = 0L; itemIdx < itemsCount; itemIdx++)
{
var item = arrays[itemIdx];
if (comparer.Equals(itemToFind, item))
{
return itemIdx;
}
itemIdx++;
}
return -1;
}
public static long LongIndexOf<T>(this T[][] arrays, long itemsCount, T itemToFind, IEqualityComparer<T> comparer)
{
var arraysSpan = new Span<T[]>(arrays);
var arraysCount = arraysSpan.Length;
for (int arrayIdx = 0, scannedCount = 0; arrayIdx < arraysCount; arrayIdx++)
{
var itemsSpan = new Span<T>(arraysSpan[arrayIdx]);
var arrayItemsCount = itemsSpan.Length;
for (var itemIdx = 0; itemIdx < arrayItemsCount; itemIdx++)
{
if (comparer.Equals(itemToFind, itemsSpan[itemIdx]))
{
return scannedCount;
}
scannedCount++;
if (scannedCount == itemsCount)
{
return -1;
}
}
}
return -1;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static RecyclableLongList<T> ToRecyclableLongList<T>(this IList<T> values, int blockSize = RecyclableDefaults.BlockSize) => new(values, blockSize);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static RecyclableLongList<T> ToRecyclableLongList<T>(this List<T> values, int blockSize = RecyclableDefaults.BlockSize) => new(values, blockSize);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static RecyclableList<T> ToRecyclableList<T>(this IEnumerable<T> values) => new(values);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static RecyclableList<T> ToRecyclableList<T>(this T[] values) => new(values);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static RecyclableList<T> ToRecyclableList<T>(this List<T> values) => new(values);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static RecyclableList<T> ToRecyclableList<T>(this RecyclableList<T> values) => new(values);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static RecyclableLongList<T> ToRecyclableLongList<T>(this IEnumerable<T> values, int minBlockSize = RecyclableDefaults.BlockSize) => new(values, minBlockSize: minBlockSize);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static T[] RentArrayFromPool<T>(this int minSize, ArrayPool<T> arrayPool) => (minSize >= _minPooledArraySize)
? arrayPool.Rent(minSize)
: new T[minSize];
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static T[] RentArrayFromPool<T>(this long minSize, ArrayPool<T> arrayPool) => (minSize is >= _minPooledArraySize and <= int.MaxValue)
? arrayPool.Rent((int)minSize)
: new T[minSize];
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void ReturnToPool<T>(this T[] array, ArrayPool<T> arrayPool, bool needsClearing)
{
if (array.LongLength is > _minPooledArraySize and <= int.MaxValue)
{
arrayPool.Return(array, needsClearing);
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static long LimitTo(this long value, int limit)
=> (value <= limit) ? value : limit;
public static int IndexOf<T>(this T[] memory, int itemCount, T? itemToFind, IEqualityComparer<T> equalityComparer)
{
for (var itemIdx = 0; itemIdx < itemCount; itemIdx++)
{
var item = memory[itemIdx];
if (equalityComparer.Equals(item, itemToFind))
{
return itemIdx;
}
}
return -1;
}
}
}
+16 -9
View File
@@ -133,7 +133,10 @@ namespace Recyclable.Collections
public void AddBlock()
{
T[] newArray = BlockSize.RentArrayFromPool<T>(_arrayPool);
T[] newArray = (BlockSize >= RecyclableDefaults.MinPooledArrayLength)
? _arrayPool.Rent(BlockSize)
: new T[BlockSize];
Memory.Add(newArray);
Capacity += BlockSize;
}
@@ -168,13 +171,13 @@ namespace Recyclable.Collections
}
}
public bool Contains(T item) => Memory.Contains(item);
public void CopyTo(T[] array, int arrayIndex) => Memory.CopyTo(RemovedCount, BlockSize, (int)(LongCount % BlockSize), array, arrayIndex);
public IEnumerable<T> Enumerate() => Memory.Enumerate(BlockSize, LongCount);
public IEnumerator<T> GetEnumerator() => Memory.Enumerate(BlockSize, LongCount).GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => Memory.Enumerate(BlockSize, LongCount).GetEnumerator();
public int IndexOf(T item) => (int)LongIndexOf(item);
public long LongIndexOf(T item) => GetRelativeIndex(Memory.LongIndexOf(BlockSize, item, _equalityComparer));
public bool Contains(T item) => RecyclableList<T>.RecyclableListHelpers.Contains(Memory, item);
public void CopyTo(T[] array, int arrayIndex) => RecyclableList<T>.RecyclableListHelpers.CopyTo(Memory, RemovedCount, BlockSize, (int)(LongCount % BlockSize), array, arrayIndex);
public IEnumerable<T> Enumerate() => RecyclableList<T>.RecyclableListHelpers.Enumerate(Memory, BlockSize, LongCount);
public IEnumerator<T> GetEnumerator() => RecyclableList<T>.RecyclableListHelpers.Enumerate(Memory, BlockSize, LongCount).GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => RecyclableList<T>.RecyclableListHelpers.Enumerate(Memory, BlockSize, LongCount).GetEnumerator();
public int IndexOf(T item) => (int)GetRelativeIndex(RecyclableList<T>.RecyclableListHelpers.LongIndexOf(Memory, BlockSize, item, _equalityComparer));
public long LongIndexOf(T item) => GetRelativeIndex(RecyclableList<T>.RecyclableListHelpers.LongIndexOf(Memory, BlockSize, item, _equalityComparer));
public void Insert(int index, T item) => throw new NotSupportedException();
public void RemoveAt(int index) => throw new NotSupportedException();
public bool TryDequeue(out T? item) => TryDequeue(this, out item);
@@ -183,7 +186,11 @@ namespace Recyclable.Collections
{
try
{
Memory[index].ReturnToPool(_arrayPool, NeedsClearing);
if (Memory[index].LongLength is > RecyclableDefaults.MinPooledArrayLength and <= int.MaxValue)
{
_arrayPool.Return(Memory[index], NeedsClearing);
}
Memory.RemoveAt(index);
}
finally
@@ -68,7 +68,7 @@
BeginUpdate();
try
{
this.QuickSort(_comparer, _randomNumberGenerator);
RecyclableList<(TKey Key, TValue Value)>.RecyclableListHelpers.QuickSort(this, _comparer, _randomNumberGenerator);
}
finally
{
@@ -419,7 +419,7 @@ namespace Recyclable.CollectionsTests
// Act
using RecyclableList<long> list = new(testData);
list.QuickSort();
RecyclableList<long>.RecyclableListHelpers.QuickSort(list);
// Validate
_ = list.Count.Should().Be((int)itemsCount);
@@ -461,7 +461,7 @@ namespace Recyclable.CollectionsTests
// Act
using RecyclableLongList<long> list = new(testData, minBlockSize: targetBlockSize);
list.QuickSort();
RecyclableList<long>.RecyclableListHelpers.QuickSort(list);
// Validate
_ = list.LongCount.Should().Be(itemsCount);