diff --git a/AdaptiveSort/AdaptiveSortExtensions.cs b/AdaptiveSort/AdaptiveSortExtensions.cs index 1253910..c3203fc 100644 --- a/AdaptiveSort/AdaptiveSortExtensions.cs +++ b/AdaptiveSort/AdaptiveSortExtensions.cs @@ -134,97 +134,73 @@ public static void AdaptiveSort(this Hashtable hashtable) // --------- Core Timsort over Span --------- - private static void Timsort(Span span) - where T : IComparable - { - int n = span.Length; - if (n <= 1) - return; - - // One reusable temporary buffer per sort. We only ever use - // the first leftSize elements when merging. - T[] temp = new T[n]; - - // 1. Sort small runs with insertion sort. - for (int i = 0; i < n; i += INSERTION_SORT_THRESHOLD) - { - int right = Math.Min(i + INSERTION_SORT_THRESHOLD - 1, n - 1); - InsertionSort(span, i, right); - } +private static void Timsort(Span span) + where T : IComparable +{ + int n = span.Length; + if (n <= 1) + return; - // 2. Bottom-up merge. - for (int size = INSERTION_SORT_THRESHOLD; size < n; size <<= 1) - { - for (int left = 0; left < n - 1; left += (size << 1)) - { - int mid = left + size - 1; - if (mid >= n - 1) - break; + // One reusable temporary buffer per sort. + T[] temp = new T[n]; - int right = Math.Min(left + (size << 1) - 1, n - 1); - MergeRuns(span, left, mid, right, temp); - } - } - } + // 1. Sort small runs with insertion sort. + for (int i = 0; i < n; i += INSERTION_SORT_THRESHOLD) + { + int right = Math.Min(i + INSERTION_SORT_THRESHOLD - 1, n - 1); + InsertionSort(span, i, right); + } - // Merge [left..mid] and [mid+1..right] within span, using temp as reusable buffer. - private static void MergeRuns(Span span, int left, int mid, int right, T[] temp) - where T : IComparable + // 2. Bottom-up merge. + for (int size = INSERTION_SORT_THRESHOLD; size < n; size <<= 1) + { + for (int left = 0; left < n - 1; left += (size << 1)) { - int leftSize = mid - left + 1; - if (leftSize <= 0) - return; + int mid = left + size - 1; + if (mid >= n - 1) + break; - Span leftSpan; - - // Blittable fast-path: stackalloc small left sides by bytes. - if (TypeTraits.IsBlittable) - { - int elementSize = Unsafe.SizeOf(); - int totalBytes = leftSize * elementSize; + int right = Math.Min(left + (size << 1) - 1, n - 1); + MergeRuns(span, left, mid, right, temp); + } + } +} - if (totalBytes <= STACKALLOC_BYTES_THRESHOLD) - { - Span buffer = stackalloc byte[totalBytes]; - leftSpan = MemoryMarshal.Cast(buffer); - } - else - { - leftSpan = temp.AsSpan(0, leftSize); - } - } - else - { - leftSpan = temp.AsSpan(0, leftSize); - } +private static void MergeRuns(Span span, int left, int mid, int right, T[] temp) + where T : IComparable +{ + int leftSize = mid - left + 1; + if (leftSize <= 0) + return; - // Copy left run into leftSpan. - for (int i = 0; i < leftSize; i++) - leftSpan[i] = span[left + i]; + // Reuse the shared temp buffer; we only touch the first leftSize elements. + Span leftSpan = temp.AsSpan(0, leftSize); - int iLeft = 0; - int iRight = mid + 1; - int k = left; + // Copy left run into leftSpan. + for (int i = 0; i < leftSize; i++) + leftSpan[i] = span[left + i]; - while (iLeft < leftSize && iRight <= right) - { - // Compare leftSpan[iLeft] with span[iRight]. - if (leftSpan[iLeft].CompareTo(span[iRight]) <= 0) - { - span[k++] = leftSpan[iLeft++]; - } - else - { - span[k++] = span[iRight++]; - } - } + int iLeft = 0; + int iRight = mid + 1; + int k = left; - // Copy remaining left elements. - while (iLeft < leftSize) - { - span[k++] = leftSpan[iLeft++]; - } + while (iLeft < leftSize && iRight <= right) + { + if (leftSpan[iLeft].CompareTo(span[iRight]) <= 0) + { + span[k++] = leftSpan[iLeft++]; + } + else + { + span[k++] = span[iRight++]; } + } + + while (iLeft < leftSize) + { + span[k++] = leftSpan[iLeft++]; + } +} // --------- Insertion sort over Span ---------