1 /*
2 * Copyright (c) 2021 Friedt Professional Engineering Services, Inc
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <stddef.h>
8 #include <stdint.h>
9 #include <stdlib.h>
10 #include <sys/types.h>
11 #include <zephyr/sys/util.h>
12
13 /*
14 * Normally parent is defined parent(k) = floor((k-1) / 2) but we can avoid a
15 * divide by noticing that floor((k-1) / 2) = ((k - 1) >> 1).
16 */
17
18 #define parent(k) (((k) - 1) >> 1)
19 /*
20 * Normally left is defined left(k) = (2 * k + 1) but we can avoid a
21 * multiply by noticing that (2 * k + 1) = ((k << 1) + 1).
22 */
23
24 #define left(k) (((k) << 1) + 1)
25
26 /*
27 * Normally right is defined right(k) = (2 * k + 2) but we can avoid a
28 * multiply by noticing that right(k) = left(k) + 1
29 */
30 #define right(k) (left(k) + 1)
31
32 #define A(k) ((uint8_t *)base + size * (k))
33
34 struct qsort_comp {
35 bool has3;
36 void *arg;
37 union {
38 int (*comp2)(const void *a, const void *b);
39 int (*comp3)(const void *a, const void *b, void *arg);
40 };
41 };
42
compare(struct qsort_comp * cmp,void * a,void * b)43 static inline int compare(struct qsort_comp *cmp, void *a, void *b)
44 {
45 if (cmp->has3) {
46 return cmp->comp3(a, b, cmp->arg);
47 }
48
49 return cmp->comp2(a, b);
50 }
51
sift_down(void * base,int start,int end,size_t size,struct qsort_comp * cmp)52 static void sift_down(void *base, int start, int end, size_t size, struct qsort_comp *cmp)
53 {
54 int root;
55 int child;
56 int swap;
57
58 for (swap = start, root = swap; left(root) < end; root = swap) {
59 child = left(root);
60
61 /* if root < left */
62 if (compare(cmp, A(swap), A(child)) < 0) {
63 swap = child;
64 }
65
66 /* right exists and min(A(root),A(left)) < A(right) */
67 if (right(root) < end && compare(cmp, A(swap), A(right(root))) < 0) {
68 swap = right(root);
69 }
70
71 if (swap == root) {
72 return;
73 }
74
75 byteswp(A(root), A(swap), size);
76 }
77 }
78
heapify(void * base,int nmemb,size_t size,struct qsort_comp * cmp)79 static void heapify(void *base, int nmemb, size_t size, struct qsort_comp *cmp)
80 {
81 int start;
82
83 for (start = parent(nmemb - 1); start >= 0; --start) {
84 sift_down(base, start, nmemb, size, cmp);
85 }
86 }
87
heap_sort(void * base,int nmemb,size_t size,struct qsort_comp * cmp)88 static void heap_sort(void *base, int nmemb, size_t size, struct qsort_comp *cmp)
89 {
90 int end;
91
92 heapify(base, nmemb, size, cmp);
93
94 for (end = nmemb - 1; end > 0; --end) {
95 byteswp(A(end), A(0), size);
96 sift_down(base, 0, end, size, cmp);
97 }
98 }
99
qsort_r(void * base,size_t nmemb,size_t size,int (* comp3)(const void * a,const void * b,void * arg),void * arg)100 void qsort_r(void *base, size_t nmemb, size_t size,
101 int (*comp3)(const void *a, const void *b, void *arg), void *arg)
102 {
103 struct qsort_comp cmp = {
104 .has3 = true,
105 .arg = arg,
106 {
107 .comp3 = comp3
108 }
109 };
110
111 heap_sort(base, nmemb, size, &cmp);
112 }
113
qsort(void * base,size_t nmemb,size_t size,int (* comp2)(const void * a,const void * b))114 void qsort(void *base, size_t nmemb, size_t size,
115 int (*comp2)(const void *a, const void *b))
116 {
117 struct qsort_comp cmp = {
118 .has3 = false,
119 .arg = NULL,
120 {
121 .comp2 = comp2
122 }
123 };
124
125 heap_sort(base, nmemb, size, &cmp);
126 }
127