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 lib/arraysort.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_TYPE (default: "x<y")
27 * ASORT_THRESHOLD threshold for switching between quicksort and insertsort
28 * ASORT_PAGE_ALIGNED the array is guaranteed to be aligned to a multiple of CPU_PAGE_SIZE (FIXME: Do we need this?)
29 * ASORT_HASH(x) a monotone hash function (safisfying hash(x) < hash(y) => x<y)
30 * ASORT_RADIX_BITS FIXME
31 * ASORT_SWAP FIXME: probably keep private
33 * After including this file, a function
34 * ASORT_KEY_TYPE *ASORT_PREFIX(sort)(ASORT_KEY_TYPE *array, uns num_elts, ASORT_KEY_TYPE *buf, uns hash_bits)
35 * is declared and all parameter macros are automatically undef'd. Here `buf' is an
36 * auxiliary buffer of the same size as the input array, required whenever radix
37 * sorting should be used, and `hash_bits' is the number of significant bits returned
38 * by the hash function. If the buffer is specified, the sorting function returns either
39 * a pointer to the input array or to the buffer, depending on where the result is stored.
40 * If you do not use hashing, these parameters should be NULL and 0, respectively.
43 #include "lib/sorter/common.h"
45 #define Q(x) ASORT_PREFIX(x)
47 typedef ASORT_KEY_TYPE Q(key);
50 #define ASORT_LT(x,y) ((x) < (y))
54 #define ASORT_SWAP(i,j) do { Q(key) tmp = array[i]; array[i]=array[j]; array[j]=tmp; } while (0)
57 #ifndef ASORT_THRESHOLD
58 #define ASORT_THRESHOLD 8 /* Guesswork and experimentation */
61 #ifndef ASORT_RADIX_BITS
62 #define ASORT_RADIX_BITS 10 // FIXME: Tune automatically?
64 #define ASORT_RADIX_MASK ((1 << (ASORT_RADIX_BITS)) - 1)
66 static void Q(quicksort)(void *array_ptr, uns num_elts)
68 Q(key) *array = array_ptr;
69 struct stk { int l, r; } stack[8*sizeof(uns)];
70 int l, r, left, right, m;
77 /* QuickSort with optimizations a'la Sedgewick, but stop at ASORT_THRESHOLD */
86 if (ASORT_LT(array[m], array[l]))
88 if (ASORT_LT(array[r], array[m]))
91 if (ASORT_LT(array[m], array[l]))
97 while (ASORT_LT(array[l], pivot))
99 while (ASORT_LT(pivot, array[r]))
114 if ((r - left) >= ASORT_THRESHOLD && (right - l) >= ASORT_THRESHOLD)
116 /* Both partitions ok => push the larger one */
117 if ((r - left) > (right - l))
131 else if ((r - left) >= ASORT_THRESHOLD)
133 /* Left partition OK, right undersize */
136 else if ((right - l) >= ASORT_THRESHOLD)
138 /* Right partition OK, left undersize */
143 /* Both partitions undersize => pop */
153 * We have a partially sorted array, finish by insertsort. Inspired
154 * by qsort() in GNU libc.
157 /* Find minimal element which will serve as a barrier */
158 r = MIN(num_elts, ASORT_THRESHOLD);
161 if (ASORT_LT(array[l], array[m]))
166 for (m=1; m<(int)num_elts; m++)
169 while (ASORT_LT(array[m], array[l-1]))
181 static void Q(radix_count)(void *src_ptr, uns num_elts, uns *cnt, uns shift)
183 Q(key) *src = src_ptr;
184 for (uns i=0; i<num_elts; i++)
185 cnt[ (ASORT_HASH(src[i]) >> shift) & ASORT_RADIX_MASK ] ++;
188 static void Q(radix_split)(void *src_ptr, void *dest_ptr, uns num_elts, uns *ptrs, uns shift)
190 Q(key) *src = src_ptr, *dest = dest_ptr;
191 for (uns i=0; i<num_elts; i++)
192 dest[ ptrs[ (ASORT_HASH(src[i]) >> shift) & ASORT_RADIX_MASK ]++ ] = src[i];
197 static Q(key) *Q(sort)(Q(key) *array, uns num_elts, Q(key) *buffer, uns hash_bits)
199 struct asort_context ctx = {
202 .num_elts = num_elts,
203 .hash_bits = hash_bits,
204 .elt_size = sizeof(Q(key)),
205 .quicksort = Q(quicksort),
207 .radix_count = Q(radix_count),
208 .radix_split = Q(radix_split),
209 .radix_bits = ASORT_RADIX_BITS,
218 #undef ASORT_KEY_TYPE
221 #undef ASORT_THRESHOLD
222 #undef ASORT_PAGE_ALIGNED
224 #undef ASORT_RADIX_BITS
225 #undef ASORT_RADIX_MASK