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 arrays, very similar to the one
15 * FIXME: Note on thread-safety
17 * So much for advocacy, there are the parameters (those marked with [*]
20 * ASORT_PREFIX(x) [*] add a name prefix (used on all global names
21 * defined by the sorter)
22 * ASORT_KEY_TYPE [*] data type of a single array entry key
23 * ASORT_LT(x,y) x < y for ASORT_TYPE (default: "x<y")
24 * ASORT_THRESHOLD threshold for switching between quicksort and insertsort
25 * ASORT_PAGE_ALIGNED the array is guaranteed to be aligned to a multiple of CPU_PAGE_SIZE (FIXME: Do we need this?)
27 * ASORT_RADIX_BITS FIXME
28 * ASORT_SWAP FIXME: probably keep private
30 * After including this file, a function
31 * ASORT_KEY_TYPE *ASORT_PREFIX(sort)(ASORT_KEY_TYPE *array, uns num_elts, ASORT_KEY_TYPE *buf, uns hash_bits)
32 * is declared and all parameter macros are automatically undef'd.
35 #include "lib/sorter/common.h"
37 #define Q(x) ASORT_PREFIX(x)
39 typedef ASORT_KEY_TYPE Q(key);
42 #define ASORT_LT(x,y) ((x) < (y))
46 #define ASORT_SWAP(i,j) do { Q(key) tmp = array[i]; array[i]=array[j]; array[j]=tmp; } while (0)
49 #ifndef ASORT_THRESHOLD
50 #define ASORT_THRESHOLD 8 /* Guesswork and experimentation */
53 #ifndef ASORT_RADIX_BITS
54 #define ASORT_RADIX_BITS 10 // FIXME: Tune automatically?
56 #define ASORT_RADIX_MASK ((1 << (ASORT_RADIX_BITS)) - 1)
58 static void Q(quicksort)(void *array_ptr, uns num_elts)
60 Q(key) *array = array_ptr;
61 struct stk { int l, r; } stack[8*sizeof(uns)];
62 int l, r, left, right, m;
69 /* QuickSort with optimizations a'la Sedgewick, but stop at ASORT_THRESHOLD */
78 if (ASORT_LT(array[m], array[l]))
80 if (ASORT_LT(array[r], array[m]))
83 if (ASORT_LT(array[m], array[l]))
89 while (ASORT_LT(array[l], pivot))
91 while (ASORT_LT(pivot, array[r]))
106 if ((r - left) >= ASORT_THRESHOLD && (right - l) >= ASORT_THRESHOLD)
108 /* Both partitions ok => push the larger one */
109 if ((r - left) > (right - l))
123 else if ((r - left) >= ASORT_THRESHOLD)
125 /* Left partition OK, right undersize */
128 else if ((right - l) >= ASORT_THRESHOLD)
130 /* Right partition OK, left undersize */
135 /* Both partitions undersize => pop */
145 * We have a partially sorted array, finish by insertsort. Inspired
146 * by qsort() in GNU libc.
149 /* Find minimal element which will serve as a barrier */
150 r = MIN(num_elts, ASORT_THRESHOLD);
153 if (ASORT_LT(array[l], array[m]))
158 for (m=1; m<(int)num_elts; m++)
161 while (ASORT_LT(array[m], array[l-1]))
173 static void Q(radix_count)(void *src_ptr, uns num_elts, uns *cnt, uns shift)
175 Q(key) *src = src_ptr;
176 for (uns i=0; i<num_elts; i++)
177 cnt[ (ASORT_HASH(src[i]) >> shift) & ASORT_RADIX_MASK ] ++;
180 static void Q(radix_split)(void *src_ptr, void *dest_ptr, uns num_elts, uns *ptrs, uns shift)
182 Q(key) *src = src_ptr, *dest = dest_ptr;
183 for (uns i=0; i<num_elts; i++)
184 dest[ ptrs[ (ASORT_HASH(src[i]) >> shift) & ASORT_RADIX_MASK ]++ ] = src[i];
189 static Q(key) *Q(sort)(Q(key) *array, uns num_elts, Q(key) *buffer, uns hash_bits)
191 struct asort_context ctx = {
194 .num_elts = num_elts,
195 .hash_bits = hash_bits,
196 .elt_size = sizeof(Q(key)),
197 .quicksort = Q(quicksort),
199 .radix_count = Q(radix_count),
200 .radix_split = Q(radix_split),
201 .radix_bits = ASORT_RADIX_BITS,
210 #undef ASORT_KEY_TYPE
213 #undef ASORT_THRESHOLD
214 #undef ASORT_PAGE_ALIGNED
216 #undef ASORT_RADIX_BITS
217 #undef ASORT_RADIX_MASK