15eb6b827SSiva Chandra Reddy //===-- Implementation of qsort -------------------------------------------===//
25eb6b827SSiva Chandra Reddy //
35eb6b827SSiva Chandra Reddy // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
45eb6b827SSiva Chandra Reddy // See https://llvm.org/LICENSE.txt for license information.
55eb6b827SSiva Chandra Reddy // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
65eb6b827SSiva Chandra Reddy //
75eb6b827SSiva Chandra Reddy //===----------------------------------------------------------------------===//
85eb6b827SSiva Chandra Reddy
95eb6b827SSiva Chandra Reddy #include "src/stdlib/qsort.h"
105eb6b827SSiva Chandra Reddy #include "src/__support/common.h"
115eb6b827SSiva Chandra Reddy
125eb6b827SSiva Chandra Reddy #include <stdint.h>
135eb6b827SSiva Chandra Reddy
145eb6b827SSiva Chandra Reddy namespace __llvm_libc {
155eb6b827SSiva Chandra Reddy
165eb6b827SSiva Chandra Reddy namespace internal {
175eb6b827SSiva Chandra Reddy
185eb6b827SSiva Chandra Reddy // A simple quicksort implementation using the Hoare partition scheme.
195eb6b827SSiva Chandra Reddy
205eb6b827SSiva Chandra Reddy class Array {
215eb6b827SSiva Chandra Reddy typedef int (*comparator)(const void *, const void *);
225eb6b827SSiva Chandra Reddy
235eb6b827SSiva Chandra Reddy uint8_t *array;
245eb6b827SSiva Chandra Reddy size_t array_size;
255eb6b827SSiva Chandra Reddy size_t elem_size;
265eb6b827SSiva Chandra Reddy comparator compare;
275eb6b827SSiva Chandra Reddy
285eb6b827SSiva Chandra Reddy public:
Array(uint8_t * a,size_t s,size_t e,comparator c)295eb6b827SSiva Chandra Reddy Array(uint8_t *a, size_t s, size_t e, comparator c)
305eb6b827SSiva Chandra Reddy : array(a), array_size(s), elem_size(e), compare(c) {}
315eb6b827SSiva Chandra Reddy
get(size_t i) const325eb6b827SSiva Chandra Reddy uint8_t *get(size_t i) const { return array + i * elem_size; }
335eb6b827SSiva Chandra Reddy
swap(size_t i,size_t j) const345eb6b827SSiva Chandra Reddy void swap(size_t i, size_t j) const {
355eb6b827SSiva Chandra Reddy uint8_t *elem_i = get(i);
365eb6b827SSiva Chandra Reddy uint8_t *elem_j = get(j);
375eb6b827SSiva Chandra Reddy for (size_t b = 0; b < elem_size; ++b) {
385eb6b827SSiva Chandra Reddy uint8_t temp = elem_i[b];
395eb6b827SSiva Chandra Reddy elem_i[b] = elem_j[b];
405eb6b827SSiva Chandra Reddy elem_j[b] = temp;
415eb6b827SSiva Chandra Reddy }
425eb6b827SSiva Chandra Reddy }
435eb6b827SSiva Chandra Reddy
elem_compare(size_t i,const uint8_t * other) const445eb6b827SSiva Chandra Reddy int elem_compare(size_t i, const uint8_t *other) const {
45*5e2d5071SAlex Brachet // An element must compare equal to itself so we don't need to consult the
46*5e2d5071SAlex Brachet // user provided comparator.
47*5e2d5071SAlex Brachet if (get(i) == other)
48*5e2d5071SAlex Brachet return 0;
495eb6b827SSiva Chandra Reddy return compare(get(i), other);
505eb6b827SSiva Chandra Reddy }
515eb6b827SSiva Chandra Reddy
size() const525eb6b827SSiva Chandra Reddy size_t size() const { return array_size; }
535eb6b827SSiva Chandra Reddy
545eb6b827SSiva Chandra Reddy // Make an Array starting at index |i| and size |s|.
make_array(size_t i,size_t s) const555eb6b827SSiva Chandra Reddy Array make_array(size_t i, size_t s) const {
565eb6b827SSiva Chandra Reddy return Array(get(i), s, elem_size, compare);
575eb6b827SSiva Chandra Reddy }
585eb6b827SSiva Chandra Reddy };
595eb6b827SSiva Chandra Reddy
partition(const Array & array)605eb6b827SSiva Chandra Reddy static size_t partition(const Array &array) {
615eb6b827SSiva Chandra Reddy const size_t array_size = array.size();
625eb6b827SSiva Chandra Reddy size_t pivot_index = array_size / 2;
635eb6b827SSiva Chandra Reddy uint8_t *pivot = array.get(pivot_index);
645eb6b827SSiva Chandra Reddy size_t i = 0;
655eb6b827SSiva Chandra Reddy size_t j = array_size - 1;
665eb6b827SSiva Chandra Reddy
675eb6b827SSiva Chandra Reddy while (true) {
685eb6b827SSiva Chandra Reddy int compare_i, compare_j;
695eb6b827SSiva Chandra Reddy
705eb6b827SSiva Chandra Reddy while ((compare_i = array.elem_compare(i, pivot)) < 0)
715eb6b827SSiva Chandra Reddy ++i;
725eb6b827SSiva Chandra Reddy while ((compare_j = array.elem_compare(j, pivot)) > 0)
735eb6b827SSiva Chandra Reddy --j;
745eb6b827SSiva Chandra Reddy
755eb6b827SSiva Chandra Reddy // At some point i will crossover j so we will definitely break out of
765eb6b827SSiva Chandra Reddy // this while loop.
775eb6b827SSiva Chandra Reddy if (i >= j)
785eb6b827SSiva Chandra Reddy return j + 1;
795eb6b827SSiva Chandra Reddy
805eb6b827SSiva Chandra Reddy array.swap(i, j);
815eb6b827SSiva Chandra Reddy
825eb6b827SSiva Chandra Reddy // The pivot itself might have got swapped so we will update the pivot.
835eb6b827SSiva Chandra Reddy if (i == pivot_index) {
845eb6b827SSiva Chandra Reddy pivot = array.get(j);
855eb6b827SSiva Chandra Reddy pivot_index = j;
865eb6b827SSiva Chandra Reddy } else if (j == pivot_index) {
875eb6b827SSiva Chandra Reddy pivot = array.get(i);
885eb6b827SSiva Chandra Reddy pivot_index = i;
895eb6b827SSiva Chandra Reddy }
905eb6b827SSiva Chandra Reddy
915eb6b827SSiva Chandra Reddy if (compare_i == 0 && compare_j == 0) {
925eb6b827SSiva Chandra Reddy // If we do not move the pointers, we will end up with an
935eb6b827SSiva Chandra Reddy // infinite loop as i and j will be stuck without advancing.
945eb6b827SSiva Chandra Reddy ++i;
955eb6b827SSiva Chandra Reddy --j;
965eb6b827SSiva Chandra Reddy }
975eb6b827SSiva Chandra Reddy }
985eb6b827SSiva Chandra Reddy }
995eb6b827SSiva Chandra Reddy
quicksort(const Array & array)1005eb6b827SSiva Chandra Reddy static void quicksort(const Array &array) {
1015eb6b827SSiva Chandra Reddy const size_t array_size = array.size();
1025eb6b827SSiva Chandra Reddy if (array_size <= 1)
1035eb6b827SSiva Chandra Reddy return;
1045eb6b827SSiva Chandra Reddy size_t split_index = partition(array);
1055eb6b827SSiva Chandra Reddy if (array_size <= 2) {
1065eb6b827SSiva Chandra Reddy // The partition operation sorts the two element array.
1075eb6b827SSiva Chandra Reddy return;
1085eb6b827SSiva Chandra Reddy }
1095eb6b827SSiva Chandra Reddy quicksort(array.make_array(0, split_index));
1105eb6b827SSiva Chandra Reddy quicksort(array.make_array(split_index, array.size() - split_index));
1115eb6b827SSiva Chandra Reddy }
1125eb6b827SSiva Chandra Reddy
1135eb6b827SSiva Chandra Reddy } // namespace internal
1145eb6b827SSiva Chandra Reddy
1155eb6b827SSiva Chandra Reddy LLVM_LIBC_FUNCTION(void, qsort,
1165eb6b827SSiva Chandra Reddy (void *array, size_t array_size, size_t elem_size,
1175eb6b827SSiva Chandra Reddy int (*compare)(const void *, const void *))) {
1185eb6b827SSiva Chandra Reddy if (array == nullptr || array_size == 0 || elem_size == 0)
1195eb6b827SSiva Chandra Reddy return;
1205eb6b827SSiva Chandra Reddy internal::quicksort(internal::Array(reinterpret_cast<uint8_t *>(array),
1215eb6b827SSiva Chandra Reddy array_size, elem_size, compare));
1225eb6b827SSiva Chandra Reddy }
1235eb6b827SSiva Chandra Reddy
1245eb6b827SSiva Chandra Reddy } // namespace __llvm_libc
125