diff --git a/libc/str/intsort.c b/libc/str/intsort.c index 70b785ec7..620f31f04 100644 --- a/libc/str/intsort.c +++ b/libc/str/intsort.c @@ -19,20 +19,36 @@ #include "libc/intrin/strace.internal.h" #include "libc/runtime/runtime.h" -static void _intsorter(int *A, size_t n) { - int t, p; - size_t i, j; - if (n < 2) return; - for (p = A[n / 2], i = 0, j = n - 1;; i++, j--) { - while (A[i] < p) i++; - while (A[j] > p) j--; - if (i >= j) break; +static inline void InsertionSort(int *A, long n) { + long i, j, t; + for (i = 1; i < n; i++) { t = A[i]; - A[i] = A[j]; - A[j] = t; + j = i - 1; + while (j >= 0 && A[j] > t) { + A[j + 1] = A[j]; + j = j - 1; + } + A[j + 1] = t; + } +} + +static void IntSort(int *A, long n) { + int t, p; + long i, j; + if (n <= 32) { + InsertionSort(A, n); + } else { + for (p = A[n >> 1], i = 0, j = n - 1;; i++, j--) { + while (A[i] < p) i++; + while (A[j] > p) j--; + if (i >= j) break; + t = A[i]; + A[i] = A[j]; + A[j] = t; + } + IntSort(A, i); + IntSort(A + i, n - i); } - _intsorter(A, i); - _intsorter(A + i, n - i); } /** @@ -40,7 +56,7 @@ static void _intsorter(int *A, size_t n) { * @see djbsort */ void _intsort(int *A, size_t n) { - _intsorter(A, n); + IntSort(A, n); if (n > 1000) { STRACE("_intsort(%p, %'zu)", A, n); } diff --git a/libc/str/longsort.c b/libc/str/longsort.c index cd3f4e60b..ace538c60 100644 --- a/libc/str/longsort.c +++ b/libc/str/longsort.c @@ -19,20 +19,35 @@ #include "libc/intrin/strace.internal.h" #include "libc/runtime/runtime.h" -static void _longsorter(long *A, size_t n) { - long t, p; - size_t i, j; - if (n < 2) return; - for (p = A[n / 2], i = 0, j = n - 1;; i++, j--) { - while (A[i] < p) i++; - while (A[j] > p) j--; - if (i >= j) break; +static inline void InsertionSort(long *A, long n) { + long i, j, t; + for (i = 1; i < n; i++) { t = A[i]; - A[i] = A[j]; - A[j] = t; + j = i - 1; + while (j >= 0 && A[j] > t) { + A[j + 1] = A[j]; + j = j - 1; + } + A[j + 1] = t; + } +} + +static void LongSort(long *A, long n) { + long t, p, i, j; + if (n <= 32) { + InsertionSort(A, n); + } else { + for (p = A[n >> 1], i = 0, j = n - 1;; i++, j--) { + while (A[i] < p) i++; + while (A[j] > p) j--; + if (i >= j) break; + t = A[i]; + A[i] = A[j]; + A[j] = t; + } + LongSort(A, i); + LongSort(A + i, n - i); } - _longsorter(A, i); - _longsorter(A + i, n - i); } /** @@ -43,7 +58,7 @@ static void _longsorter(long *A, size_t n) { * */ void _longsort(long *A, size_t n) { - _longsorter(A, n); + LongSort(A, n); if (n > 1000) { STRACE("_longsort(%p, %'zu)", A, n); } diff --git a/test/libc/str/longsort_test.c b/test/libc/str/longsort_test.c index c8048cfc3..59beb0723 100644 --- a/test/libc/str/longsort_test.c +++ b/test/libc/str/longsort_test.c @@ -53,3 +53,32 @@ BENCH(_longsort, bench) { EZBENCH2("qsort", memcpy(p2, p1, n * sizeof(long)), qsort(p2, n, sizeof(long), CompareLong)); } + +int CompareInt(const void *a, const void *b) { + const int *x = a; + const int *y = b; + if (*x < *y) return -1; + if (*x > *y) return +1; + return 0; +} + +TEST(_intsort, test) { + size_t n = 5000; + int *a = gc(calloc(n, sizeof(int))); + int *b = gc(calloc(n, sizeof(int))); + rngset(a, n * sizeof(int), 0, 0); + memcpy(b, a, n * sizeof(int)); + qsort(a, n, sizeof(int), CompareInt); + _intsort(b, n); + ASSERT_EQ(0, memcmp(b, a, n * sizeof(int))); +} + +BENCH(_intsort, bench) { + size_t n = 1000; + int *p1 = gc(malloc(n * sizeof(int))); + int *p2 = gc(malloc(n * sizeof(int))); + rngset(p1, n * sizeof(int), 0, 0); + EZBENCH2("_intsort", memcpy(p2, p1, n * sizeof(int)), _intsort(p2, n)); + EZBENCH2("qsort", memcpy(p2, p1, n * sizeof(int)), + qsort(p2, n, sizeof(int), CompareInt)); +}