diff --git a/CMakeLists.txt b/CMakeLists.txt index b404408..12d00db 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -149,6 +149,7 @@ set(SOURCES src/libc/stdlib/ldiv.c src/libc/stdlib/llabs.c src/libc/stdlib/lldiv.c + src/libc/stdlib/qsort.c src/libc/stdlib/reallocarray.c src/libc/stdlib/strto_fp.c src/libc/stdlib/strto_int.c diff --git a/STATUS b/STATUS index 64e0cf8..baa03f6 100644 --- a/STATUS +++ b/STATUS @@ -115,7 +115,8 @@ DONE: Function/symbol/macro is defined, builds, links, and is tested 7.20.4.4 _Exit: DONE (gint only) ! 7.20.4.5 getenv: TODO ! 7.20.4.6 system: TODO -! 7.20.5 Searching and sorting utilities: TODO +! 7.20.5.1 bsearch: TODO +! 7.20.5.2 qsort: TEST 7.20.6.1 abs, labs, llabs: DONE 7.20.6.2 div, ldiv, lldiv: DONE ! 7.20.7 Multibyte/wide character conversion functions: TODO diff --git a/src/libc/stdlib/qsort.c b/src/libc/stdlib/qsort.c new file mode 100644 index 0000000..8501187 --- /dev/null +++ b/src/libc/stdlib/qsort.c @@ -0,0 +1,45 @@ +#include +#include + +typedef int comp_func(void const *left, void const *right); + +static int partition(void *base, size_t size, comp_func *compare, + int low, int high) +{ + #define AT(n) (base + size * (n)) + + __attribute__((aligned(4))) char tmp[size], pivot[size]; + memcpy(pivot, AT((low + high) >> 1), size); + + int i = low - 1; + int j = high + 1; + + while(1) { + do i++; + while(compare(AT(i), pivot) < 0); + + do j--; + while(compare(AT(j), pivot) > 0); + + if(i >= j) return j; + + memcpy(tmp, AT(i), size); + memcpy(AT(i), AT(j), size); + memcpy(AT(j), tmp, size); + } +} + +static void sort(void *base, size_t size, comp_func *compare, + int low, int high) +{ + if(low >= high) return; + + int p = partition(base, size, compare, low, high); + sort(base, size, compare, low, p); + sort(base, size, compare, p+1, high); +} + +void qsort(void *base, size_t n, size_t size, comp_func *compare) +{ + sort(base, size, compare, 0, n-1); +}