Issue 193 and issue 194: Always use heapsort instead of quicksort.

The quicksort implementation behaves badly when presented with
non-deterministic comparison functions.

The heapsort is more robust and has fewer edge cases to worry about
in the face of an adversarial comparison function.
This commit is contained in:
Tor Andersson
2025-01-03 13:25:06 +01:00
parent 02147f5a9f
commit 91abee5641

View File

@@ -346,8 +346,6 @@ static void Ap_sort_swap(js_State *J, int idx_a, int idx_b)
} }
} }
#if JS_HEAPSORT
/* A bottom-up/bouncing heapsort implementation */ /* A bottom-up/bouncing heapsort implementation */
static int Ap_sort_leaf(js_State *J, int i, int end) static int Ap_sort_leaf(js_State *J, int i, int end)
@@ -390,46 +388,6 @@ static void Ap_sort_heapsort(js_State *J, int n)
} }
} }
#else
static int Ap_sort_quicksort_partition(js_State *J, int a, int b)
{
int pivot = (a + b) >> 1;
while (a <= b) {
while (Ap_sort_cmp(J, a, pivot) < 0)
++a;
while (Ap_sort_cmp(J, b, pivot) > 0)
--b;
if (a <= b) {
Ap_sort_swap(J, a, b);
++a;
--b;
}
}
return a;
}
static void Ap_sort_quicksort(js_State *J, int a, int b)
{
int i, j, m;
/* insertion sort small fragments */
if (b - a < 8) {
for (i = a+1; i < b; ++i)
for (j = i; j > a && Ap_sort_cmp(J, j-1, j) > 0; --j)
Ap_sort_swap(J, j-1, j);
return;
}
m = Ap_sort_quicksort_partition(J, a, b);
if (a < m - 1)
Ap_sort_quicksort(J, a, m - 1);
if (m < b)
Ap_sort_quicksort(J, m, b);
}
#endif
static void Ap_sort(js_State *J) static void Ap_sort(js_State *J)
{ {
int len; int len;
@@ -446,12 +404,7 @@ static void Ap_sort(js_State *J)
if (len >= INT_MAX) if (len >= INT_MAX)
js_rangeerror(J, "array is too large to sort"); js_rangeerror(J, "array is too large to sort");
#if JS_HEAPSORT
Ap_sort_heapsort(J, len); Ap_sort_heapsort(J, len);
#else
Ap_sort_quicksort(J, 0, len - 1);
#endif
js_copy(J, 0); js_copy(J, 0);
} }