2 * UCW Library -- Optimized Array Sorter
4 * (c) 2003--2007 Martin Mares <mj@ucw.cz>
6 * This software may be freely distributed and used according to the terms
7 * of the GNU Lesser General Public License.
11 * This is a generator of routines for sorting huge arrays, similar to the one
12 * in ucw/sorter/array-simple.h. It cannot handle discontiguous arrays, but it is able
13 * to employ radix-sorting if a monotone hash function is available and also
14 * use several threads in parallel on SMP systems (this assumes that all
15 * callbacks you provide are thread-safe).
17 * It is usually called internally by the generic shorter machinery, but
18 * you are free to use it explicitly if you need.
20 * So much for advocacy, there are the parameters (those marked with [*]
23 * ASORT_PREFIX(x) [*] add a name prefix (used on all global names
24 * defined by the sorter)
25 * ASORT_KEY_TYPE [*] data type of a single array entry key
26 * ASORT_LT(x,y) x < y for ASORT_KEY_TYPE (default: "x<y")
27 * ASORT_HASH(x) a monotone hash function (safisfying hash(x) < hash(y) => x<y)
28 * ASORT_LONG_HASH hashes are 64-bit numbers (default is 32 bits)
30 * Fine-tuning parameters: (if you really insist)
32 * ASORT_THRESHOLD threshold for switching between quicksort and insertsort
33 * ASORT_RADIX_BITS how many bits of the hash functions are to be used at once for
36 * After including this file, a function
37 * ASORT_KEY_TYPE *ASORT_PREFIX(sort)(ASORT_KEY_TYPE *array, uns num_elts [, ASORT_KEY_TYPE *buf, uns hash_bits])
38 * is declared and all parameter macros are automatically undef'd. Here `buf' is an
39 * auxiliary buffer of the same size as the input array, required whenever radix
40 * sorting should be used, and `hash_bits' is the number of significant bits returned
41 * by the hash function. If the buffer is specified, the sorting function returns either
42 * a pointer to the input array or to the buffer, depending on where the result is stored.
43 * If you do not use hashing, these parameters should be omitted.
46 #include <ucw/sorter/common.h>
48 #define Q(x) ASORT_PREFIX(x)
50 typedef ASORT_KEY_TYPE Q(key);
53 #define ASORT_LT(x,y) ((x) < (y))
57 #define ASORT_SWAP(i,j) do { Q(key) tmp = array[i]; array[i]=array[j]; array[j]=tmp; } while (0)
60 #ifndef ASORT_THRESHOLD
61 #define ASORT_THRESHOLD 8 /* Guesswork and experimentation */
64 #ifndef ASORT_RADIX_BITS
65 #define ASORT_RADIX_BITS CONFIG_UCW_RADIX_SORTER_BITS
67 #define ASORT_RADIX_MASK ((1 << (ASORT_RADIX_BITS)) - 1)
69 /* QuickSort with optimizations a'la Sedgewick, inspired by qsort() from GNU libc. */
71 static void Q(quicksort)(void *array_ptr, uns num_elts)
73 Q(key) *array = array_ptr;
74 struct stk { int l, r; } stack[8*sizeof(uns)];
75 int l, r, left, right, m;
89 if (ASORT_LT(array[m], array[l]))
91 if (ASORT_LT(array[r], array[m]))
94 if (ASORT_LT(array[m], array[l]))
100 while (ASORT_LT(array[l], pivot))
102 while (ASORT_LT(pivot, array[r]))
117 if ((r - left) >= ASORT_THRESHOLD && (right - l) >= ASORT_THRESHOLD)
119 /* Both partitions ok => push the larger one */
120 if ((r - left) > (right - l))
134 else if ((r - left) >= ASORT_THRESHOLD)
136 /* Left partition OK, right undersize */
139 else if ((right - l) >= ASORT_THRESHOLD)
141 /* Right partition OK, left undersize */
146 /* Both partitions undersize => pop */
156 * We have a partially sorted array, finish by insertsort. Inspired
157 * by qsort() in GNU libc.
160 /* Find minimal element which will serve as a barrier */
161 r = MIN(num_elts, ASORT_THRESHOLD);
164 if (ASORT_LT(array[l], array[m]))
169 for (m=1; m<(int)num_elts; m++)
172 while (ASORT_LT(array[m], array[l-1]))
182 /* Just the splitting part of QuickSort */
184 static void Q(quicksplit)(void *array_ptr, uns num_elts, int *leftp, int *rightp)
186 Q(key) *array = array_ptr;
193 if (ASORT_LT(array[m], array[l]))
195 if (ASORT_LT(array[r], array[m]))
198 if (ASORT_LT(array[m], array[l]))
204 while (ASORT_LT(array[l], pivot))
206 while (ASORT_LT(pivot, array[r]))
227 static void Q(radix_count)(void *src_ptr, uns num_elts, uns *cnt, uns shift)
229 Q(key) *src = src_ptr;
236 for (i=0; i<num_elts; i++) \
237 cnt[ (ASORT_HASH(src[i]) >> s) & ASORT_RADIX_MASK ] ++; \
240 #ifdef ASORT_LONG_HASH
241 RC(63); RC(62); RC(61); RC(60); RC(59); RC(58); RC(57); RC(56);
242 RC(55); RC(54); RC(53); RC(52); RC(51); RC(50); RC(49); RC(48);
243 RC(47); RC(46); RC(45); RC(44); RC(43); RC(42); RC(41); RC(40);
244 RC(39); RC(38); RC(37); RC(36); RC(35); RC(34); RC(33); RC(32);
246 RC(31); RC(30); RC(29); RC(28); RC(27); RC(26); RC(25); RC(24);
247 RC(23); RC(22); RC(21); RC(20); RC(19); RC(18); RC(17); RC(16);
248 RC(15); RC(14); RC(13); RC(12); RC(11); RC(10); RC(9); RC(8);
249 RC(7); RC(6); RC(5); RC(4); RC(3); RC(2); RC(1); RC(0);
256 static void Q(radix_split)(void *src_ptr, void *dest_ptr, uns num_elts, uns *ptrs, uns shift)
258 Q(key) *src = src_ptr, *dest = dest_ptr;
265 for (i=0; i<num_elts; i++) \
266 dest[ ptrs[ (ASORT_HASH(src[i]) >> s) & ASORT_RADIX_MASK ]++ ] = src[i]; \
269 #ifdef ASORT_LONG_HASH
270 RS(63); RS(62); RS(61); RS(60); RS(59); RS(58); RS(57); RS(56);
271 RS(55); RS(54); RS(53); RS(52); RS(51); RS(50); RS(49); RS(48);
272 RS(47); RS(46); RS(45); RS(44); RS(43); RS(42); RS(41); RS(40);
273 RS(39); RS(38); RS(37); RS(36); RS(35); RS(34); RS(33); RS(32);
275 RS(31); RS(30); RS(29); RS(28); RS(27); RS(26); RS(25); RS(24);
276 RS(23); RS(22); RS(21); RS(20); RS(19); RS(18); RS(17); RS(16);
277 RS(15); RS(14); RS(13); RS(12); RS(11); RS(10); RS(9); RS(8);
278 RS(7); RS(6); RS(5); RS(4); RS(3); RS(2); RS(1); RS(0);
288 #define ASORT_HASH_ARGS , Q(key) *buffer, uns hash_bits
290 #define ASORT_HASH_ARGS
294 * The generated function. The @array is the data to be sorted, @num_elts tells
295 * how many elements the array has. If you did not provide `ASORT_HASH`, then
296 * the `ASORT_HASH_ARGS` is empty (there are only the two parameters in that
297 * case). When you provide it, the function gains two more parameters in the
298 * `ASORT_HASH_ARGS` macro. They are `ASORT_KEY_TYPE *@buffer`, which must be a
299 * memory buffer of the same size as the input array, and `uns @hash_bits`,
300 * specifying how many significant bits the hash function returns.
302 * The function returns pointer to the sorted data, either the @array or the
305 static ASORT_KEY_TYPE *ASORT_PREFIX(sort)(ASORT_KEY_TYPE *array, uns num_elts ASORT_HASH_ARGS)
307 struct asort_context ctx = {
309 .num_elts = num_elts,
310 .elt_size = sizeof(Q(key)),
311 .quicksort = Q(quicksort),
312 .quicksplit = Q(quicksplit),
315 .hash_bits = hash_bits,
316 .radix_count = Q(radix_count),
317 .radix_split = Q(radix_split),
318 .radix_bits = ASORT_RADIX_BITS,
326 #undef ASORT_KEY_TYPE
327 #undef ASORT_LONG_HASH
329 #undef ASORT_PAGE_ALIGNED
331 #undef ASORT_RADIX_BITS
332 #undef ASORT_RADIX_MASK
334 #undef ASORT_THRESHOLD
335 #undef ASORT_HASH_ARGS