From a6d2da8b9d7be19816dd4c76b02016c19618c1be Mon Sep 17 00:00:00 2001 From: lntue <35648136+lntue@users.noreply.github.com> Date: Tue, 16 Jul 2024 08:13:25 -0400 Subject: [PATCH] [libc][stdlib] Implement heap sort. (#98582) --- .../modules/LLVMLibCCompileOptionRules.cmake | 13 +- libc/config/baremetal/config.json | 5 + libc/config/config.json | 6 + libc/docs/configure.rst | 2 + libc/src/stdlib/CMakeLists.txt | 4 + libc/src/stdlib/heap_sort.h | 61 +++ libc/src/stdlib/qsort.cpp | 7 +- libc/src/stdlib/qsort_data.h | 102 +++++ libc/src/stdlib/qsort_r.cpp | 6 +- libc/src/stdlib/qsort_util.h | 150 +------ libc/src/stdlib/quick_sort.h | 78 ++++ libc/test/src/stdlib/CMakeLists.txt | 27 +- libc/test/src/stdlib/SortingTest.h | 377 ++++++++++++++++++ libc/test/src/stdlib/heap_sort_test.cpp | 16 + libc/test/src/stdlib/qsort_test.cpp | 258 +----------- libc/test/src/stdlib/quick_sort_test.cpp | 16 + .../llvm-project-overlay/libc/BUILD.bazel | 8 +- .../libc/test/src/stdlib/BUILD.bazel | 25 ++ 18 files changed, 768 insertions(+), 393 deletions(-) create mode 100644 libc/src/stdlib/heap_sort.h create mode 100644 libc/src/stdlib/qsort_data.h create mode 100644 libc/src/stdlib/quick_sort.h create mode 100644 libc/test/src/stdlib/SortingTest.h create mode 100644 libc/test/src/stdlib/heap_sort_test.cpp create mode 100644 libc/test/src/stdlib/quick_sort_test.cpp diff --git a/libc/cmake/modules/LLVMLibCCompileOptionRules.cmake b/libc/cmake/modules/LLVMLibCCompileOptionRules.cmake index 253da4ae890e5d..62e16d52cb3ea0 100644 --- a/libc/cmake/modules/LLVMLibCCompileOptionRules.cmake +++ b/libc/cmake/modules/LLVMLibCCompileOptionRules.cmake @@ -49,10 +49,21 @@ function(_get_compile_options_from_flags output_var) set(${output_var} ${compile_options} PARENT_SCOPE) endfunction(_get_compile_options_from_flags) +function(_get_compile_options_from_config output_var) + set(config_options "") + + if(LIBC_CONF_QSORT_IMPL) + list(APPEND config_options "-DLIBC_QSORT_IMPL=${LIBC_CONF_QSORT_IMPL}") + endif() + + set(${output_var} ${config_options} PARENT_SCOPE) +endfunction(_get_compile_options_from_config) + function(_get_common_compile_options output_var flags) _get_compile_options_from_flags(compile_flags ${flags}) + _get_compile_options_from_config(config_flags) - set(compile_options ${LIBC_COMPILE_OPTIONS_DEFAULT} ${compile_flags}) + set(compile_options ${LIBC_COMPILE_OPTIONS_DEFAULT} ${compile_flags} ${config_flags}) if(LLVM_COMPILER_IS_GCC_COMPATIBLE) list(APPEND compile_options "-fpie") diff --git a/libc/config/baremetal/config.json b/libc/config/baremetal/config.json index b7426dd341d977..12f4c2aa3a805c 100644 --- a/libc/config/baremetal/config.json +++ b/libc/config/baremetal/config.json @@ -22,5 +22,10 @@ "LIBC_CONF_FREELIST_MALLOC_BUFFER_SIZE": { "value": 102400 } + }, + "qsort": { + "LIBC_CONF_QSORT_IMPL": { + "value": "LIBC_QSORT_HEAP_SORT" + } } } diff --git a/libc/config/config.json b/libc/config/config.json index 3a9c08d195445a..94bfed894c173c 100644 --- a/libc/config/config.json +++ b/libc/config/config.json @@ -82,5 +82,11 @@ "value": 0, "doc": "Configures optimizations for math functions. Values accepted are LIBC_MATH_SKIP_ACCURATE_PASS, LIBC_MATH_SMALL_TABLES, LIBC_MATH_NO_ERRNO, LIBC_MATH_NO_EXCEPT, and LIBC_MATH_FAST." } + }, + "qsort": { + "LIBC_CONF_QSORT_IMPL": { + "value": "LIBC_QSORT_QUICK_SORT", + "doc": "Configures sorting algorithm for qsort and qsort_r. Values accepted are LIBC_QSORT_QUICK_SORT, LIBC_QSORT_HEAP_SORT." + } } } diff --git a/libc/docs/configure.rst b/libc/docs/configure.rst index 24ef2ef189ffd9..dfb35f6a6611a4 100644 --- a/libc/docs/configure.rst +++ b/libc/docs/configure.rst @@ -44,6 +44,8 @@ to learn about the defaults for your platform and target. - ``LIBC_CONF_RAW_MUTEX_DEFAULT_SPIN_COUNT``: Default number of spins before blocking if a mutex is in contention (default to 100). - ``LIBC_CONF_RWLOCK_DEFAULT_SPIN_COUNT``: Default number of spins before blocking if a rwlock is in contention (default to 100). - ``LIBC_CONF_TIMEOUT_ENSURE_MONOTONICITY``: Automatically adjust timeout to CLOCK_MONOTONIC (default to true). POSIX API may require CLOCK_REALTIME, which can be unstable and leading to unexpected behavior. This option will convert the real-time timestamp to monotonic timestamp relative to the time of call. +* **"qsort" options** + - ``LIBC_CONF_QSORT_IMPL``: Configures sorting algorithm for qsort and qsort_r. Values accepted are LIBC_QSORT_QUICK_SORT, LIBC_QSORT_HEAP_SORT. * **"scanf" options** - ``LIBC_CONF_SCANF_DISABLE_FLOAT``: Disable parsing floating point values in scanf and friends. - ``LIBC_CONF_SCANF_DISABLE_INDEX_MODE``: Disable index mode in the scanf format string. diff --git a/libc/src/stdlib/CMakeLists.txt b/libc/src/stdlib/CMakeLists.txt index 7b7e55db391fae..513f6ad723d564 100644 --- a/libc/src/stdlib/CMakeLists.txt +++ b/libc/src/stdlib/CMakeLists.txt @@ -258,9 +258,13 @@ add_entrypoint_object( add_header_library( qsort_util HDRS + qsort_data.h qsort_util.h + heap_sort.h + quick_sort.h DEPENDS libc.include.stdlib + libc.src.__support.CPP.cstddef ) add_entrypoint_object( diff --git a/libc/src/stdlib/heap_sort.h b/libc/src/stdlib/heap_sort.h new file mode 100644 index 00000000000000..ccb9ec5f82149e --- /dev/null +++ b/libc/src/stdlib/heap_sort.h @@ -0,0 +1,61 @@ +//===-- Implementation of heap sort -----------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC_STDLIB_HEAP_SORT_H +#define LLVM_LIBC_SRC_STDLIB_HEAP_SORT_H + +#include "src/__support/CPP/cstddef.h" +#include "src/stdlib/qsort_data.h" + +namespace LIBC_NAMESPACE_DECL { +namespace internal { + +// A simple in-place heapsort implementation. +// Follow the implementation in https://en.wikipedia.org/wiki/Heapsort. + +LIBC_INLINE void heap_sort(const Array &array) { + size_t end = array.size(); + size_t start = end / 2; + + auto left_child = [](size_t i) -> size_t { return 2 * i + 1; }; + + while (end > 1) { + if (start > 0) { + // Select the next unheapified element to sift down. + --start; + } else { + // Extract the max element of the heap, moving a leaf to root to be sifted + // down. + --end; + array.swap(0, end); + } + + // Sift start down the heap. + size_t root = start; + while (left_child(root) < end) { + size_t child = left_child(root); + // If there are two children, set child to the greater. + if (child + 1 < end && + array.elem_compare(child, array.get(child + 1)) < 0) + ++child; + + // If the root is less than the greater child + if (array.elem_compare(root, array.get(child)) >= 0) + break; + + // Swap the root with the greater child and continue sifting down. + array.swap(root, child); + root = child; + } + } +} + +} // namespace internal +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC_STDLIB_HEAP_SORT_H diff --git a/libc/src/stdlib/qsort.cpp b/libc/src/stdlib/qsort.cpp index 048e63ab214ed3..65a63c239f5c0d 100644 --- a/libc/src/stdlib/qsort.cpp +++ b/libc/src/stdlib/qsort.cpp @@ -21,8 +21,11 @@ LLVM_LIBC_FUNCTION(void, qsort, if (array == nullptr || array_size == 0 || elem_size == 0) return; internal::Comparator c(compare); - internal::quicksort(internal::Array(reinterpret_cast(array), - array_size, elem_size, c)); + + auto arr = internal::Array(reinterpret_cast(array), array_size, + elem_size, c); + + internal::sort(arr); } } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/stdlib/qsort_data.h b/libc/src/stdlib/qsort_data.h new file mode 100644 index 00000000000000..db045332708ae6 --- /dev/null +++ b/libc/src/stdlib/qsort_data.h @@ -0,0 +1,102 @@ +//===-- Data structures for sorting routines --------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC_STDLIB_QSORT_DATA_H +#define LLVM_LIBC_SRC_STDLIB_QSORT_DATA_H + +#include "src/__support/CPP/cstddef.h" +#include "src/__support/macros/config.h" + +#include + +namespace LIBC_NAMESPACE_DECL { +namespace internal { + +using Compare = int(const void *, const void *); +using CompareWithState = int(const void *, const void *, void *); + +enum class CompType { COMPARE, COMPARE_WITH_STATE }; + +struct Comparator { + union { + Compare *comp_func; + CompareWithState *comp_func_r; + }; + const CompType comp_type; + + void *arg; + + Comparator(Compare *func) + : comp_func(func), comp_type(CompType::COMPARE), arg(nullptr) {} + + Comparator(CompareWithState *func, void *arg_val) + : comp_func_r(func), comp_type(CompType::COMPARE_WITH_STATE), + arg(arg_val) {} + +#if defined(__clang__) + // Recent upstream changes to -fsanitize=function find more instances of + // function type mismatches. One case is with the comparator passed to this + // class. Libraries will tend to pass comparators that take pointers to + // varying types while this comparator expects to accept const void pointers. + // Ideally those tools would pass a function that strictly accepts const + // void*s to avoid UB, or would use qsort_r to pass their own comparator. + [[clang::no_sanitize("function")]] +#endif + int comp_vals(const void *a, const void *b) const { + if (comp_type == CompType::COMPARE) { + return comp_func(a, b); + } else { + return comp_func_r(a, b, arg); + } + } +}; + +class Array { + uint8_t *array; + size_t array_size; + size_t elem_size; + Comparator compare; + +public: + Array(uint8_t *a, size_t s, size_t e, Comparator c) + : array(a), array_size(s), elem_size(e), compare(c) {} + + uint8_t *get(size_t i) const { return array + i * elem_size; } + + void swap(size_t i, size_t j) const { + uint8_t *elem_i = get(i); + uint8_t *elem_j = get(j); + for (size_t b = 0; b < elem_size; ++b) { + uint8_t temp = elem_i[b]; + elem_i[b] = elem_j[b]; + elem_j[b] = temp; + } + } + + int elem_compare(size_t i, const uint8_t *other) const { + // An element must compare equal to itself so we don't need to consult the + // user provided comparator. + if (get(i) == other) + return 0; + return compare.comp_vals(get(i), other); + } + + size_t size() const { return array_size; } + + // Make an Array starting at index |i| and size |s|. + Array make_array(size_t i, size_t s) const { + return Array(get(i), s, elem_size, compare); + } +}; + +using SortingRoutine = void(const Array &); + +} // namespace internal +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC_STDLIB_QSORT_DATA_H diff --git a/libc/src/stdlib/qsort_r.cpp b/libc/src/stdlib/qsort_r.cpp index efbe5ad484b0ea..bf61a40e847341 100644 --- a/libc/src/stdlib/qsort_r.cpp +++ b/libc/src/stdlib/qsort_r.cpp @@ -22,8 +22,10 @@ LLVM_LIBC_FUNCTION(void, qsort_r, if (array == nullptr || array_size == 0 || elem_size == 0) return; internal::Comparator c(compare, arg); - internal::quicksort(internal::Array(reinterpret_cast(array), - array_size, elem_size, c)); + auto arr = internal::Array(reinterpret_cast(array), array_size, + elem_size, c); + + internal::sort(arr); } } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/stdlib/qsort_util.h b/libc/src/stdlib/qsort_util.h index 3a9cc4b8669f86..d42adde06d9762 100644 --- a/libc/src/stdlib/qsort_util.h +++ b/libc/src/stdlib/qsort_util.h @@ -9,145 +9,29 @@ #ifndef LLVM_LIBC_SRC_STDLIB_QSORT_UTIL_H #define LLVM_LIBC_SRC_STDLIB_QSORT_UTIL_H -#include "src/__support/macros/attributes.h" -#include "src/__support/macros/config.h" -#include -#include +#include "src/stdlib/heap_sort.h" +#include "src/stdlib/quick_sort.h" -namespace LIBC_NAMESPACE_DECL { -namespace internal { - -// A simple quicksort implementation using the Hoare partition scheme. - -using Compare = int(const void *, const void *); -using CompareWithState = int(const void *, const void *, void *); - -enum class CompType { COMPARE, COMPARE_WITH_STATE }; - -struct Comparator { - union { - Compare *comp_func; - CompareWithState *comp_func_r; - }; - const CompType comp_type; +#define LIBC_QSORT_QUICK_SORT 1 +#define LIBC_QSORT_HEAP_SORT 2 - void *arg; +#ifndef LIBC_QSORT_IMPL +#define LIBC_QSORT_IMPL LIBC_QSORT_QUICK_SORT +#endif // LIBC_QSORT_IMPL - Comparator(Compare *func) - : comp_func(func), comp_type(CompType::COMPARE), arg(nullptr) {} - - Comparator(CompareWithState *func, void *arg_val) - : comp_func_r(func), comp_type(CompType::COMPARE_WITH_STATE), - arg(arg_val) {} - -#if defined(__clang__) - // Recent upstream changes to -fsanitize=function find more instances of - // function type mismatches. One case is with the comparator passed to this - // class. Libraries will tend to pass comparators that take pointers to - // varying types while this comparator expects to accept const void pointers. - // Ideally those tools would pass a function that strictly accepts const - // void*s to avoid UB, or would use qsort_r to pass their own comparator. - [[clang::no_sanitize("function")]] +#if (LIBC_QSORT_IMPL != LIBC_QSORT_QUICK_SORT && \ + LIBC_QSORT_IMPL != LIBC_QSORT_HEAP_SORT) +#error "LIBC_QSORT_IMPL is not recognized." #endif - int comp_vals(const void *a, const void *b) const { - if (comp_type == CompType::COMPARE) { - return comp_func(a, b); - } else { - return comp_func_r(a, b, arg); - } - } -}; - -class Array { - uint8_t *array; - size_t array_size; - size_t elem_size; - Comparator compare; - -public: - Array(uint8_t *a, size_t s, size_t e, Comparator c) - : array(a), array_size(s), elem_size(e), compare(c) {} - - uint8_t *get(size_t i) const { return array + i * elem_size; } - - void swap(size_t i, size_t j) const { - uint8_t *elem_i = get(i); - uint8_t *elem_j = get(j); - for (size_t b = 0; b < elem_size; ++b) { - uint8_t temp = elem_i[b]; - elem_i[b] = elem_j[b]; - elem_j[b] = temp; - } - } - int elem_compare(size_t i, const uint8_t *other) const { - // An element must compare equal to itself so we don't need to consult the - // user provided comparator. - if (get(i) == other) - return 0; - return compare.comp_vals(get(i), other); - } - - size_t size() const { return array_size; } - - // Make an Array starting at index |i| and size |s|. - Array make_array(size_t i, size_t s) const { - return Array(get(i), s, elem_size, compare); - } -}; - -static size_t partition(const Array &array) { - const size_t array_size = array.size(); - size_t pivot_index = array_size / 2; - uint8_t *pivot = array.get(pivot_index); - size_t i = 0; - size_t j = array_size - 1; - - while (true) { - int compare_i, compare_j; - - while ((compare_i = array.elem_compare(i, pivot)) < 0) - ++i; - while ((compare_j = array.elem_compare(j, pivot)) > 0) - --j; - - // At some point i will crossover j so we will definitely break out of - // this while loop. - if (i >= j) - return j + 1; - - array.swap(i, j); - - // The pivot itself might have got swapped so we will update the pivot. - if (i == pivot_index) { - pivot = array.get(j); - pivot_index = j; - } else if (j == pivot_index) { - pivot = array.get(i); - pivot_index = i; - } - - if (compare_i == 0 && compare_j == 0) { - // If we do not move the pointers, we will end up with an - // infinite loop as i and j will be stuck without advancing. - ++i; - --j; - } - } -} +namespace LIBC_NAMESPACE_DECL { +namespace internal { -LIBC_INLINE void quicksort(const Array &array) { - const size_t array_size = array.size(); - if (array_size <= 1) - return; - size_t split_index = partition(array); - if (array_size <= 2) { - // The partition operation sorts the two element array. - return; - } - quicksort(array.make_array(0, split_index)); - quicksort(array.make_array(split_index, array.size() - split_index)); -} +#if LIBC_QSORT_IMPL == LIBC_QSORT_QUICK_SORT +constexpr auto sort = quick_sort; +#elif LIBC_QSORT_IMPL == LIBC_QSORT_HEAP_SORT +constexpr auto sort = heap_sort; +#endif } // namespace internal } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/stdlib/quick_sort.h b/libc/src/stdlib/quick_sort.h new file mode 100644 index 00000000000000..89ec107161e3e5 --- /dev/null +++ b/libc/src/stdlib/quick_sort.h @@ -0,0 +1,78 @@ +//===-- Implementation header for qsort utilities ---------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC_STDLIB_QUICK_SORT_H +#define LLVM_LIBC_SRC_STDLIB_QUICK_SORT_H + +#include "src/__support/macros/attributes.h" +#include "src/__support/macros/config.h" +#include "src/stdlib/qsort_data.h" + +#include + +namespace LIBC_NAMESPACE_DECL { +namespace internal { + +// A simple quicksort implementation using the Hoare partition scheme. +static size_t partition(const Array &array) { + const size_t array_size = array.size(); + size_t pivot_index = array_size / 2; + uint8_t *pivot = array.get(pivot_index); + size_t i = 0; + size_t j = array_size - 1; + + while (true) { + int compare_i, compare_j; + + while ((compare_i = array.elem_compare(i, pivot)) < 0) + ++i; + while ((compare_j = array.elem_compare(j, pivot)) > 0) + --j; + + // At some point i will crossover j so we will definitely break out of + // this while loop. + if (i >= j) + return j + 1; + + array.swap(i, j); + + // The pivot itself might have got swapped so we will update the pivot. + if (i == pivot_index) { + pivot = array.get(j); + pivot_index = j; + } else if (j == pivot_index) { + pivot = array.get(i); + pivot_index = i; + } + + if (compare_i == 0 && compare_j == 0) { + // If we do not move the pointers, we will end up with an + // infinite loop as i and j will be stuck without advancing. + ++i; + --j; + } + } +} + +LIBC_INLINE void quick_sort(const Array &array) { + const size_t array_size = array.size(); + if (array_size <= 1) + return; + size_t split_index = partition(array); + if (array_size <= 2) { + // The partition operation sorts the two element array. + return; + } + quick_sort(array.make_array(0, split_index)); + quick_sort(array.make_array(split_index, array.size() - split_index)); +} + +} // namespace internal +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC_STDLIB_QUICK_SORT_H diff --git a/libc/test/src/stdlib/CMakeLists.txt b/libc/test/src/stdlib/CMakeLists.txt index 38488778c657c3..db90d9a4741ebf 100644 --- a/libc/test/src/stdlib/CMakeLists.txt +++ b/libc/test/src/stdlib/CMakeLists.txt @@ -290,14 +290,39 @@ add_libc_test( libc.src.stdlib.bsearch ) +add_libc_test( + quick_sort_test + SUITE + libc-stdlib-tests + SRCS + quick_sort_test.cpp + HDRS + SortingTest.h + DEPENDS + libc.src.stdlib.qsort_util +) + +add_libc_test( + heap_sort_test + SUITE + libc-stdlib-tests + SRCS + heap_sort_test.cpp + HDRS + SortingTest.h + DEPENDS + libc.src.stdlib.qsort_util +) + add_libc_test( qsort_test SUITE libc-stdlib-tests SRCS qsort_test.cpp + HDRS + SortingTest.h DEPENDS - libc.include.stdlib libc.src.stdlib.qsort ) diff --git a/libc/test/src/stdlib/SortingTest.h b/libc/test/src/stdlib/SortingTest.h new file mode 100644 index 00000000000000..d34584e5addf03 --- /dev/null +++ b/libc/test/src/stdlib/SortingTest.h @@ -0,0 +1,377 @@ +//===-- Unittests for sorting routines ------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "src/__support/macros/config.h" +#include "src/stdlib/qsort_data.h" +#include "test/UnitTest/Test.h" + +class SortingTest : public LIBC_NAMESPACE::testing::Test { + + using Array = LIBC_NAMESPACE::internal::Array; + using Comparator = LIBC_NAMESPACE::internal::Comparator; + using SortingRoutine = LIBC_NAMESPACE::internal::SortingRoutine; + +public: + static int int_compare(const void *l, const void *r) { + int li = *reinterpret_cast(l); + int ri = *reinterpret_cast(r); + if (li == ri) + return 0; + else if (li > ri) + return 1; + else + return -1; + } + + void test_sorted_array(SortingRoutine sort_func) { + int array[25] = {10, 23, 33, 35, 55, 70, 71, 100, 110, + 123, 133, 135, 155, 170, 171, 1100, 1110, 1123, + 1133, 1135, 1155, 1170, 1171, 11100, 12310}; + constexpr size_t ARRAY_SIZE = sizeof(array) / sizeof(int); + + auto arr = Array(reinterpret_cast(array), ARRAY_SIZE, + sizeof(int), Comparator(int_compare)); + + sort_func(arr); + + ASSERT_LE(array[0], 10); + ASSERT_LE(array[1], 23); + ASSERT_LE(array[2], 33); + ASSERT_LE(array[3], 35); + ASSERT_LE(array[4], 55); + ASSERT_LE(array[5], 70); + ASSERT_LE(array[6], 71); + ASSERT_LE(array[7], 100); + ASSERT_LE(array[8], 110); + ASSERT_LE(array[9], 123); + ASSERT_LE(array[10], 133); + ASSERT_LE(array[11], 135); + ASSERT_LE(array[12], 155); + ASSERT_LE(array[13], 170); + ASSERT_LE(array[14], 171); + ASSERT_LE(array[15], 1100); + ASSERT_LE(array[16], 1110); + ASSERT_LE(array[17], 1123); + ASSERT_LE(array[18], 1133); + ASSERT_LE(array[19], 1135); + ASSERT_LE(array[20], 1155); + ASSERT_LE(array[21], 1170); + ASSERT_LE(array[22], 1171); + ASSERT_LE(array[23], 11100); + ASSERT_LE(array[24], 12310); + } + + void test_reversed_sorted_array(SortingRoutine sort_func) { + int array[] = {25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, + 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1}; + constexpr size_t ARRAY_SIZE = sizeof(array) / sizeof(int); + + auto arr = Array(reinterpret_cast(array), ARRAY_SIZE, + sizeof(int), Comparator(int_compare)); + + sort_func(arr); + + for (int i = 0; i < int(ARRAY_SIZE - 1); ++i) + ASSERT_EQ(array[i], i + 1); + } + + void test_all_equal_elements(SortingRoutine sort_func) { + int array[] = {100, 100, 100, 100, 100, 100, 100, 100, 100, + 100, 100, 100, 100, 100, 100, 100, 100, 100, + 100, 100, 100, 100, 100, 100, 100}; + constexpr size_t ARRAY_SIZE = sizeof(array) / sizeof(int); + + auto arr = Array(reinterpret_cast(array), ARRAY_SIZE, + sizeof(int), Comparator(int_compare)); + + sort_func(arr); + + for (size_t i = 0; i < ARRAY_SIZE; ++i) + ASSERT_EQ(array[i], 100); + } + + void test_unsorted_array_1(SortingRoutine sort_func) { + int array[25] = {10, 23, 8, 35, 55, 45, 40, 100, 110, + 123, 90, 80, 70, 60, 171, 11, 1, -1, + -5, -10, 1155, 1170, 1171, 12, -100}; + constexpr size_t ARRAY_SIZE = sizeof(array) / sizeof(int); + + auto arr = Array(reinterpret_cast(array), ARRAY_SIZE, + sizeof(int), Comparator(int_compare)); + + sort_func(arr); + + ASSERT_EQ(array[0], -100); + ASSERT_EQ(array[1], -10); + ASSERT_EQ(array[2], -5); + ASSERT_EQ(array[3], -1); + ASSERT_EQ(array[4], 1); + ASSERT_EQ(array[5], 8); + ASSERT_EQ(array[6], 10); + ASSERT_EQ(array[7], 11); + ASSERT_EQ(array[8], 12); + ASSERT_EQ(array[9], 23); + ASSERT_EQ(array[10], 35); + ASSERT_EQ(array[11], 40); + ASSERT_EQ(array[12], 45); + ASSERT_EQ(array[13], 55); + ASSERT_EQ(array[14], 60); + ASSERT_EQ(array[15], 70); + ASSERT_EQ(array[16], 80); + ASSERT_EQ(array[17], 90); + ASSERT_EQ(array[18], 100); + ASSERT_EQ(array[19], 110); + ASSERT_EQ(array[20], 123); + ASSERT_EQ(array[21], 171); + ASSERT_EQ(array[22], 1155); + ASSERT_EQ(array[23], 1170); + ASSERT_EQ(array[24], 1171); + } + + void test_unsorted_array_2(SortingRoutine sort_func) { + int array[7] = {10, 40, 45, 55, 35, 23, 60}; + constexpr size_t ARRAY_SIZE = sizeof(array) / sizeof(int); + + auto arr = Array(reinterpret_cast(array), ARRAY_SIZE, + sizeof(int), Comparator(int_compare)); + + sort_func(arr); + + ASSERT_EQ(array[0], 10); + ASSERT_EQ(array[1], 23); + ASSERT_EQ(array[2], 35); + ASSERT_EQ(array[3], 40); + ASSERT_EQ(array[4], 45); + ASSERT_EQ(array[5], 55); + ASSERT_EQ(array[6], 60); + } + + void test_unsorted_array_duplicated_1(SortingRoutine sort_func) { + int array[6] = {10, 10, 20, 20, 5, 5}; + constexpr size_t ARRAY_SIZE = sizeof(array) / sizeof(int); + + auto arr = Array(reinterpret_cast(array), ARRAY_SIZE, + sizeof(int), Comparator(int_compare)); + + sort_func(arr); + + ASSERT_EQ(array[0], 5); + ASSERT_EQ(array[1], 5); + ASSERT_EQ(array[2], 10); + ASSERT_EQ(array[3], 10); + ASSERT_EQ(array[4], 20); + ASSERT_EQ(array[5], 20); + } + + void test_unsorted_array_duplicated_2(SortingRoutine sort_func) { + int array[10] = {20, 10, 10, 10, 10, 20, 21, 21, 21, 21}; + constexpr size_t ARRAY_SIZE = sizeof(array) / sizeof(int); + + auto arr = Array(reinterpret_cast(array), ARRAY_SIZE, + sizeof(int), Comparator(int_compare)); + + sort_func(arr); + + ASSERT_EQ(array[0], 10); + ASSERT_EQ(array[1], 10); + ASSERT_EQ(array[2], 10); + ASSERT_EQ(array[3], 10); + ASSERT_EQ(array[4], 20); + ASSERT_EQ(array[5], 20); + ASSERT_EQ(array[6], 21); + ASSERT_EQ(array[7], 21); + ASSERT_EQ(array[8], 21); + ASSERT_EQ(array[9], 21); + } + + void test_unsorted_array_duplicated_3(SortingRoutine sort_func) { + int array[10] = {20, 30, 30, 30, 30, 20, 21, 21, 21, 21}; + constexpr size_t ARRAY_SIZE = sizeof(array) / sizeof(int); + + auto arr = Array(reinterpret_cast(array), ARRAY_SIZE, + sizeof(int), Comparator(int_compare)); + + sort_func(arr); + + ASSERT_EQ(array[0], 20); + ASSERT_EQ(array[1], 20); + ASSERT_EQ(array[2], 21); + ASSERT_EQ(array[3], 21); + ASSERT_EQ(array[4], 21); + ASSERT_EQ(array[5], 21); + ASSERT_EQ(array[6], 30); + ASSERT_EQ(array[7], 30); + ASSERT_EQ(array[8], 30); + ASSERT_EQ(array[9], 30); + } + + void test_unsorted_three_element_1(SortingRoutine sort_func) { + int array[3] = {14999024, 0, 3}; + + constexpr size_t ARRAY_SIZE = sizeof(array) / sizeof(int); + + auto arr = Array(reinterpret_cast(array), ARRAY_SIZE, + sizeof(int), Comparator(int_compare)); + + sort_func(arr); + + ASSERT_EQ(array[0], 0); + ASSERT_EQ(array[1], 3); + ASSERT_EQ(array[2], 14999024); + } + + void test_unsorted_three_element_2(SortingRoutine sort_func) { + int array[3] = {3, 14999024, 0}; + + constexpr size_t ARRAY_SIZE = sizeof(array) / sizeof(int); + + auto arr = Array(reinterpret_cast(array), ARRAY_SIZE, + sizeof(int), Comparator(int_compare)); + + sort_func(arr); + + ASSERT_EQ(array[0], 0); + ASSERT_EQ(array[1], 3); + ASSERT_EQ(array[2], 14999024); + } + + void test_unsorted_three_element_3(SortingRoutine sort_func) { + int array[3] = {3, 0, 14999024}; + + constexpr size_t ARRAY_SIZE = sizeof(array) / sizeof(int); + + auto arr = Array(reinterpret_cast(array), ARRAY_SIZE, + sizeof(int), Comparator(int_compare)); + + sort_func(arr); + + ASSERT_EQ(array[0], 0); + ASSERT_EQ(array[1], 3); + ASSERT_EQ(array[2], 14999024); + } + + void test_same_three_element(SortingRoutine sort_func) { + int array[3] = {12345, 12345, 12345}; + + constexpr size_t ARRAY_SIZE = sizeof(array) / sizeof(int); + + auto arr = Array(reinterpret_cast(array), ARRAY_SIZE, + sizeof(int), Comparator(int_compare)); + + sort_func(arr); + + ASSERT_EQ(array[0], 12345); + ASSERT_EQ(array[1], 12345); + ASSERT_EQ(array[2], 12345); + } + + void test_unsorted_two_element_1(SortingRoutine sort_func) { + int array[] = {14999024, 0}; + + constexpr size_t ARRAY_SIZE = sizeof(array) / sizeof(int); + + auto arr = Array(reinterpret_cast(array), ARRAY_SIZE, + sizeof(int), Comparator(int_compare)); + + sort_func(arr); + + ASSERT_EQ(array[0], 0); + ASSERT_EQ(array[1], 14999024); + } + + void test_unsorted_two_element_2(SortingRoutine sort_func) { + int array[] = {0, 14999024}; + + constexpr size_t ARRAY_SIZE = sizeof(array) / sizeof(int); + + auto arr = Array(reinterpret_cast(array), ARRAY_SIZE, + sizeof(int), Comparator(int_compare)); + + sort_func(arr); + + ASSERT_EQ(array[0], 0); + ASSERT_EQ(array[1], 14999024); + } + + void test_same_two_element(SortingRoutine sort_func) { + int array[] = {12345, 12345}; + + constexpr size_t ARRAY_SIZE = sizeof(array) / sizeof(int); + + auto arr = Array(reinterpret_cast(array), ARRAY_SIZE, + sizeof(int), Comparator(int_compare)); + + sort_func(arr); + + ASSERT_EQ(array[0], 12345); + ASSERT_EQ(array[1], 12345); + } + + void test_single_element(SortingRoutine sort_func) { + int array[] = {12345}; + + constexpr size_t ARRAY_SIZE = sizeof(array) / sizeof(int); + + auto arr = Array(reinterpret_cast(array), ARRAY_SIZE, + sizeof(int), Comparator(int_compare)); + + sort_func(arr); + + ASSERT_EQ(array[0], 12345); + } +}; + +#define LIST_SORTING_TESTS(Name, Func) \ + using LlvmLibc##Name##Test = SortingTest; \ + TEST_F(LlvmLibc##Name##Test, SortedArray) { test_sorted_array(Func); } \ + TEST_F(LlvmLibc##Name##Test, ReverseSortedArray) { \ + test_reversed_sorted_array(Func); \ + } \ + TEST_F(LlvmLibc##Name##Test, AllEqualElements) { \ + test_all_equal_elements(Func); \ + } \ + TEST_F(LlvmLibc##Name##Test, UnsortedArray1) { \ + test_unsorted_array_1(Func); \ + } \ + TEST_F(LlvmLibc##Name##Test, UnsortedArray2) { \ + test_unsorted_array_2(Func); \ + } \ + TEST_F(LlvmLibc##Name##Test, UnsortedArrayDuplicateElements1) { \ + test_unsorted_array_duplicated_1(Func); \ + } \ + TEST_F(LlvmLibc##Name##Test, UnsortedArrayDuplicateElements2) { \ + test_unsorted_array_duplicated_2(Func); \ + } \ + TEST_F(LlvmLibc##Name##Test, UnsortedArrayDuplicateElements3) { \ + test_unsorted_array_duplicated_3(Func); \ + } \ + TEST_F(LlvmLibc##Name##Test, UnsortedThreeElementArray1) { \ + test_unsorted_three_element_1(Func); \ + } \ + TEST_F(LlvmLibc##Name##Test, UnsortedThreeElementArray2) { \ + test_unsorted_three_element_2(Func); \ + } \ + TEST_F(LlvmLibc##Name##Test, UnsortedThreeElementArray3) { \ + test_unsorted_three_element_3(Func); \ + } \ + TEST_F(LlvmLibc##Name##Test, SameElementThreeElementArray) { \ + test_same_three_element(Func); \ + } \ + TEST_F(LlvmLibc##Name##Test, UnsortedTwoElementArray1) { \ + test_unsorted_two_element_1(Func); \ + } \ + TEST_F(LlvmLibc##Name##Test, UnsortedTwoElementArray2) { \ + test_unsorted_two_element_2(Func); \ + } \ + TEST_F(LlvmLibc##Name##Test, SameElementTwoElementArray) { \ + test_same_two_element(Func); \ + } \ + TEST_F(LlvmLibc##Name##Test, SingleElementArray) { \ + test_single_element(Func); \ + } \ + static_assert(true) diff --git a/libc/test/src/stdlib/heap_sort_test.cpp b/libc/test/src/stdlib/heap_sort_test.cpp new file mode 100644 index 00000000000000..d70e3dc2272beb --- /dev/null +++ b/libc/test/src/stdlib/heap_sort_test.cpp @@ -0,0 +1,16 @@ +//===-- Unittests for heap sort -------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "SortingTest.h" +#include "src/stdlib/heap_sort.h" + +void sort(const LIBC_NAMESPACE::internal::Array &array) { + LIBC_NAMESPACE::internal::heap_sort(array); +} + +LIST_SORTING_TESTS(HeapSort, sort); diff --git a/libc/test/src/stdlib/qsort_test.cpp b/libc/test/src/stdlib/qsort_test.cpp index 0822d490e65208..1e921a86fd1fd3 100644 --- a/libc/test/src/stdlib/qsort_test.cpp +++ b/libc/test/src/stdlib/qsort_test.cpp @@ -6,260 +6,12 @@ // //===----------------------------------------------------------------------===// +#include "SortingTest.h" #include "src/stdlib/qsort.h" -#include "test/UnitTest/Test.h" - -#include - -static int int_compare(const void *l, const void *r) { - int li = *reinterpret_cast(l); - int ri = *reinterpret_cast(r); - if (li == ri) - return 0; - else if (li > ri) - return 1; - else - return -1; +void sort(const LIBC_NAMESPACE::internal::Array &array) { + LIBC_NAMESPACE::qsort(reinterpret_cast(array.get(0)), array.size(), + sizeof(int), SortingTest::int_compare); } -TEST(LlvmLibcQsortTest, SortedArray) { - int array[25] = {10, 23, 33, 35, 55, 70, 71, 100, 110, - 123, 133, 135, 155, 170, 171, 1100, 1110, 1123, - 1133, 1135, 1155, 1170, 1171, 11100, 12310}; - constexpr size_t ARRAY_SIZE = sizeof(array) / sizeof(int); - - LIBC_NAMESPACE::qsort(array, ARRAY_SIZE, sizeof(int), int_compare); - - ASSERT_LE(array[0], 10); - ASSERT_LE(array[1], 23); - ASSERT_LE(array[2], 33); - ASSERT_LE(array[3], 35); - ASSERT_LE(array[4], 55); - ASSERT_LE(array[5], 70); - ASSERT_LE(array[6], 71); - ASSERT_LE(array[7], 100); - ASSERT_LE(array[8], 110); - ASSERT_LE(array[9], 123); - ASSERT_LE(array[10], 133); - ASSERT_LE(array[11], 135); - ASSERT_LE(array[12], 155); - ASSERT_LE(array[13], 170); - ASSERT_LE(array[14], 171); - ASSERT_LE(array[15], 1100); - ASSERT_LE(array[16], 1110); - ASSERT_LE(array[17], 1123); - ASSERT_LE(array[18], 1133); - ASSERT_LE(array[19], 1135); - ASSERT_LE(array[20], 1155); - ASSERT_LE(array[21], 1170); - ASSERT_LE(array[22], 1171); - ASSERT_LE(array[23], 11100); - ASSERT_LE(array[24], 12310); -} - -TEST(LlvmLibcQsortTest, ReverseSortedArray) { - int array[25] = {25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, - 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1}; - constexpr size_t ARRAY_SIZE = sizeof(array) / sizeof(int); - - LIBC_NAMESPACE::qsort(array, ARRAY_SIZE, sizeof(int), int_compare); - - for (int i = 0; i < int(ARRAY_SIZE - 1); ++i) - ASSERT_LE(array[i], i + 1); -} - -TEST(LlvmLibcQsortTest, AllEqualElements) { - int array[25] = {100, 100, 100, 100, 100, 100, 100, 100, 100, - 100, 100, 100, 100, 100, 100, 100, 100, 100, - 100, 100, 100, 100, 100, 100, 100}; - constexpr size_t ARRAY_SIZE = sizeof(array) / sizeof(int); - - LIBC_NAMESPACE::qsort(array, ARRAY_SIZE, sizeof(int), int_compare); - - for (size_t i = 0; i < ARRAY_SIZE - 1; ++i) - ASSERT_LE(array[i], 100); -} - -TEST(LlvmLibcQsortTest, UnsortedArray1) { - int array[25] = {10, 23, 8, 35, 55, 45, 40, 100, 110, 123, 90, 80, 70, - 60, 171, 11, 1, -1, -5, -10, 1155, 1170, 1171, 12, -100}; - constexpr size_t ARRAY_SIZE = sizeof(array) / sizeof(int); - - LIBC_NAMESPACE::qsort(array, ARRAY_SIZE, sizeof(int), int_compare); - - ASSERT_LE(array[0], -100); - ASSERT_LE(array[1], -10); - ASSERT_LE(array[2], -5); - ASSERT_LE(array[3], -1); - ASSERT_LE(array[4], 1); - ASSERT_LE(array[5], 8); - ASSERT_LE(array[6], 10); - ASSERT_LE(array[7], 11); - ASSERT_LE(array[8], 12); - ASSERT_LE(array[9], 23); - ASSERT_LE(array[10], 35); - ASSERT_LE(array[11], 40); - ASSERT_LE(array[12], 45); - ASSERT_LE(array[13], 55); - ASSERT_LE(array[14], 60); - ASSERT_LE(array[15], 70); - ASSERT_LE(array[16], 80); - ASSERT_LE(array[17], 90); - ASSERT_LE(array[18], 100); - ASSERT_LE(array[19], 110); - ASSERT_LE(array[20], 123); - ASSERT_LE(array[21], 171); - ASSERT_LE(array[22], 1155); - ASSERT_LE(array[23], 1170); - ASSERT_LE(array[24], 1171); -} - -TEST(LlvmLibcQsortTest, UnsortedArray2) { - int array[7] = {10, 40, 45, 55, 35, 23, 60}; - constexpr size_t ARRAY_SIZE = sizeof(array) / sizeof(int); - - LIBC_NAMESPACE::qsort(array, ARRAY_SIZE, sizeof(int), int_compare); - - ASSERT_LE(array[0], 10); - ASSERT_LE(array[1], 23); - ASSERT_LE(array[2], 35); - ASSERT_LE(array[3], 40); - ASSERT_LE(array[4], 45); - ASSERT_LE(array[5], 55); - ASSERT_LE(array[6], 60); -} - -TEST(LlvmLibcQsortTest, UnsortedArrayDuplicateElements1) { - int array[6] = {10, 10, 20, 20, 5, 5}; - constexpr size_t ARRAY_SIZE = sizeof(array) / sizeof(int); - - LIBC_NAMESPACE::qsort(array, ARRAY_SIZE, sizeof(int), int_compare); - - ASSERT_LE(array[0], 5); - ASSERT_LE(array[1], 5); - ASSERT_LE(array[2], 10); - ASSERT_LE(array[3], 10); - ASSERT_LE(array[4], 20); - ASSERT_LE(array[5], 20); -} - -TEST(LlvmLibcQsortTest, UnsortedArrayDuplicateElements2) { - int array[10] = {20, 10, 10, 10, 10, 20, 21, 21, 21, 21}; - constexpr size_t ARRAY_SIZE = sizeof(array) / sizeof(int); - - LIBC_NAMESPACE::qsort(array, ARRAY_SIZE, sizeof(int), int_compare); - - ASSERT_LE(array[0], 10); - ASSERT_LE(array[1], 10); - ASSERT_LE(array[2], 10); - ASSERT_LE(array[3], 10); - ASSERT_LE(array[4], 20); - ASSERT_LE(array[5], 20); - ASSERT_LE(array[6], 21); - ASSERT_LE(array[7], 21); - ASSERT_LE(array[8], 21); - ASSERT_LE(array[9], 21); -} - -TEST(LlvmLibcQsortTest, UnsortedArrayDuplicateElements3) { - int array[10] = {20, 30, 30, 30, 30, 20, 21, 21, 21, 21}; - constexpr size_t ARRAY_SIZE = sizeof(array) / sizeof(int); - - LIBC_NAMESPACE::qsort(array, ARRAY_SIZE, sizeof(int), int_compare); - - ASSERT_LE(array[0], 20); - ASSERT_LE(array[1], 20); - ASSERT_LE(array[2], 21); - ASSERT_LE(array[3], 21); - ASSERT_LE(array[4], 21); - ASSERT_LE(array[5], 21); - ASSERT_LE(array[6], 30); - ASSERT_LE(array[7], 30); - ASSERT_LE(array[8], 30); - ASSERT_LE(array[9], 30); -} - -TEST(LlvmLibcQsortTest, UnsortedThreeElementArray1) { - int array[3] = {14999024, 0, 3}; - constexpr size_t ARRAY_SIZE = sizeof(array) / sizeof(int); - - LIBC_NAMESPACE::qsort(array, ARRAY_SIZE, sizeof(int), int_compare); - - ASSERT_LE(array[0], 0); - ASSERT_LE(array[1], 3); - ASSERT_LE(array[2], 14999024); -} - -TEST(LlvmLibcQsortTest, UnsortedThreeElementArray2) { - int array[3] = {3, 14999024, 0}; - constexpr size_t ARRAY_SIZE = sizeof(array) / sizeof(int); - - LIBC_NAMESPACE::qsort(array, ARRAY_SIZE, sizeof(int), int_compare); - - ASSERT_LE(array[0], 0); - ASSERT_LE(array[1], 3); - ASSERT_LE(array[2], 14999024); -} - -TEST(LlvmLibcQsortTest, UnsortedThreeElementArray3) { - int array[3] = {3, 0, 14999024}; - constexpr size_t ARRAY_SIZE = sizeof(array) / sizeof(int); - - LIBC_NAMESPACE::qsort(array, ARRAY_SIZE, sizeof(int), int_compare); - - ASSERT_LE(array[0], 0); - ASSERT_LE(array[1], 3); - ASSERT_LE(array[2], 14999024); -} - -TEST(LlvmLibcQsortTest, SameElementThreeElementArray) { - int array[3] = {12345, 12345, 12345}; - constexpr size_t ARRAY_SIZE = sizeof(array) / sizeof(int); - - LIBC_NAMESPACE::qsort(array, ARRAY_SIZE, sizeof(int), int_compare); - - ASSERT_LE(array[0], 12345); - ASSERT_LE(array[1], 12345); - ASSERT_LE(array[2], 12345); -} - -TEST(LlvmLibcQsortTest, UnsortedTwoElementArray1) { - int array[2] = {14999024, 0}; - constexpr size_t ARRAY_SIZE = sizeof(array) / sizeof(int); - - LIBC_NAMESPACE::qsort(array, ARRAY_SIZE, sizeof(int), int_compare); - - ASSERT_LE(array[0], 0); - ASSERT_LE(array[1], 14999024); -} - -TEST(LlvmLibcQsortTest, UnsortedTwoElementArray2) { - int array[2] = {0, 14999024}; - constexpr size_t ARRAY_SIZE = sizeof(array) / sizeof(int); - - LIBC_NAMESPACE::qsort(array, ARRAY_SIZE, sizeof(int), int_compare); - - ASSERT_LE(array[0], 0); - ASSERT_LE(array[1], 14999024); -} - -TEST(LlvmLibcQsortTest, SameElementTwoElementArray) { - int array[2] = {12345, 12345}; - constexpr size_t ARRAY_SIZE = sizeof(array) / sizeof(int); - - LIBC_NAMESPACE::qsort(array, ARRAY_SIZE, sizeof(int), int_compare); - - ASSERT_LE(array[0], 12345); - ASSERT_LE(array[1], 12345); -} - -TEST(LlvmLibcQSortTest, SingleElementArray) { - constexpr int ELEM = 12345; - int array[1] = {ELEM}; - constexpr size_t ARRAY_SIZE = sizeof(array) / sizeof(int); - - LIBC_NAMESPACE::qsort(array, ARRAY_SIZE, sizeof(int), int_compare); - - ASSERT_LE(array[0], ELEM); -} +LIST_SORTING_TESTS(Qsort, sort); diff --git a/libc/test/src/stdlib/quick_sort_test.cpp b/libc/test/src/stdlib/quick_sort_test.cpp new file mode 100644 index 00000000000000..d6bf77ebfd40d7 --- /dev/null +++ b/libc/test/src/stdlib/quick_sort_test.cpp @@ -0,0 +1,16 @@ +//===-- Unittests for quick sort ------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "SortingTest.h" +#include "src/stdlib/quick_sort.h" + +void sort(const LIBC_NAMESPACE::internal::Array &array) { + LIBC_NAMESPACE::internal::quick_sort(array); +} + +LIST_SORTING_TESTS(QuickSort, sort); diff --git a/utils/bazel/llvm-project-overlay/libc/BUILD.bazel b/utils/bazel/llvm-project-overlay/libc/BUILD.bazel index 5d47f4a9cd640a..1687321b521e68 100644 --- a/utils/bazel/llvm-project-overlay/libc/BUILD.bazel +++ b/utils/bazel/llvm-project-overlay/libc/BUILD.bazel @@ -2413,9 +2413,15 @@ libc_function( libc_support_library( name = "qsort_util", - hdrs = ["src/stdlib/qsort_util.h"], + hdrs = [ + "src/stdlib/heap_sort.h", + "src/stdlib/qsort_data.h", + "src/stdlib/qsort_util.h", + "src/stdlib/quick_sort.h", + ], deps = [ ":__support_common", + ":__support_cpp_cstddef", ":__support_macros_attributes", ], ) diff --git a/utils/bazel/llvm-project-overlay/libc/test/src/stdlib/BUILD.bazel b/utils/bazel/llvm-project-overlay/libc/test/src/stdlib/BUILD.bazel index b34e281ce0ecd6..a6f9d4f2fdac2a 100644 --- a/utils/bazel/llvm-project-overlay/libc/test/src/stdlib/BUILD.bazel +++ b/utils/bazel/llvm-project-overlay/libc/test/src/stdlib/BUILD.bazel @@ -100,10 +100,35 @@ libc_test( libc_function_deps = ["//libc:bsearch"], ) +libc_support_library( + name = "qsort_test_helper", + hdrs = ["SortingTest.h"], + deps = [ + "//libc:qsort_util", + "//libc/test/UnitTest:LibcUnitTest", + ], +) libc_test( name = "qsort_test", srcs = ["qsort_test.cpp"], libc_function_deps = ["//libc:qsort"], + deps = [":qsort_test_helper"], +) +libc_test( + name = "quick_sort_test", + srcs = ["quick_sort_test.cpp"], + deps = [ + ":qsort_test_helper", + "//libc:qsort_util", + ], +) +libc_test( + name = "heap_sort_test", + srcs = ["heap_sort_test.cpp"], + deps = [ + ":qsort_test_helper", + "//libc:qsort_util", + ], ) libc_test(