From 660722490fdb29e9e43a5e7942173ef3baf01249 Mon Sep 17 00:00:00 2001
From: David Sehnal <david.sehnal@gmail.com>
Date: Mon, 23 Oct 2017 13:57:13 +0200
Subject: [PATCH] specialized array sort is back (because ordered sets need it)

---
 src/structure/collections/sort.ts | 62 ++++++++++++++++++++++++++++++-
 1 file changed, 61 insertions(+), 1 deletion(-)

diff --git a/src/structure/collections/sort.ts b/src/structure/collections/sort.ts
index 92ac607ac..86525401a 100644
--- a/src/structure/collections/sort.ts
+++ b/src/structure/collections/sort.ts
@@ -83,12 +83,72 @@ function quickSort(ctx: Ctx, low: number, high: number) {
     }
 }
 
+function partitionArrayAsc(data: number[], parts: number[], l: number, r: number) {
+    let equals = l + 1, tail = r;
+
+    // move the median to the 1st spot
+    arraySwap(data, l, medianPivotIndex(data, arrayLess, l, r));
+    const pivot = data[l];
+
+    while (data[tail] > pivot) { --tail; }
+    for (let i = l + 1; i <= tail; i++) {
+        const v = data[i];
+        if (v > pivot) {
+            arraySwap(data, i, tail);
+            --tail;
+            while (data[tail] > pivot) { --tail; }
+            i--;
+        } else if (v === pivot) {
+            arraySwap(data, i, equals);
+            ++equals;
+        }
+    }
+
+    // move all medians to the correct spots
+    for (let i = l; i < equals; i++) { arraySwap(data, i, l + tail - i); }
+    parts[0] = tail - equals + l + 1;
+    parts[1] = tail;
+}
+
+function insertionSortArrayAsc(data: number[], start: number, end: number) {
+    for (let i = start + 1; i <= end; i++) {
+        const key = data[i];
+        let j = i - 1;
+        while (j >= start && data[j] > key) {
+            data[j + 1] = data[j];
+            j = j - 1;
+        }
+        data[j + 1] = key;
+    }
+}
+
+function quickSortArrayAsc(data: number[], parts: number[], low: number, high: number) {
+    while (low < high) {
+        if (high - low < 16) {
+            insertionSortArrayAsc(data, low, high);
+            return;
+        }
+
+        partitionArrayAsc(data, parts, low, high);
+        const li = parts[0], ri = parts[1];
+
+        if (li - low < high - ri) {
+            quickSortArrayAsc(data, parts, low, li - 1);
+            low = ri + 1;
+        } else {
+            quickSortArrayAsc(data, parts, ri + 1, high);
+            high = li - 1;
+        }
+    }
+}
+
 export function sortArray(data: ArrayLike<number>, cmp: Comparer<ArrayLike<number>> = arrayLess): ArrayLike<number> {
     return sortArrayRange(data, 0, data.length, cmp);
 }
 
 export function sortArrayRange(data: ArrayLike<number>, start: number, end: number, cmp: Comparer<ArrayLike<number>> = arrayLess): ArrayLike<number> {
-    quickSort({ data, cmp, swap: arraySwap, parts: [0, 0] }, start, end - 1);
+    if (cmp === arrayLess) quickSortArrayAsc(data as any, [0, 0], start, end - 1);
+    else quickSort({ data, cmp, swap: arraySwap, parts: [0, 0] }, start, end - 1);
     return data;
 }
 
-- 
GitLab