4 Copyright © Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
6 ** NOTE! The following LGPL license applies to this file which is used by
7 ** the ldb library. This does NOT imply that all of Samba is released
10 This library is free software; you can redistribute it and/or
11 modify it under the terms of the GNU Lesser General Public
12 License as published by the Free Software Foundation; either
13 version 3 of the License, or (at your option) any later version.
15 This library is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 Lesser General Public License for more details.
20 You should have received a copy of the GNU Lesser General Public
21 License along with this library; if not, see <http://www.gnu.org/licenses/>.
30 #include "stable_sort.h"
32 static void sort_few(char *array
, char *aux
,
35 samba_compare_with_context_fn_t cmpfn
,
38 /* a kind of insertion sort for small n. */
43 for (i
= 1; i
< n
; i
++) {
45 /* leftwards is sorted. look until we find this one's place */
46 for (j
= i
- 1; j
>= 0; j
--) {
48 cmp
= cmpfn(a
, b
, opaque
);
55 /* a is already in the right place */
59 b
= &array
[(i
- dist
) * s
];
61 memmove(b
+ s
, b
, s
* dist
);
67 static void merge(char *dest
,
71 samba_compare_with_context_fn_t cmpfn
,
77 while (ai
< alen
&& bi
< blen
) {
78 int cmp
= cmpfn(&a
[ai
* s
], &b
[bi
* s
], opaque
);
80 memcpy(&dest
[di
* s
], &a
[ai
* s
], s
);
83 memcpy(&dest
[di
* s
], &b
[bi
* s
], s
);
89 memcpy(&dest
[di
* s
], &a
[ai
* s
], s
* (alen
- ai
));
90 } else if (bi
< blen
) {
91 memcpy(&dest
[di
* s
], &b
[bi
* s
], s
* (blen
- bi
));
96 bool stable_sort_r(void *array
, void *aux
,
99 samba_compare_with_context_fn_t cmpfn
,
102 char *src
= array
, *dest
= aux
, *tmp
= NULL
;
105 if (array
== NULL
|| aux
== NULL
) {
110 sort_few(array
, aux
, n
, s
, cmpfn
, opaque
);
114 if (n
> SIZE_MAX
/ s
) {
116 * We will have an integer overflow if we continue.
118 * This means that the *supposed* size of the allocated buffer
119 * is greater than SIZE_MAX, which is not possible in theory
120 * or practice, and is a sign the caller has got very
127 * This is kind of a bottom-up merge sort.
129 * We start but sorting into a whole lot of little runs, using an
130 * insertion sort which is efficient for small numbers. Empirically,
131 * on 2 machines, a run size of around 8 seems optimal, but the peak
132 * is wide, and it seems worth adapting the size to avoid an
133 * unbalanced final merge at the top. That is, if we pick the right
134 * runsize now, we will finish with a merge of roughly n/2:n/2, and
135 * not have to follow that with an merge of roughly n:[a few], which
136 * we would sometimes do with a fixed size at the lowest level.
138 * The aim is a runsize of n / (a power of 2) rounded up, in the
143 while (runsize
> 10) {
148 for (i
= 0; i
< n
; i
+= runsize
) {
149 size_t nn
= MIN(n
- i
, runsize
);
150 sort_few(&src
[i
* s
], aux
, nn
, s
, cmpfn
, opaque
);
153 while (runsize
< n
) {
154 for (i
= 0; i
< n
; i
+= runsize
* 2) {
158 * first run doesn't fit, meaning this chunk
159 * is already sorted. We just need to copy
163 memcpy(&dest
[i
* s
], &src
[i
* s
], nn
* s
);
169 &src
[i
* s
], runsize
,
175 &src
[i
* s
], runsize
,
176 &src
[j
* s
], runsize
,
188 * We have sorted the array into src, which is either array or aux.
191 memcpy(array
, src
, n
* s
);
199 * A wrapper that allocates (and frees) the temporary buffer if necessary.
201 * returns false on allocation error, true otherwise.
204 bool stable_sort_talloc_r(TALLOC_CTX
*mem_ctx
,
208 samba_compare_with_context_fn_t cmpfn
,
212 char *mem
= talloc_array_size(mem_ctx
, s
, n
);
216 ok
= stable_sort_r(array
, mem
, n
, s
, cmpfn
, opaque
);
222 bool stable_sort(void *array
, void *aux
,
225 samba_compare_fn_t cmpfn
)
228 * What is this magic, casting cmpfn into a different type that takes
229 * an extra parameter? Is that allowed?
231 * A: Yes. It's fine. The extra argument will be passed on the stack
232 * or (more likely) a register, and the cmpfn will remain blissfully
235 return stable_sort_r(array
, aux
, n
, s
,
236 (samba_compare_with_context_fn_t
)cmpfn
,
241 bool stable_sort_talloc(TALLOC_CTX
*mem_ctx
,
245 samba_compare_fn_t cmpfn
)
247 return stable_sort_talloc_r(mem_ctx
, array
, n
, s
,
248 (samba_compare_with_context_fn_t
)cmpfn
,