diff --git a/libluna/CMakeLists.txt b/libluna/CMakeLists.txt index a775b140..3d1f3cee 100644 --- a/libluna/CMakeLists.txt +++ b/libluna/CMakeLists.txt @@ -5,6 +5,7 @@ file(GLOB HEADERS include/luna/*.h) set(FREESTANDING_SOURCES ${HEADERS} src/Format.cpp + src/Sort.cpp src/NumberParsing.cpp src/CString.cpp src/CPath.cpp diff --git a/libluna/include/luna/Sort.h b/libluna/include/luna/Sort.h new file mode 100644 index 00000000..16c1ea31 --- /dev/null +++ b/libluna/include/luna/Sort.h @@ -0,0 +1,26 @@ +#pragma once +#include + +typedef int (*compar_t)(const void*, const void*); + +void c_quicksort(void* base, usize nmemb, usize size, compar_t compar); + +template void sort(T* base, usize nmemb, int (*compar)(const T*, const T*)) +{ + return c_quicksort(base, nmemb, sizeof(T), (compar_t)compar); +} + +template void sort(T* base, usize nmemb, compar_t compar) +{ + return c_quicksort(base, nmemb, sizeof(T), compar); +} + +template void sort(T* begin, T* end, int (*compar)(const T*, const T*)) +{ + return c_quicksort(begin, end - begin, sizeof(T), (compar_t)compar); +} + +template void sort(T* begin, T* end, compar_t compar) +{ + return c_quicksort(begin, end - begin, sizeof(T), compar); +} diff --git a/libluna/src/Sort.cpp b/libluna/src/Sort.cpp new file mode 100644 index 00000000..4a4da6b4 --- /dev/null +++ b/libluna/src/Sort.cpp @@ -0,0 +1,53 @@ +#include +#include + +static void swap_sized(void* ptr1, void* ptr2, usize size) +{ + char* x = (char*)ptr1; + char* y = (char*)ptr2; + + while (size--) + { + char t = *x; + *x = *y; + *y = t; + x += 1; + y += 1; + } +} + +static usize partition(void* base, usize start, usize end, usize size, compar_t compar) +{ + auto atindex = [&base, &size](usize index) { return offset_ptr(base, index * size); }; + + void* pivot = atindex(end); + usize i = (start - 1); + + for (usize j = start; j <= end - 1; j++) + { + if (compar(atindex(j), pivot) < 0) + { + i++; + swap_sized(atindex(i), atindex(j), size); + } + } + + swap_sized(atindex(i + 1), pivot, size); + return i + 1; +} + +static void quicksort_impl(void* base, usize start, usize end, usize size, compar_t compar) +{ + if (start < end) + { + usize pivot = partition(base, start, end, size, compar); + if ((end - start) < 2) return; + quicksort_impl(base, start, pivot - 1, size, compar); + quicksort_impl(base, pivot + 1, end, size, compar); + } +} + +void c_quicksort(void* base, usize nmemb, usize size, compar_t compar) +{ + quicksort_impl(base, 0, nmemb - 1, size, compar); +}