[libc-commits] [libc] [libc][stdlib] Implement heap sort. (PR #98582)
via libc-commits
libc-commits at lists.llvm.org
Thu Jul 11 19:41:57 PDT 2024
https://github.com/lntue created https://github.com/llvm/llvm-project/pull/98582
None
>From b19bcbb794db159284cdd836ed28eed36eceb83b Mon Sep 17 00:00:00 2001
From: Tue Ly <lntue.h at gmail.com>
Date: Fri, 12 Jul 2024 02:40:16 +0000
Subject: [PATCH] [libc][stdlib] Implement heap sort.
---
.../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 | 2 +
libc/src/stdlib/heap_sort.h | 54 +++++++++++++++++++
libc/src/stdlib/qsort.cpp | 12 ++++-
libc/src/stdlib/qsort_r.cpp | 10 +++-
libc/src/stdlib/qsort_util.h | 19 +++++--
9 files changed, 114 insertions(+), 9 deletions(-)
create mode 100644 libc/src/stdlib/heap_sort.h
diff --git a/libc/cmake/modules/LLVMLibCCompileOptionRules.cmake b/libc/cmake/modules/LLVMLibCCompileOptionRules.cmake
index c5e7dfe8abd0f..097d9cb2fd1b9 100644
--- a/libc/cmake/modules/LLVMLibCCompileOptionRules.cmake
+++ b/libc/cmake/modules/LLVMLibCCompileOptionRules.cmake
@@ -34,10 +34,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 dda4c42425755..f2bc6e6517f7c 100644
--- a/libc/config/baremetal/config.json
+++ b/libc/config/baremetal/config.json
@@ -17,5 +17,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 e8feab20175f4..e6a65d6689ec7 100644
--- a/libc/config/config.json
+++ b/libc/config/config.json
@@ -76,5 +76,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 9c641ef94570f..777330d815756 100644
--- a/libc/docs/configure.rst
+++ b/libc/docs/configure.rst
@@ -42,6 +42,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 7b7e55db391fa..e19d97b1025d9 100644
--- a/libc/src/stdlib/CMakeLists.txt
+++ b/libc/src/stdlib/CMakeLists.txt
@@ -259,8 +259,10 @@ add_header_library(
qsort_util
HDRS
qsort_util.h
+ heap_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 0000000000000..63aba88fb933f
--- /dev/null
+++ b/libc/src/stdlib/heap_sort.h
@@ -0,0 +1,54 @@
+//===-- 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 "qsort_util.h"
+#include "src/__support/CPP/cstddef.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) {
+ --start;
+ } else {
+ --end;
+ array.swap(0, end);
+ }
+
+ size_t root = start;
+ while (left_child(root) < end) {
+ size_t child = left_child(root);
+ if (child + 1 < end &&
+ array.elem_compare(child, array.get(child + 1)) < 0)
+ ++child;
+
+ if (array.elem_compare(root, array.get(child)) >= 0)
+ break;
+
+ 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 048e63ab214ed..fb6bfa006eb1f 100644
--- a/libc/src/stdlib/qsort.cpp
+++ b/libc/src/stdlib/qsort.cpp
@@ -9,6 +9,7 @@
#include "src/stdlib/qsort.h"
#include "src/__support/common.h"
#include "src/__support/macros/config.h"
+#include "src/stdlib/heap_sort.h"
#include "src/stdlib/qsort_util.h"
#include <stdint.h>
@@ -21,8 +22,15 @@ 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<uint8_t *>(array),
- array_size, elem_size, c));
+
+ auto arr = internal::Array(reinterpret_cast<uint8_t *>(array), array_size,
+ elem_size, c);
+
+#if LIBC_QSORT_IMPL == LIBC_QSORT_QUICK_SORT
+ internal::quick_sort(arr);
+#elif LIBC_QSORT_IMPL == LIBC_QSORT_HEAP_SORT
+ internal::heap_sort(arr);
+#endif
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdlib/qsort_r.cpp b/libc/src/stdlib/qsort_r.cpp
index efbe5ad484b0e..3c9bb5aa21f43 100644
--- a/libc/src/stdlib/qsort_r.cpp
+++ b/libc/src/stdlib/qsort_r.cpp
@@ -22,8 +22,14 @@ 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<uint8_t *>(array),
- array_size, elem_size, c));
+ auto arr = internal::Array(reinterpret_cast<uint8_t *>(array), array_size,
+ elem_size, c);
+
+#if LIBC_QSORT_IMPL == LIBC_QSORT_QUICK_SORT
+ internal::quick_sort(arr);
+#elif LIBC_QSORT_IMPL == LIBC_QSORT_HEAP_SORT
+ internal::heap_sort(arr);
+#endif
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdlib/qsort_util.h b/libc/src/stdlib/qsort_util.h
index 3a9cc4b8669f8..87945c26b3c93 100644
--- a/libc/src/stdlib/qsort_util.h
+++ b/libc/src/stdlib/qsort_util.h
@@ -12,7 +12,18 @@
#include "src/__support/macros/attributes.h"
#include "src/__support/macros/config.h"
#include <stdint.h>
-#include <stdlib.h>
+
+#define LIBC_QSORT_QUICK_SORT 1
+#define LIBC_QSORT_HEAP_SORT 2
+
+#ifndef LIBC_QSORT_IMPL
+#define LIBC_QSORT_IMPL LIBC_QSORT_QUICK_SORT
+#endif // LIBC_QSORT_IMPL
+
+#if (LIBC_QSORT_IMPL != LIBC_QSORT_QUICK_SORT && \
+ LIBC_QSORT_IMPL != LIBC_QSORT_HEAP_SORT)
+#error "LIBC_QSORT_IMPL is not recognized."
+#endif
namespace LIBC_NAMESPACE_DECL {
namespace internal {
@@ -136,7 +147,7 @@ static size_t partition(const Array &array) {
}
}
-LIBC_INLINE void quicksort(const Array &array) {
+LIBC_INLINE void quick_sort(const Array &array) {
const size_t array_size = array.size();
if (array_size <= 1)
return;
@@ -145,8 +156,8 @@ LIBC_INLINE void quicksort(const Array &array) {
// 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));
+ quick_sort(array.make_array(0, split_index));
+ quick_sort(array.make_array(split_index, array.size() - split_index));
}
} // namespace internal
More information about the libc-commits
mailing list