diff --git a/libc/stdlib/qsort.c b/libc/stdlib/qsort.c index af40359c..34399d9b 100644 --- a/libc/stdlib/qsort.c +++ b/libc/stdlib/qsort.c @@ -1,3 +1,4 @@ +#include #include #include #include @@ -7,19 +8,46 @@ extern char * _argv_0; extern int __libc_debug; -void qsort(void * base, size_t nmemb, size_t size, int (*compar)(const void *, const void *)) { - if (!nmemb) return; - if (!size) return; - for (size_t i = 0; i < nmemb-1; ++i) { - for (size_t j = 0; j < nmemb-1; ++j) { - void * left = (char *)base + size * j; - void * right = (char *)base + size * (j + 1); - if (compar(left,right) > 0) { - char tmp[size]; - memcpy(tmp, right, size); - memcpy(right, left, size); - memcpy(left, tmp, size); +struct SortableArray { + void * data; + size_t size; + int (*func)(const void *, const void *); +}; + +static ssize_t partition(struct SortableArray * array, ssize_t lo, ssize_t hi) { + char pivot[array->size]; + memcpy(pivot, (char *)array->data + array->size * hi, array->size); + ssize_t i = lo - 1; + for (ssize_t j = lo; j <= hi; ++j) { + uint8_t * obj_j = (uint8_t *)array->data + array->size * j; + if (array->func(obj_j, pivot) <= 0) { + i++; + if (j != i) { + uint8_t * obj_i = (uint8_t *)array->data + array->size * i; + for (size_t x = 0; x < array->size; ++x) { + obj_j[x] ^= obj_i[x]; + obj_i[x] ^= obj_j[x]; + obj_j[x] ^= obj_i[x]; + } } } } + return i; +} + +static void quicksort(struct SortableArray * array, ssize_t lo, ssize_t hi) { + if (lo >= 0 && hi >= 0) { + if (lo < hi) { + ssize_t pivot = partition(array, lo, hi); + quicksort(array, lo, pivot - 1); + quicksort(array, pivot + 1, hi); + } + } +} + +void qsort(void * base, size_t nmemb, size_t size, int (*compar)(const void *, const void *)) { + if (nmemb < 2) return; + if (!size) return; + struct SortableArray array = {base,size,compar}; + quicksort(&array, 0, nmemb - 1); }