1 #ifndef ULINUX_UTILS_QSORT_C
2 #define ULINUX_UTILS_QSORT_C
4 * this code is protected by the GNU affero GPLv3
5 * author:Sylvain BERTRAND
9 #include <ulinux/compiler_types.h>
10 #include <ulinux/types.h>
12 #include <ulinux/utils/qsort.h>
13 /*----------------------------------------------------------------------------*/
14 /* "One Compilation Unit" support */
15 #ifdef ULINUX_UTILS_EXTERNAL
18 #define ULINUX_EXPORT static
20 /*----------------------------------------------------------------------------*/
22 #define swap ulinux_qsort_swap
23 /*----------------------------------------------------------------------------*/
24 static void swap(void *a
, void *b
, ulinux_u64 sz
)
47 #define LT ULINUX_QSORT_CMP_LT
48 #define LT_PIVOT ULINUX_QSORT_CMP_LT
49 #define EQ_PIVOT ULINUX_QSORT_CMP_EQ
50 #define GT_PIVOT ULINUX_QSORT_CMP_GT
51 ULINUX_EXPORT
void ulinux_qsort(void *base
, ulinux_u64 n
, ulinux_u64 sz
,
52 ulinux_s8 (*cmp
)(void *a
, void *b
))
59 /* fast paths for the low values of n, 0 1 and 2 */
63 if (cmp(base
+ sz
, base
) == LT
)
64 swap(base
, base
+ sz
, sz
);
68 /* from here n >= 3 */
70 last
= base
+ (n
- 1) * sz
;
75 * setup a pivot which is the best-of-three median with the value from
76 * the middle. Do pre-partition the values from those 3 array slots.
77 * This setup natural bounds.
79 pivot
= base
+ ((n
- 1) / 2) * sz
;
81 if (cmp(pivot
, left
) == LT_PIVOT
)
82 swap(left
, pivot
, sz
);
83 if (cmp(right
, pivot
) == LT_PIVOT
) {
84 swap(pivot
, right
, sz
);
85 if (cmp(pivot
, left
) == LT_PIVOT
)
86 swap(left
, pivot
, sz
);
89 /* the best-of-three median is a fast path for n = 3 */
93 /* from here n >= 4 */
95 /*-------------------------------------------------------------------*/
98 * - left side LT/EQ the pivot value.
99 * - right side EQ/GT the pivot value.
100 * both sides can contain slots with the pivot value.
102 left
+= sz
; /* skip the pre-partitioned array left-most value */
103 right
-= sz
; /* skip the pre-partitioned array righ-most value */
109 * this loop cannot go forever, the pre-partitioned right most
110 * slot contains a value higher or equal to the pivot
111 * value, and will not change.
114 left_cmp
= cmp(left
, pivot
);
115 if (left_cmp
!= LT_PIVOT
)
120 /* same thing than above but backward */
122 right_cmp
= cmp(pivot
, right
);
123 if (right_cmp
!= LT_PIVOT
)
129 * left points on a slot which contains:
131 * - a value higher than the pivot value.
132 * all slots below left contains values
133 * lesser than or equal to the pivot value.
135 * right points on a slot which contains:
137 * - a value lower than the pivot value.
138 * all slots above right contains values
139 * higher than or equal to the pivot value.
147 if ((left_cmp
!= EQ_PIVOT
) || (right_cmp
!= EQ_PIVOT
)) {
148 swap(left
, right
, sz
);
151 * we must keep track of the pivot value if it is
156 else if (right
== pivot
)
165 * if right < left rewind one slot for each which will be our
166 * boundaries of the partitions. if left == right, then rewind only
172 /*-------------------------------------------------------------------*/
174 ulinux_qsort(base
, (left
- (ulinux_u8
*)base
) / sz
+ 1, sz
, cmp
);
175 ulinux_qsort(right
, (last
- right
) / sz
+ 1, sz
, cmp
);
181 /*----------------------------------------------------------------------------*/