using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
+using System.Runtime.CompilerServices;
namespace System.Collections.Generic
{
{
#region IArraySortHelper<T> Members
- public void Sort(T[] keys, int index, int length, IComparer<T>? comparer)
+ public void Sort(Span<T> keys, IComparer<T>? comparer)
{
- Debug.Assert(keys != null, "Check the arguments in the caller!");
- Debug.Assert(index >= 0 && length >= 0 && (keys.Length - index >= length), "Check the arguments in the caller!");
-
// Add a try block here to detect IComparers (or their
// underlying IComparables, etc) that are bogus.
try
{
comparer ??= Comparer<T>.Default;
- IntrospectiveSort(keys, index, length, comparer.Compare);
+ IntrospectiveSort(keys, comparer.Compare);
}
catch (IndexOutOfRangeException)
{
#endregion
- internal static void Sort(T[] keys, int index, int length, Comparison<T> comparer)
+ internal static void Sort(Span<T> keys, Comparison<T> comparer)
{
- Debug.Assert(keys != null, "Check the arguments in the caller!");
- Debug.Assert(index >= 0 && length >= 0 && (keys.Length - index >= length), "Check the arguments in the caller!");
Debug.Assert(comparer != null, "Check the arguments in the caller!");
// Add a try block here to detect bogus comparisons
try
{
- IntrospectiveSort(keys, index, length, comparer);
+ IntrospectiveSort(keys, comparer);
}
catch (IndexOutOfRangeException)
{
return ~lo;
}
- private static void SwapIfGreater(T[] keys, Comparison<T> comparer, int a, int b)
+ private static void SwapIfGreater(Span<T> keys, Comparison<T> comparer, int i, int j)
{
- if (a != b)
+ if (i != j)
{
- if (comparer(keys[a], keys[b]) > 0)
+ if (comparer(keys[i], keys[j]) > 0)
{
- T key = keys[a];
- keys[a] = keys[b];
- keys[b] = key;
+ T key = keys[i];
+ keys[i] = keys[j];
+ keys[j] = key;
}
}
}
- private static void Swap(T[] a, int i, int j)
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static void Swap(Span<T> a, int i, int j)
{
if (i != j)
{
}
}
- internal static void IntrospectiveSort(T[] keys, int left, int length, Comparison<T> comparer)
+ internal static void IntrospectiveSort(Span<T> keys, Comparison<T> comparer)
{
- Debug.Assert(keys != null);
Debug.Assert(comparer != null);
- Debug.Assert(left >= 0);
- Debug.Assert(length >= 0);
- Debug.Assert(length <= keys.Length);
- Debug.Assert(length + left <= keys.Length);
-
- if (length < 2)
- return;
- IntroSort(keys, left, length + left - 1, 2 * IntrospectiveSortUtilities.FloorLog2PlusOne(length), comparer);
+ if (keys.Length > 1)
+ {
+ IntroSort(keys, 2 * IntrospectiveSortUtilities.FloorLog2PlusOne(keys.Length), comparer);
+ }
}
- private static void IntroSort(T[] keys, int lo, int hi, int depthLimit, Comparison<T> comparer)
+ private static void IntroSort(Span<T> keys, int depthLimit, Comparison<T> comparer)
{
- Debug.Assert(keys != null);
+ int lo = 0;
+ int hi = keys.Length - 1;
+
Debug.Assert(comparer != null);
- Debug.Assert(lo >= 0);
- Debug.Assert(hi < keys.Length);
while (hi > lo)
{
{
return;
}
+
if (partitionSize == 2)
{
SwapIfGreater(keys, comparer, lo, hi);
return;
}
+
if (partitionSize == 3)
{
SwapIfGreater(keys, comparer, lo, hi - 1);
return;
}
- InsertionSort(keys, lo, hi, comparer);
+ InsertionSort(keys[lo..(hi+1)], comparer);
return;
}
if (depthLimit == 0)
{
- Heapsort(keys, lo, hi, comparer);
+ HeapSort(keys[lo..(hi+1)], comparer);
return;
}
depthLimit--;
- int p = PickPivotAndPartition(keys, lo, hi, comparer);
+ int p = PickPivotAndPartition(keys[lo..(hi+1)], comparer);
+
// Note we've already partitioned around the pivot and do not have to move the pivot again.
- IntroSort(keys, p + 1, hi, depthLimit, comparer);
+ IntroSort(keys[(p+1)..(hi+1)], depthLimit, comparer);
hi = p - 1;
}
}
- private static int PickPivotAndPartition(T[] keys, int lo, int hi, Comparison<T> comparer)
+ private static int PickPivotAndPartition(Span<T> keys, Comparison<T> comparer)
{
- Debug.Assert(keys != null);
Debug.Assert(comparer != null);
- Debug.Assert(lo >= 0);
- Debug.Assert(hi > lo);
- Debug.Assert(hi < keys.Length);
+ Debug.Assert(!keys.IsEmpty);
+
+ int lo = 0;
+ int hi = keys.Length - 1;
// Compute median-of-three. But also partition them, since we've done the comparison.
int middle = lo + ((hi - lo) / 2);
return left;
}
- private static void Heapsort(T[] keys, int lo, int hi, Comparison<T> comparer)
+ private static void HeapSort(Span<T> keys, Comparison<T> comparer)
{
- Debug.Assert(keys != null);
Debug.Assert(comparer != null);
- Debug.Assert(lo >= 0);
- Debug.Assert(hi > lo);
- Debug.Assert(hi < keys.Length);
+ Debug.Assert(!keys.IsEmpty);
+
+ int lo = 0;
+ int hi = keys.Length - 1;
int n = hi - lo + 1;
+
for (int i = n / 2; i >= 1; i--)
{
DownHeap(keys, i, n, lo, comparer);
}
+
for (int i = n; i > 1; i--)
{
Swap(keys, lo, lo + i - 1);
}
}
- private static void DownHeap(T[] keys, int i, int n, int lo, Comparison<T> comparer)
+ private static void DownHeap(Span<T> keys, int i, int n, int lo, Comparison<T> comparer)
{
- Debug.Assert(keys != null);
Debug.Assert(comparer != null);
Debug.Assert(lo >= 0);
Debug.Assert(lo < keys.Length);
T d = keys[lo + i - 1];
- int child;
while (i <= n / 2)
{
- child = 2 * i;
+ int child = 2 * i;
if (child < n && comparer(keys[lo + child - 1], keys[lo + child]) < 0)
{
child++;
}
+
if (!(comparer(d, keys[lo + child - 1]) < 0))
break;
+
keys[lo + i - 1] = keys[lo + child - 1];
i = child;
}
+
keys[lo + i - 1] = d;
}
- private static void InsertionSort(T[] keys, int lo, int hi, Comparison<T> comparer)
+ private static void InsertionSort(Span<T> keys, Comparison<T> comparer)
{
- Debug.Assert(keys != null);
- Debug.Assert(lo >= 0);
- Debug.Assert(hi >= lo);
- Debug.Assert(hi <= keys.Length);
-
- int i, j;
- T t;
- for (i = lo; i < hi; i++)
+ for (int i = 0; i < keys.Length - 1; i++)
{
- j = i;
- t = keys[i + 1];
- while (j >= lo && comparer(t, keys[j]) < 0)
+ T t = keys[i + 1];
+
+ int j = i;
+ while (j >= 0 && comparer(t, keys[j]) < 0)
{
keys[j + 1] = keys[j];
j--;
}
+
keys[j + 1] = t;
}
}
#region IArraySortHelper<T> Members
- public void Sort(T[] keys, int index, int length, IComparer<T>? comparer)
+ public void Sort(Span<T> keys, IComparer<T>? comparer)
{
- Debug.Assert(keys != null, "Check the arguments in the caller!");
- Debug.Assert(index >= 0 && length >= 0 && (keys.Length - index >= length), "Check the arguments in the caller!");
-
try
{
if (comparer == null || comparer == Comparer<T>.Default)
{
- IntrospectiveSort(keys, index, length);
+ IntrospectiveSort(keys);
}
else
{
- ArraySortHelper<T>.IntrospectiveSort(keys, index, length, comparer.Compare);
+ ArraySortHelper<T>.IntrospectiveSort(keys, comparer.Compare);
}
}
catch (IndexOutOfRangeException)
return ~lo;
}
- private static void SwapIfGreaterWithItems(T[] keys, int a, int b)
+ private static void SwapIfGreater(Span<T> keys, int i, int j)
{
- Debug.Assert(keys != null);
- Debug.Assert(0 <= a && a < keys.Length);
- Debug.Assert(0 <= b && b < keys.Length);
+ Debug.Assert(0 <= i && i < keys.Length);
+ Debug.Assert(0 <= j && j < keys.Length);
- if (a != b)
+ if (i != j)
{
- if (keys[a] != null && keys[a].CompareTo(keys[b]) > 0)
+ if (keys[i] != null && keys[i].CompareTo(keys[j]) > 0)
{
- T key = keys[a];
- keys[a] = keys[b];
- keys[b] = key;
+ T key = keys[i];
+ keys[i] = keys[j];
+ keys[j] = key;
}
}
}
- private static void Swap(T[] a, int i, int j)
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static void Swap(Span<T> a, int i, int j)
{
if (i != j)
{
}
}
- internal static void IntrospectiveSort(T[] keys, int left, int length)
+ internal static void IntrospectiveSort(Span<T> keys)
{
- Debug.Assert(keys != null);
- Debug.Assert(left >= 0);
- Debug.Assert(length >= 0);
- Debug.Assert(length <= keys.Length);
- Debug.Assert(length + left <= keys.Length);
-
- if (length < 2)
- return;
-
- IntroSort(keys, left, length + left - 1, 2 * IntrospectiveSortUtilities.FloorLog2PlusOne(length));
+ if (keys.Length > 1)
+ {
+ IntroSort(keys, 2 * IntrospectiveSortUtilities.FloorLog2PlusOne(keys.Length));
+ }
}
- private static void IntroSort(T[] keys, int lo, int hi, int depthLimit)
+ private static void IntroSort(Span<T> keys, int depthLimit)
{
- Debug.Assert(keys != null);
- Debug.Assert(lo >= 0);
- Debug.Assert(hi < keys.Length);
+ int lo = 0;
+ int hi = keys.Length - 1;
while (hi > lo)
{
}
if (partitionSize == 2)
{
- SwapIfGreaterWithItems(keys, lo, hi);
+ SwapIfGreater(keys, lo, hi);
return;
}
if (partitionSize == 3)
{
- SwapIfGreaterWithItems(keys, lo, hi - 1);
- SwapIfGreaterWithItems(keys, lo, hi);
- SwapIfGreaterWithItems(keys, hi - 1, hi);
+ SwapIfGreater(keys, lo, hi - 1);
+ SwapIfGreater(keys, lo, hi);
+ SwapIfGreater(keys, hi - 1, hi);
return;
}
- InsertionSort(keys, lo, hi);
+ InsertionSort(keys[lo..(hi+1)]);
return;
}
if (depthLimit == 0)
{
- Heapsort(keys, lo, hi);
+ HeapSort(keys[lo..(hi+1)]);
return;
}
depthLimit--;
- int p = PickPivotAndPartition(keys, lo, hi);
+ int p = PickPivotAndPartition(keys[lo..(hi+1)]);
+
// Note we've already partitioned around the pivot and do not have to move the pivot again.
- IntroSort(keys, p + 1, hi, depthLimit);
+ IntroSort(keys[(p+1)..(hi+1)], depthLimit);
hi = p - 1;
}
}
- private static int PickPivotAndPartition(T[] keys, int lo, int hi)
+ private static int PickPivotAndPartition(Span<T> keys)
{
- Debug.Assert(keys != null);
- Debug.Assert(lo >= 0);
- Debug.Assert(hi > lo);
- Debug.Assert(hi < keys.Length);
+ Debug.Assert(!keys.IsEmpty);
+
+ int lo = 0;
+ int hi = keys.Length - 1;
// Compute median-of-three. But also partition them, since we've done the comparison.
int middle = lo + ((hi - lo) / 2);
// Sort lo, mid and hi appropriately, then pick mid as the pivot.
- SwapIfGreaterWithItems(keys, lo, middle); // swap the low with the mid point
- SwapIfGreaterWithItems(keys, lo, hi); // swap the low with the high
- SwapIfGreaterWithItems(keys, middle, hi); // swap the middle with the high
+ SwapIfGreater(keys, lo, middle); // swap the low with the mid point
+ SwapIfGreater(keys, lo, hi); // swap the low with the high
+ SwapIfGreater(keys, middle, hi); // swap the middle with the high
T pivot = keys[middle];
Swap(keys, middle, hi - 1);
return left;
}
- private static void Heapsort(T[] keys, int lo, int hi)
+ private static void HeapSort(Span<T> keys)
{
- Debug.Assert(keys != null);
- Debug.Assert(lo >= 0);
- Debug.Assert(hi > lo);
- Debug.Assert(hi < keys.Length);
+ Debug.Assert(!keys.IsEmpty);
+
+ int lo = 0;
+ int hi = keys.Length - 1;
int n = hi - lo + 1;
- for (int i = n / 2; i >= 1; i--)
+ for (int i = n / 2; i >= 1; i = i - 1)
{
DownHeap(keys, i, n, lo);
}
+
for (int i = n; i > 1; i--)
{
Swap(keys, lo, lo + i - 1);
}
}
- private static void DownHeap(T[] keys, int i, int n, int lo)
+ private static void DownHeap(Span<T> keys, int i, int n, int lo)
{
- Debug.Assert(keys != null);
Debug.Assert(lo >= 0);
Debug.Assert(lo < keys.Length);
T d = keys[lo + i - 1];
- int child;
while (i <= n / 2)
{
- child = 2 * i;
+ int child = 2 * i;
if (child < n && (keys[lo + child - 1] == null || keys[lo + child - 1].CompareTo(keys[lo + child]) < 0))
{
child++;
}
+
if (keys[lo + child - 1] == null || keys[lo + child - 1].CompareTo(d) < 0)
break;
+
keys[lo + i - 1] = keys[lo + child - 1];
i = child;
}
+
keys[lo + i - 1] = d;
}
- private static void InsertionSort(T[] keys, int lo, int hi)
+ private static void InsertionSort(Span<T> keys)
{
- Debug.Assert(keys != null);
- Debug.Assert(lo >= 0);
- Debug.Assert(hi >= lo);
- Debug.Assert(hi <= keys.Length);
-
- int i, j;
- T t;
- for (i = lo; i < hi; i++)
+ for (int i = 0; i < keys.Length - 1; i++)
{
- j = i;
- t = keys[i + 1];
- while (j >= lo && (t == null || t.CompareTo(keys[j]) < 0))
+ T t = keys[i + 1];
+
+ int j = i;
+ while (j >= 0 && (t == null || t.CompareTo(keys[j]) < 0))
{
keys[j + 1] = keys[j];
j--;
}
+
keys[j + 1] = t;
}
}
internal partial class ArraySortHelper<TKey, TValue>
{
- public void Sort(TKey[] keys, TValue[] values, int index, int length, IComparer<TKey>? comparer)
+ public void Sort(Span<TKey> keys, Span<TValue> values, IComparer<TKey>? comparer)
{
- Debug.Assert(keys != null, "Check the arguments in the caller!"); // Precondition on interface method
- Debug.Assert(values != null, "Check the arguments in the caller!");
- Debug.Assert(index >= 0 && length >= 0 && (keys.Length - index >= length), "Check the arguments in the caller!");
-
// Add a try block here to detect IComparers (or their
// underlying IComparables, etc) that are bogus.
try
{
- if (comparer == null || comparer == Comparer<TKey>.Default)
- {
- comparer = Comparer<TKey>.Default;
- }
-
- IntrospectiveSort(keys, values, index, length, comparer);
+ IntrospectiveSort(keys, values, comparer ?? Comparer<TKey>.Default);
}
catch (IndexOutOfRangeException)
{
}
}
- private static void SwapIfGreaterWithItems(TKey[] keys, TValue[] values, IComparer<TKey> comparer, int a, int b)
+ private static void SwapIfGreaterWithValues(Span<TKey> keys, Span<TValue> values, IComparer<TKey> comparer, int i, int j)
{
- Debug.Assert(keys != null);
- Debug.Assert(values != null);
Debug.Assert(comparer != null);
- Debug.Assert(0 <= a && a < keys.Length && a < values.Length);
- Debug.Assert(0 <= b && b < keys.Length && b < values.Length);
+ Debug.Assert(0 <= i && i < keys.Length && i < values.Length);
+ Debug.Assert(0 <= j && j < keys.Length && j < values.Length);
- if (a != b)
+ if (i != j)
{
- if (comparer.Compare(keys[a], keys[b]) > 0)
+ if (comparer.Compare(keys[i], keys[j]) > 0)
{
- TKey key = keys[a];
- keys[a] = keys[b];
- keys[b] = key;
+ TKey key = keys[i];
+ keys[i] = keys[j];
+ keys[j] = key;
- TValue value = values[a];
- values[a] = values[b];
- values[b] = value;
+ TValue value = values[i];
+ values[i] = values[j];
+ values[j] = value;
}
}
}
- private static void Swap(TKey[] keys, TValue[] values, int i, int j)
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static void Swap(Span<TKey> keys, Span<TValue> values, int i, int j)
{
if (i != j)
{
}
}
- internal static void IntrospectiveSort(TKey[] keys, TValue[] values, int left, int length, IComparer<TKey> comparer)
+ internal static void IntrospectiveSort(Span<TKey> keys, Span<TValue> values, IComparer<TKey> comparer)
{
- Debug.Assert(keys != null);
- Debug.Assert(values != null);
Debug.Assert(comparer != null);
- Debug.Assert(left >= 0);
- Debug.Assert(length >= 0);
- Debug.Assert(length <= keys.Length);
- Debug.Assert(length + left <= keys.Length);
- Debug.Assert(length + left <= values.Length);
-
- if (length < 2)
- return;
+ Debug.Assert(keys.Length == values.Length);
- IntroSort(keys, values, left, length + left - 1, 2 * IntrospectiveSortUtilities.FloorLog2PlusOne(length), comparer);
+ if (keys.Length > 1)
+ {
+ IntroSort(keys, values, 2 * IntrospectiveSortUtilities.FloorLog2PlusOne(keys.Length), comparer);
+ }
}
- private static void IntroSort(TKey[] keys, TValue[] values, int lo, int hi, int depthLimit, IComparer<TKey> comparer)
+ private static void IntroSort(Span<TKey> keys, Span<TValue> values, int depthLimit, IComparer<TKey> comparer)
{
- Debug.Assert(keys != null);
- Debug.Assert(values != null);
Debug.Assert(comparer != null);
- Debug.Assert(lo >= 0);
- Debug.Assert(hi < keys.Length);
+
+ int lo = 0;
+ int hi = keys.Length - 1;
while (hi > lo)
{
{
return;
}
+
if (partitionSize == 2)
{
- SwapIfGreaterWithItems(keys, values, comparer, lo, hi);
+ SwapIfGreaterWithValues(keys, values, comparer, lo, hi);
return;
}
+
if (partitionSize == 3)
{
- SwapIfGreaterWithItems(keys, values, comparer, lo, hi - 1);
- SwapIfGreaterWithItems(keys, values, comparer, lo, hi);
- SwapIfGreaterWithItems(keys, values, comparer, hi - 1, hi);
+ SwapIfGreaterWithValues(keys, values, comparer, lo, hi - 1);
+ SwapIfGreaterWithValues(keys, values, comparer, lo, hi);
+ SwapIfGreaterWithValues(keys, values, comparer, hi - 1, hi);
return;
}
- InsertionSort(keys, values, lo, hi, comparer);
+ InsertionSort(keys[lo..(hi+1)], values[lo..(hi+1)], comparer);
return;
}
if (depthLimit == 0)
{
- Heapsort(keys, values, lo, hi, comparer);
+ HeapSort(keys[lo..(hi+1)], values[lo..(hi+1)], comparer);
return;
}
depthLimit--;
- int p = PickPivotAndPartition(keys, values, lo, hi, comparer);
+ int p = PickPivotAndPartition(keys[lo..(hi+1)], values[lo..(hi+1)], comparer);
+
// Note we've already partitioned around the pivot and do not have to move the pivot again.
- IntroSort(keys, values, p + 1, hi, depthLimit, comparer);
+ IntroSort(keys[(p+1)..(hi+1)], values[(p+1)..(hi+1)], depthLimit, comparer);
hi = p - 1;
}
}
- private static int PickPivotAndPartition(TKey[] keys, TValue[] values, int lo, int hi, IComparer<TKey> comparer)
+ private static int PickPivotAndPartition(Span<TKey> keys, Span<TValue> values, IComparer<TKey> comparer)
{
- Debug.Assert(keys != null);
- Debug.Assert(values != null);
Debug.Assert(comparer != null);
- Debug.Assert(lo >= 0);
- Debug.Assert(hi > lo);
- Debug.Assert(hi < keys.Length);
+ Debug.Assert(!keys.IsEmpty);
+
+ int lo = 0;
+ int hi = keys.Length - 1;
// Compute median-of-three. But also partition them, since we've done the comparison.
int middle = lo + ((hi - lo) / 2);
// Sort lo, mid and hi appropriately, then pick mid as the pivot.
- SwapIfGreaterWithItems(keys, values, comparer, lo, middle); // swap the low with the mid point
- SwapIfGreaterWithItems(keys, values, comparer, lo, hi); // swap the low with the high
- SwapIfGreaterWithItems(keys, values, comparer, middle, hi); // swap the middle with the high
+ SwapIfGreaterWithValues(keys, values, comparer, lo, middle); // swap the low with the mid point
+ SwapIfGreaterWithValues(keys, values, comparer, lo, hi); // swap the low with the high
+ SwapIfGreaterWithValues(keys, values, comparer, middle, hi); // swap the middle with the high
TKey pivot = keys[middle];
Swap(keys, values, middle, hi - 1);
return left;
}
- private static void Heapsort(TKey[] keys, TValue[] values, int lo, int hi, IComparer<TKey> comparer)
+ private static void HeapSort(Span<TKey> keys, Span<TValue> values, IComparer<TKey> comparer)
{
- Debug.Assert(keys != null);
- Debug.Assert(values != null);
Debug.Assert(comparer != null);
- Debug.Assert(lo >= 0);
- Debug.Assert(hi > lo);
- Debug.Assert(hi < keys.Length);
+ Debug.Assert(!keys.IsEmpty);
+
+ int lo = 0;
+ int hi = keys.Length - 1;
int n = hi - lo + 1;
for (int i = n / 2; i >= 1; i--)
{
DownHeap(keys, values, i, n, lo, comparer);
}
+
for (int i = n; i > 1; i--)
{
Swap(keys, values, lo, lo + i - 1);
}
}
- private static void DownHeap(TKey[] keys, TValue[] values, int i, int n, int lo, IComparer<TKey> comparer)
+ private static void DownHeap(Span<TKey> keys, Span<TValue> values, int i, int n, int lo, IComparer<TKey> comparer)
{
- Debug.Assert(keys != null);
- Debug.Assert(values != null);
Debug.Assert(comparer != null);
Debug.Assert(lo >= 0);
Debug.Assert(lo < keys.Length);
TKey d = keys[lo + i - 1];
TValue dValue = values[lo + i - 1];
- int child;
+
while (i <= n / 2)
{
- child = 2 * i;
+ int child = 2 * i;
if (child < n && comparer.Compare(keys[lo + child - 1], keys[lo + child]) < 0)
{
child++;
}
+
if (!(comparer.Compare(d, keys[lo + child - 1]) < 0))
break;
+
keys[lo + i - 1] = keys[lo + child - 1];
values[lo + i - 1] = values[lo + child - 1];
i = child;
}
+
keys[lo + i - 1] = d;
values[lo + i - 1] = dValue;
}
- private static void InsertionSort(TKey[] keys, TValue[] values, int lo, int hi, IComparer<TKey> comparer)
+ private static void InsertionSort(Span<TKey> keys, Span<TValue> values, IComparer<TKey> comparer)
{
- Debug.Assert(keys != null);
- Debug.Assert(values != null);
Debug.Assert(comparer != null);
- Debug.Assert(lo >= 0);
- Debug.Assert(hi >= lo);
- Debug.Assert(hi <= keys.Length);
- int i, j;
- TKey t;
- TValue tValue;
- for (i = lo; i < hi; i++)
+ for (int i = 0; i < keys.Length - 1; i++)
{
- j = i;
- t = keys[i + 1];
- tValue = values[i + 1];
- while (j >= lo && comparer.Compare(t, keys[j]) < 0)
+ TKey t = keys[i + 1];
+ TValue tValue = values[i + 1];
+
+ int j = i;
+ while (j >= 0 && comparer.Compare(t, keys[j]) < 0)
{
keys[j + 1] = keys[j];
values[j + 1] = values[j];
j--;
}
+
keys[j + 1] = t;
values[j + 1] = tValue;
}
internal partial class GenericArraySortHelper<TKey, TValue>
where TKey : IComparable<TKey>
{
- public void Sort(TKey[] keys, TValue[] values, int index, int length, IComparer<TKey>? comparer)
+ public void Sort(Span<TKey> keys, Span<TValue> values, IComparer<TKey>? comparer)
{
- Debug.Assert(keys != null, "Check the arguments in the caller!");
- Debug.Assert(index >= 0 && length >= 0 && (keys.Length - index >= length), "Check the arguments in the caller!");
-
// Add a try block here to detect IComparers (or their
// underlying IComparables, etc) that are bogus.
try
{
if (comparer == null || comparer == Comparer<TKey>.Default)
{
- IntrospectiveSort(keys, values, index, length);
+ IntrospectiveSort(keys, values);
}
else
{
- ArraySortHelper<TKey, TValue>.IntrospectiveSort(keys, values, index, length, comparer);
+ ArraySortHelper<TKey, TValue>.IntrospectiveSort(keys, values, comparer);
}
}
catch (IndexOutOfRangeException)
}
}
- private static void SwapIfGreaterWithItems(TKey[] keys, TValue[] values, int a, int b)
+ private static void SwapIfGreaterWithValues(Span<TKey> keys, Span<TValue> values, int i, int j)
{
- if (a != b)
+ if (i != j)
{
- if (keys[a] != null && keys[a].CompareTo(keys[b]) > 0)
+ if (keys[i] != null && keys[i].CompareTo(keys[j]) > 0)
{
- TKey key = keys[a];
- keys[a] = keys[b];
- keys[b] = key;
+ TKey key = keys[i];
+ keys[i] = keys[j];
+ keys[j] = key;
- TValue value = values[a];
- values[a] = values[b];
- values[b] = value;
+ TValue value = values[i];
+ values[i] = values[j];
+ values[j] = value;
}
}
}
- private static void Swap(TKey[] keys, TValue[] values, int i, int j)
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static void Swap(Span<TKey> keys, Span<TValue> values, int i, int j)
{
if (i != j)
{
}
}
- internal static void IntrospectiveSort(TKey[] keys, TValue[] values, int left, int length)
+ internal static void IntrospectiveSort(Span<TKey> keys, Span<TValue> values)
{
- Debug.Assert(keys != null);
- Debug.Assert(values != null);
- Debug.Assert(left >= 0);
- Debug.Assert(length >= 0);
- Debug.Assert(length <= keys.Length);
- Debug.Assert(length + left <= keys.Length);
- Debug.Assert(length + left <= values.Length);
-
- if (length < 2)
- return;
-
- IntroSort(keys, values, left, length + left - 1, 2 * IntrospectiveSortUtilities.FloorLog2PlusOne(length));
+ Debug.Assert(keys.Length == values.Length);
+
+ if (keys.Length > 1)
+ {
+ IntroSort(keys, values, 2 * IntrospectiveSortUtilities.FloorLog2PlusOne(keys.Length));
+ }
}
- private static void IntroSort(TKey[] keys, TValue[] values, int lo, int hi, int depthLimit)
+ private static void IntroSort(Span<TKey> keys, Span<TValue> values, int depthLimit)
{
- Debug.Assert(keys != null);
- Debug.Assert(values != null);
- Debug.Assert(lo >= 0);
- Debug.Assert(hi < keys.Length);
+ int lo = 0;
+ int hi = keys.Length - 1;
while (hi > lo)
{
{
return;
}
+
if (partitionSize == 2)
{
- SwapIfGreaterWithItems(keys, values, lo, hi);
+ SwapIfGreaterWithValues(keys, values, lo, hi);
return;
}
+
if (partitionSize == 3)
{
- SwapIfGreaterWithItems(keys, values, lo, hi - 1);
- SwapIfGreaterWithItems(keys, values, lo, hi);
- SwapIfGreaterWithItems(keys, values, hi - 1, hi);
+ SwapIfGreaterWithValues(keys, values, lo, hi - 1);
+ SwapIfGreaterWithValues(keys, values, lo, hi);
+ SwapIfGreaterWithValues(keys, values, hi - 1, hi);
return;
}
- InsertionSort(keys, values, lo, hi);
+ InsertionSort(keys[lo..(hi+1)], values[lo..(hi+1)]);
return;
}
if (depthLimit == 0)
{
- Heapsort(keys, values, lo, hi);
+ HeapSort(keys[lo..(hi+1)], values[lo..(hi+1)]);
return;
}
depthLimit--;
- int p = PickPivotAndPartition(keys, values, lo, hi);
+ int p = PickPivotAndPartition(keys[lo..(hi+1)], values[lo..(hi+1)]);
+
// Note we've already partitioned around the pivot and do not have to move the pivot again.
- IntroSort(keys, values, p + 1, hi, depthLimit);
+ IntroSort(keys[(p+1)..(hi+1)], values[(p+1)..(hi+1)], depthLimit);
hi = p - 1;
}
}
- private static int PickPivotAndPartition(TKey[] keys, TValue[] values, int lo, int hi)
+ private static int PickPivotAndPartition(Span<TKey> keys, Span<TValue> values)
{
- Debug.Assert(keys != null);
- Debug.Assert(values != null);
- Debug.Assert(lo >= 0);
- Debug.Assert(hi > lo);
- Debug.Assert(hi < keys.Length);
+ Debug.Assert(!keys.IsEmpty);
+
+ int lo = 0;
+ int hi = keys.Length - 1;
// Compute median-of-three. But also partition them, since we've done the comparison.
int middle = lo + ((hi - lo) / 2);
// Sort lo, mid and hi appropriately, then pick mid as the pivot.
- SwapIfGreaterWithItems(keys, values, lo, middle); // swap the low with the mid point
- SwapIfGreaterWithItems(keys, values, lo, hi); // swap the low with the high
- SwapIfGreaterWithItems(keys, values, middle, hi); // swap the middle with the high
+ SwapIfGreaterWithValues(keys, values, lo, middle); // swap the low with the mid point
+ SwapIfGreaterWithValues(keys, values, lo, hi); // swap the low with the high
+ SwapIfGreaterWithValues(keys, values, middle, hi); // swap the middle with the high
TKey pivot = keys[middle];
Swap(keys, values, middle, hi - 1);
return left;
}
- private static void Heapsort(TKey[] keys, TValue[] values, int lo, int hi)
+ private static void HeapSort(Span<TKey> keys, Span<TValue> values)
{
- Debug.Assert(keys != null);
- Debug.Assert(values != null);
- Debug.Assert(lo >= 0);
- Debug.Assert(hi > lo);
- Debug.Assert(hi < keys.Length);
+ Debug.Assert(!keys.IsEmpty);
+
+ int lo = 0;
+ int hi = keys.Length - 1;
int n = hi - lo + 1;
for (int i = n / 2; i >= 1; i--)
{
DownHeap(keys, values, i, n, lo);
}
+
for (int i = n; i > 1; i--)
{
Swap(keys, values, lo, lo + i - 1);
}
}
- private static void DownHeap(TKey[] keys, TValue[] values, int i, int n, int lo)
+ private static void DownHeap(Span<TKey> keys, Span<TValue> values, int i, int n, int lo)
{
- Debug.Assert(keys != null);
Debug.Assert(lo >= 0);
Debug.Assert(lo < keys.Length);
TKey d = keys[lo + i - 1];
TValue dValue = values[lo + i - 1];
- int child;
+
while (i <= n / 2)
{
- child = 2 * i;
+ int child = 2 * i;
if (child < n && (keys[lo + child - 1] == null || keys[lo + child - 1].CompareTo(keys[lo + child]) < 0))
{
child++;
}
+
if (keys[lo + child - 1] == null || keys[lo + child - 1].CompareTo(d) < 0)
break;
+
keys[lo + i - 1] = keys[lo + child - 1];
values[lo + i - 1] = values[lo + child - 1];
i = child;
}
+
keys[lo + i - 1] = d;
values[lo + i - 1] = dValue;
}
- private static void InsertionSort(TKey[] keys, TValue[] values, int lo, int hi)
+ private static void InsertionSort(Span<TKey> keys, Span<TValue> values)
{
- Debug.Assert(keys != null);
- Debug.Assert(values != null);
- Debug.Assert(lo >= 0);
- Debug.Assert(hi >= lo);
- Debug.Assert(hi <= keys.Length);
-
- int i, j;
- TKey t;
- TValue tValue;
- for (i = lo; i < hi; i++)
+ for (int i = 0; i < keys.Length - 1; i++)
{
- j = i;
- t = keys[i + 1];
- tValue = values[i + 1];
- while (j >= lo && (t == null || t.CompareTo(keys[j]) < 0))
+ TKey t = keys[i + 1];
+ TValue tValue = values[i + 1];
+
+ int j = i;
+ while (j >= 0 && (t == null || t.CompareTo(keys[j]) < 0))
{
keys[j + 1] = keys[j];
values[j + 1] = values[j];
j--;
}
+
keys[j + 1] = t;
values[j + 1] = tValue;
}