RecyclableList<T>.Helpers renamed to RecyclableListHelpers and made top-level class for better performance.
This commit is contained in:
1 parent
db8b0602c0
commit
11fd6e3dd0
6 files changed
+235
-238
No files matched your search
@@ -3,271 +3,269 @@ using System.Runtime.CompilerServices;
|
|||||||
|
|
||||||
namespace Recyclable.Collections
|
namespace Recyclable.Collections
|
||||||
{
|
{
|
||||||
public partial class RecyclableList<T>
|
internal static class RecyclableListHelpers<T>
|
||||||
{
|
{
|
||||||
internal static class Helpers
|
[Obsolete("This method MAY be removed in the near future.")]
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static bool Contains(RecyclableList<T[]> arrays, T item) => arrays.Any(x => x.Contains(item));
|
||||||
|
|
||||||
|
[Obsolete("This method MAY be removed in the near future.")]
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void CopyTo(RecyclableList<T[]> arrays, long startingIndex, int blockSize, int lastBlockSize, T[] destinationArray, int destinationArrayIndex)
|
||||||
{
|
{
|
||||||
[Obsolete("This method MAY be removed in the near future.")]
|
Span<T> arrayMemory = destinationArray.AsSpan();
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
arrayMemory = arrayMemory[destinationArrayIndex..];
|
||||||
public static bool Contains(RecyclableList<T[]> arrays, T item) => arrays.Any(x => x.Contains(item));
|
int startingArrayIndex = (int)(startingIndex / blockSize);
|
||||||
|
startingIndex %= blockSize;
|
||||||
[Obsolete("This method MAY be removed in the near future.")]
|
if (arrays.Count > 0)
|
||||||
[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();
|
ReadOnlySpan<T> sourceMemory = arrays[0].AsSpan();
|
||||||
arrayMemory = arrayMemory[destinationArrayIndex..];
|
var maxToCopy = (int)Math.Min(blockSize - startingIndex, arrayMemory.Length);
|
||||||
int startingArrayIndex = (int)(startingIndex / blockSize);
|
if (arrays.Count == 1)
|
||||||
startingIndex %= blockSize;
|
|
||||||
if (arrays.Count > 0)
|
|
||||||
{
|
{
|
||||||
ReadOnlySpan<T> sourceMemory = arrays[0].AsSpan();
|
maxToCopy = Math.Min(maxToCopy, lastBlockSize);
|
||||||
var maxToCopy = (int)Math.Min(blockSize - startingIndex, arrayMemory.Length);
|
|
||||||
if (arrays.Count == 1)
|
|
||||||
{
|
|
||||||
maxToCopy = 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++)
|
sourceMemory = sourceMemory[(int)startingIndex..maxToCopy];
|
||||||
{
|
sourceMemory.CopyTo(arrayMemory);
|
||||||
ReadOnlySpan<T> sourceMemory = arrays[arrayIdx].AsSpan();
|
arrayMemory = arrayMemory[maxToCopy..];
|
||||||
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 | MethodImplOptions.AggressiveOptimization)]
|
for (var arrayIdx = startingArrayIndex + 1; arrayIdx < arrays.Count - 1 && arrayMemory.Length > 0; arrayIdx++)
|
||||||
public static int EnsureCapacity(RecyclableList<T> list, int requestedCapacity)
|
|
||||||
{
|
{
|
||||||
int newCapacity;
|
ReadOnlySpan<T> sourceMemory = arrays[arrayIdx].AsSpan();
|
||||||
switch (list._capacity > 0)
|
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 | MethodImplOptions.AggressiveOptimization)]
|
||||||
|
public static int EnsureCapacity(RecyclableList<T> list, int requestedCapacity)
|
||||||
|
{
|
||||||
|
int newCapacity;
|
||||||
|
switch (list._capacity > 0)
|
||||||
|
{
|
||||||
|
case true:
|
||||||
|
newCapacity = list._capacity;
|
||||||
|
while (newCapacity < requestedCapacity)
|
||||||
|
{
|
||||||
|
newCapacity <<= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case false:
|
||||||
|
newCapacity = requestedCapacity;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
list._memoryBlock = Resize(list._memoryBlock, newCapacity);
|
||||||
|
newCapacity = list._memoryBlock.Length;
|
||||||
|
list._capacity = newCapacity;
|
||||||
|
return newCapacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[Obsolete("This method WILL be removed in the near future. Please use the existing enumerators instead of it.")]
|
||||||
|
[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:
|
case true:
|
||||||
newCapacity = list._capacity;
|
for (var valueIdx = 0; valueIdx < chunkSize; valueIdx++)
|
||||||
while (newCapacity < requestedCapacity)
|
|
||||||
{
|
{
|
||||||
newCapacity <<= 1;
|
yield return array[valueIdx];
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case false:
|
case false:
|
||||||
newCapacity = requestedCapacity;
|
var partialCount = (int)(totalCount % chunkSize);
|
||||||
|
int maxCount = partialCount > 0 ? partialCount : chunkSize;
|
||||||
|
for (var valueIdx = 0; valueIdx < maxCount; valueIdx++)
|
||||||
|
{
|
||||||
|
yield return array[valueIdx];
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
list._memoryBlock = Resize(list._memoryBlock, newCapacity);
|
|
||||||
newCapacity = list._memoryBlock.Length;
|
|
||||||
list._capacity = newCapacity;
|
|
||||||
return newCapacity;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[Obsolete("This method WILL be removed in the near future. Please use the existing enumerators instead of it.")]
|
public static void InsertionSort(IList<T> values, int startIndex, int endIndex, IComparer<T> comparer)
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
{
|
||||||
public static IEnumerable<T> Enumerate(RecyclableList<T[]> arrays, int chunkSize, long totalCount)
|
var left = startIndex;
|
||||||
|
while (left < endIndex)
|
||||||
{
|
{
|
||||||
long currentCount = 0;
|
int right = left;
|
||||||
for (var arrayIdx = 0; (arrayIdx < arrays.Count) && (currentCount < totalCount); arrayIdx++)
|
T? temp = values[++left];
|
||||||
|
while (right >= startIndex && 0 < comparer.Compare(values[right], temp))
|
||||||
{
|
{
|
||||||
var array = arrays[arrayIdx];
|
values[right + 1] = values[right--];
|
||||||
currentCount += Math.Min(chunkSize, totalCount);
|
}
|
||||||
switch (currentCount < totalCount)
|
|
||||||
|
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))
|
||||||
{
|
{
|
||||||
case true:
|
return (arrayIdx * (long)blockSize) + memoryIdx;
|
||||||
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)
|
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 left = startIndex;
|
||||||
while (left < endIndex)
|
var right = endIndex;
|
||||||
|
|
||||||
|
while (left <= right)
|
||||||
{
|
{
|
||||||
int right = left;
|
while (0 > comparer.Compare(values[left], pivot))
|
||||||
T? temp = values[++left];
|
|
||||||
while (right >= startIndex && 0 < comparer.Compare(values[right], temp))
|
|
||||||
{
|
{
|
||||||
values[right + 1] = values[right--];
|
left++;
|
||||||
}
|
}
|
||||||
|
|
||||||
values[right + 1] = temp;
|
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 InsertionSort(IList<T> values, IComparer<T> comparer)
|
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]))
|
||||||
{
|
{
|
||||||
InsertionSort(values, 0, values.Count - 1, comparer);
|
Swap(values, right, left);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void InsertionSort(IList<T> values)
|
if (0 > comparer.Compare(values[middle], values[left]))
|
||||||
{
|
{
|
||||||
InsertionSort(values, Comparer<T>.Default);
|
Swap(values, middle, left);
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
if (0 > comparer.Compare(values[right], values[middle]))
|
||||||
public static long LongIndexOf(RecyclableList<T[]> arrays, int blockSize, T item, IEqualityComparer<T> comparer)
|
|
||||||
{
|
{
|
||||||
for (var arrayIdx = 0; arrayIdx < arrays.Count; arrayIdx++)
|
Swap(values, right, middle);
|
||||||
{
|
|
||||||
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.
|
return values[middle];
|
||||||
// It was only beautified for .Net 6.0+.
|
}
|
||||||
public static void QuickSort(IList<T> values, int startIndex, int endIndex, IComparer<T> comparer, IRandomNumberGenerator randomNumberGenerator)
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||||
|
public static T[] Resize(in T[]? source, int newSize)
|
||||||
|
{
|
||||||
|
ArrayPool<T> arrayPool = _arrayPool;
|
||||||
|
T[] newMemoryBlock = newSize >= RecyclableDefaults.MinPooledArrayLength
|
||||||
|
? arrayPool.Rent(newSize)
|
||||||
|
: new T[newSize];
|
||||||
|
|
||||||
|
if (source?.Length > 0)
|
||||||
{
|
{
|
||||||
var range = (startIndex, endIndex);
|
Array.Copy(source!, 0, newMemoryBlock, 0, source!.Length);
|
||||||
var stack = new Stack<(int, int)>();
|
if (source!.Length >= RecyclableDefaults.MinPooledArrayLength)
|
||||||
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
startIndex = range.startIndex;
|
// TODO: Measure gain vs relying on arrayPool to clear
|
||||||
endIndex = range.endIndex;
|
//if (NeedsClearing)
|
||||||
|
//{
|
||||||
|
// Array.Clear(source);
|
||||||
|
//}
|
||||||
|
|
||||||
if (endIndex - startIndex + 1 < 31)
|
// If anything, it has been already cleared above, so we don't need to repeat it.
|
||||||
{
|
arrayPool.Return(source, NeedsClearing);
|
||||||
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 | MethodImplOptions.AggressiveOptimization)]
|
|
||||||
public static T[] Resize(in T[]? source, int newSize)
|
|
||||||
{
|
|
||||||
ArrayPool<T> arrayPool = _arrayPool;
|
|
||||||
T[] newMemoryBlock = newSize >= RecyclableDefaults.MinPooledArrayLength
|
|
||||||
? arrayPool.Rent(newSize)
|
|
||||||
: new T[newSize];
|
|
||||||
|
|
||||||
if (source?.Length > 0)
|
|
||||||
{
|
|
||||||
Array.Copy(source!, 0, newMemoryBlock, 0, source!.Length);
|
|
||||||
if (source!.Length >= RecyclableDefaults.MinPooledArrayLength)
|
|
||||||
{
|
|
||||||
// TODO: Measure gain vs relying on arrayPool to clear
|
|
||||||
//if (NeedsClearing)
|
|
||||||
//{
|
|
||||||
// Array.Clear(source);
|
|
||||||
//}
|
|
||||||
|
|
||||||
// If anything, it has been already cleared above, so we don't need to repeat it.
|
|
||||||
arrayPool.Return(source, NeedsClearing);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return newMemoryBlock;
|
return newMemoryBlock;
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
private static void Swap(IList<T> values, int xIndex, int yIndex)
|
|
||||||
=> (values[yIndex], values[xIndex]) = (values[xIndex], values[yIndex]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
private static void Swap(IList<T> values, int xIndex, int yIndex)
|
||||||
|
=> (values[yIndex], values[xIndex]) = (values[xIndex], values[yIndex]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -36,7 +36,7 @@ namespace Recyclable.Collections
|
|||||||
{
|
{
|
||||||
if (targetItemIdx + growByCount > capacity)
|
if (targetItemIdx + growByCount > capacity)
|
||||||
{
|
{
|
||||||
capacity = Helpers.EnsureCapacity(this, capacity + growByCount);
|
capacity = RecyclableListHelpers<T>.EnsureCapacity(this, capacity + growByCount);
|
||||||
memorySpan = new(_memoryBlock);
|
memorySpan = new(_memoryBlock);
|
||||||
available = capacity - targetItemIdx;
|
available = capacity - targetItemIdx;
|
||||||
}
|
}
|
||||||
@@ -59,7 +59,7 @@ namespace Recyclable.Collections
|
|||||||
|
|
||||||
private void AddRangeWithKnownCount(IEnumerable<T> source, int targetItemIdx, int requiredAdditionalCapacity)
|
private void AddRangeWithKnownCount(IEnumerable<T> source, int targetItemIdx, int requiredAdditionalCapacity)
|
||||||
{
|
{
|
||||||
_ = Helpers.EnsureCapacity(this, targetItemIdx + requiredAdditionalCapacity);
|
_ = RecyclableListHelpers<T>.EnsureCapacity(this, targetItemIdx + requiredAdditionalCapacity);
|
||||||
|
|
||||||
Span<T> memorySpan = new(_memoryBlock);
|
Span<T> memorySpan = new(_memoryBlock);
|
||||||
foreach (var item in source)
|
foreach (var item in source)
|
||||||
@@ -82,7 +82,7 @@ namespace Recyclable.Collections
|
|||||||
{
|
{
|
||||||
if (initialCapacity > 0)
|
if (initialCapacity > 0)
|
||||||
{
|
{
|
||||||
_memoryBlock = Helpers.Resize(_memoryBlock, initialCapacity);
|
_memoryBlock = RecyclableListHelpers<T>.Resize(_memoryBlock, initialCapacity);
|
||||||
_capacity = _memoryBlock.Length;
|
_capacity = _memoryBlock.Length;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -131,7 +131,7 @@ namespace Recyclable.Collections
|
|||||||
|
|
||||||
public RecyclableList(IEnumerable<T> source, int initialCapacity = RecyclableDefaults.Capacity)
|
public RecyclableList(IEnumerable<T> source, int initialCapacity = RecyclableDefaults.Capacity)
|
||||||
{
|
{
|
||||||
_memoryBlock = Helpers.Resize(_memoryBlock, initialCapacity);
|
_memoryBlock = RecyclableListHelpers<T>.Resize(_memoryBlock, initialCapacity);
|
||||||
_capacity = _memoryBlock.Length;
|
_capacity = _memoryBlock.Length;
|
||||||
AddRange(source);
|
AddRange(source);
|
||||||
}
|
}
|
||||||
@@ -149,7 +149,7 @@ namespace Recyclable.Collections
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private int _capacity;
|
internal int _capacity;
|
||||||
public int Capacity
|
public int Capacity
|
||||||
{
|
{
|
||||||
get => _capacity;
|
get => _capacity;
|
||||||
@@ -157,7 +157,7 @@ namespace Recyclable.Collections
|
|||||||
{
|
{
|
||||||
if (_capacity != value)
|
if (_capacity != value)
|
||||||
{
|
{
|
||||||
_memoryBlock = Helpers.Resize(_memoryBlock, value);
|
_memoryBlock = RecyclableListHelpers<T>.Resize(_memoryBlock, value);
|
||||||
_capacity = _memoryBlock.Length;
|
_capacity = _memoryBlock.Length;
|
||||||
_version++;
|
_version++;
|
||||||
}
|
}
|
||||||
@@ -175,7 +175,7 @@ namespace Recyclable.Collections
|
|||||||
int requiredCapacity = _count + 1;
|
int requiredCapacity = _count + 1;
|
||||||
if (_capacity < requiredCapacity)
|
if (_capacity < requiredCapacity)
|
||||||
{
|
{
|
||||||
_ = Helpers.EnsureCapacity(this, requiredCapacity);
|
_ = RecyclableListHelpers<T>.EnsureCapacity(this, requiredCapacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
_memoryBlock[_count++] = item;
|
_memoryBlock[_count++] = item;
|
||||||
@@ -194,14 +194,13 @@ namespace Recyclable.Collections
|
|||||||
int targetCapacity = _count + sourceItemsCount;
|
int targetCapacity = _count + sourceItemsCount;
|
||||||
if (_capacity < targetCapacity)
|
if (_capacity < targetCapacity)
|
||||||
{
|
{
|
||||||
_ = Helpers.EnsureCapacity(this, targetCapacity);
|
_ = RecyclableListHelpers<T>.EnsureCapacity(this, targetCapacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
var targetSpan = new Span<T>(_memoryBlock, _count, sourceItemsCount);
|
var targetSpan = new Span<T>(_memoryBlock, _count, sourceItemsCount);
|
||||||
Span<T> itemsSpan = new(items);
|
Span<T> itemsSpan = new(items);
|
||||||
itemsSpan.CopyTo(targetSpan);
|
itemsSpan.CopyTo(targetSpan);
|
||||||
_count = targetCapacity;
|
_count = targetCapacity;
|
||||||
|
|
||||||
_version++;
|
_version++;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -217,7 +216,7 @@ namespace Recyclable.Collections
|
|||||||
int targetCapacity = _count + sourceItemsCount;
|
int targetCapacity = _count + sourceItemsCount;
|
||||||
if (_capacity < targetCapacity)
|
if (_capacity < targetCapacity)
|
||||||
{
|
{
|
||||||
_ = Helpers.EnsureCapacity(this, targetCapacity);
|
_ = RecyclableListHelpers<T>.EnsureCapacity(this, targetCapacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
var targetSpan = new Span<T>(_memoryBlock, _count, sourceItemsCount);
|
var targetSpan = new Span<T>(_memoryBlock, _count, sourceItemsCount);
|
||||||
@@ -239,7 +238,7 @@ namespace Recyclable.Collections
|
|||||||
var targetCapacity = _count + sourceItemsCount;
|
var targetCapacity = _count + sourceItemsCount;
|
||||||
if (_capacity < targetCapacity)
|
if (_capacity < targetCapacity)
|
||||||
{
|
{
|
||||||
_ = Helpers.EnsureCapacity(this, targetCapacity);
|
_ = RecyclableListHelpers<T>.EnsureCapacity(this, targetCapacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
items.CopyTo(_memoryBlock, _count);
|
items.CopyTo(_memoryBlock, _count);
|
||||||
@@ -260,7 +259,7 @@ namespace Recyclable.Collections
|
|||||||
var targetCapacity = _count + sourceItemsCount;
|
var targetCapacity = _count + sourceItemsCount;
|
||||||
if (_capacity < targetCapacity)
|
if (_capacity < targetCapacity)
|
||||||
{
|
{
|
||||||
_ = Helpers.EnsureCapacity(this, targetCapacity);
|
_ = RecyclableListHelpers<T>.EnsureCapacity(this, targetCapacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
items.CopyTo(_memoryBlock, _count);
|
items.CopyTo(_memoryBlock, _count);
|
||||||
@@ -281,7 +280,7 @@ namespace Recyclable.Collections
|
|||||||
var targetCapacity = _count + sourceItemsCount;
|
var targetCapacity = _count + sourceItemsCount;
|
||||||
if (_capacity < targetCapacity)
|
if (_capacity < targetCapacity)
|
||||||
{
|
{
|
||||||
_ = Helpers.EnsureCapacity(this, targetCapacity);
|
_ = RecyclableListHelpers<T>.EnsureCapacity(this, targetCapacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
var targetSpan = new Span<T>(_memoryBlock, _count, sourceItemsCount);
|
var targetSpan = new Span<T>(_memoryBlock, _count, sourceItemsCount);
|
||||||
@@ -314,7 +313,7 @@ namespace Recyclable.Collections
|
|||||||
int targetCapacity = _count + (int)sourceItemsCount;
|
int targetCapacity = _count + (int)sourceItemsCount;
|
||||||
if (_capacity < targetCapacity)
|
if (_capacity < targetCapacity)
|
||||||
{
|
{
|
||||||
_ = Helpers.EnsureCapacity(this, targetCapacity);
|
_ = RecyclableListHelpers<T>.EnsureCapacity(this, targetCapacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
Span<T> targetSpan = new Span<T>(_memoryBlock)[_count..],
|
Span<T> targetSpan = new Span<T>(_memoryBlock)[_count..],
|
||||||
@@ -415,7 +414,7 @@ namespace Recyclable.Collections
|
|||||||
int requestedCapacity = oldCount + 1;
|
int requestedCapacity = oldCount + 1;
|
||||||
if (_capacity < requestedCapacity)
|
if (_capacity < requestedCapacity)
|
||||||
{
|
{
|
||||||
_ = Helpers.EnsureCapacity(this, requestedCapacity);
|
_ = RecyclableListHelpers<T>.EnsureCapacity(this, requestedCapacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (oldCount > 0)
|
if (oldCount > 0)
|
||||||
|
|||||||
@@ -171,13 +171,13 @@ namespace Recyclable.Collections
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Contains(T item) => RecyclableList<T>.Helpers.Contains(Memory, item);
|
public bool Contains(T item) => RecyclableListHelpers<T>.Contains(Memory, item);
|
||||||
public void CopyTo(T[] array, int arrayIndex) => RecyclableList<T>.Helpers.CopyTo(Memory, RemovedCount, BlockSize, (int)(LongCount % BlockSize), array, arrayIndex);
|
public void CopyTo(T[] array, int arrayIndex) => RecyclableListHelpers<T>.CopyTo(Memory, RemovedCount, BlockSize, (int)(LongCount % BlockSize), array, arrayIndex);
|
||||||
public IEnumerable<T> Enumerate() => RecyclableList<T>.Helpers.Enumerate(Memory, BlockSize, LongCount);
|
public IEnumerable<T> Enumerate() => RecyclableListHelpers<T>.Enumerate(Memory, BlockSize, LongCount);
|
||||||
public IEnumerator<T> GetEnumerator() => RecyclableList<T>.Helpers.Enumerate(Memory, BlockSize, LongCount).GetEnumerator();
|
public IEnumerator<T> GetEnumerator() => RecyclableListHelpers<T>.Enumerate(Memory, BlockSize, LongCount).GetEnumerator();
|
||||||
IEnumerator IEnumerable.GetEnumerator() => RecyclableList<T>.Helpers.Enumerate(Memory, BlockSize, LongCount).GetEnumerator();
|
IEnumerator IEnumerable.GetEnumerator() => RecyclableListHelpers<T>.Enumerate(Memory, BlockSize, LongCount).GetEnumerator();
|
||||||
public int IndexOf(T item) => (int)GetRelativeIndex(RecyclableList<T>.Helpers.LongIndexOf(Memory, BlockSize, item, _equalityComparer));
|
public int IndexOf(T item) => (int)GetRelativeIndex(RecyclableListHelpers<T>.LongIndexOf(Memory, BlockSize, item, _equalityComparer));
|
||||||
public long LongIndexOf(T item) => GetRelativeIndex(RecyclableList<T>.Helpers.LongIndexOf(Memory, BlockSize, item, _equalityComparer));
|
public long LongIndexOf(T item) => GetRelativeIndex(RecyclableListHelpers<T>.LongIndexOf(Memory, BlockSize, item, _equalityComparer));
|
||||||
public void Insert(int index, T item) => throw new NotSupportedException();
|
public void Insert(int index, T item) => throw new NotSupportedException();
|
||||||
public void RemoveAt(int index) => throw new NotSupportedException();
|
public void RemoveAt(int index) => throw new NotSupportedException();
|
||||||
public bool TryDequeue(out T? item) => TryDequeue(this, out item);
|
public bool TryDequeue(out T? item) => TryDequeue(this, out item);
|
||||||
|
|||||||
@@ -68,7 +68,7 @@
|
|||||||
BeginUpdate();
|
BeginUpdate();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
RecyclableList<(TKey Key, TValue Value)>.Helpers.QuickSort(this, _comparer, _randomNumberGenerator);
|
RecyclableListHelpers<(TKey, TValue)>.QuickSort(this, _comparer, _randomNumberGenerator);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -422,7 +422,7 @@ namespace Recyclable.CollectionsTests
|
|||||||
|
|
||||||
// Act
|
// Act
|
||||||
using RecyclableList<long> list = new(testData);
|
using RecyclableList<long> list = new(testData);
|
||||||
RecyclableList<long>.Helpers.QuickSort(list);
|
RecyclableListHelpers<long>.QuickSort(list);
|
||||||
|
|
||||||
// Validate
|
// Validate
|
||||||
_ = list.Count.Should().Be((int)itemsCount);
|
_ = list.Count.Should().Be((int)itemsCount);
|
||||||
|
|||||||
@@ -479,7 +479,7 @@ namespace Recyclable.CollectionsTests
|
|||||||
|
|
||||||
// Act
|
// Act
|
||||||
using RecyclableLongList<long> list = new(testData, minBlockSize: targetBlockSize);
|
using RecyclableLongList<long> list = new(testData, minBlockSize: targetBlockSize);
|
||||||
RecyclableList<long>.Helpers.QuickSort(list);
|
RecyclableListHelpers<long>.QuickSort(list);
|
||||||
|
|
||||||
// Validate
|
// Validate
|
||||||
_ = list.LongCount.Should().Be(itemsCount);
|
_ = list.LongCount.Should().Be(itemsCount);
|
||||||
|
|||||||
Reference in new issue
Block a user