internal sealed partial class GenericArraySortHelper<T>
where T : IComparable<T>
{
// Do not add a constructor to this class because ArraySortHelper<T>.CreateSortHelper will not execute it
#region IArraySortHelper<T> Members
public void Sort(Span<T> keys, IComparer<T>? comparer)
{
try
{
if (comparer == null || comparer == Comparer<T>.Default)
{
if (keys.Length > 1)
{
// For floating-point, do a pre-pass to move all NaNs to the beginning
// so that we can do an optimized comparison as part of the actual sort
// on the remainder of the values.
if (typeof(T) == typeof(double) ||
typeof(T) == typeof(float) ||
typeof(T) == typeof(Half))
{
int nanLeft = SortUtils.MoveNansToFront(keys, default(Span<byte>));
if (nanLeft == keys.Length)
{
return;
}
keys = keys.Slice(nanLeft);
}
IntroSort(keys, 2 * (BitOperations.Log2((uint)keys.Length) + 1));
}
}
else
{
ArraySortHelper<T>.IntrospectiveSort(keys, comparer.Compare);
}
}
catch (IndexOutOfRangeException)
{
ThrowHelper.ThrowArgumentException_BadComparer(comparer);
}
catch (Exception e)
{
ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_IComparerFailed, e);
}
}
private static int PickPivotAndPartition(Span<TKey> keys, Span<TValue> values)
{
Debug.Assert(keys.Length >= Array.IntrosortSizeThreshold);
int hi = keys.Length - 1;
// Compute median-of-three. But also partition them, since we've done the comparison.
int middle = hi >> 1;
// Sort lo, mid and hi appropriately, then pick mid as the pivot.
SwapIfGreaterWithValues(keys, values, 0, middle); // swap the low with the mid point
SwapIfGreaterWithValues(keys, values, 0, 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);
int left = 0, right = hi - 1; // We already partitioned lo and hi and put the pivot in hi - 1. And we pre-increment & decrement below.
while (left < right)
{
if (pivot == null)
{
while (left < (hi - 1) && keys[++left] == null) ;
while (right > 0 && keys[--right] != null) ;
}
else
{
while (GreaterThan(ref pivot, ref keys[++left])) ;
while (LessThan(ref pivot, ref keys[--right])) ;
}
if (left >= right)
break;
Swap(keys, values, left, right);
}
// Put pivot in the right location.
if (left != hi - 1)
{
Swap(keys, values, left, hi - 1);
}
return left;
}