2 * UCW Library -- Universal Simple Array Sorter
4 * (c) 2003--2008 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 not a normal header file, it's a generator of sorting
12 * routines. Each time you include it with parameters set in the
13 * corresponding preprocessor macros, it generates an array sorter
14 * with the parameters given.
16 * You might wonder why the heck do we implement our own array sorter
17 * instead of using qsort(). The primary reason is that qsort handles
18 * only continuous arrays, but we need to sort array-like data structures
19 * where the only way to access elements is by using an indexing macro.
20 * Besides that, we are more than 2 times faster.
22 * So much for advocacy, there are the parameters (those marked with [*]
25 * ASORT_PREFIX(x) [*] add a name prefix (used on all global names
26 * defined by the sorter)
27 * ASORT_KEY_TYPE [*] data type of a single array entry key
28 * ASORT_ELT(i) returns the key of i-th element; if this macro is not
29 * defined, the function gets a pointer to an array to be sorted
30 * ASORT_LT(x,y) x < y for ASORT_TYPE (default: "x<y")
31 * ASORT_SWAP(i,j) swap i-th and j-th element (default: assume _ELT
32 * is an l-value and swap just the keys)
33 * ASORT_THRESHOLD threshold for switching between quicksort and insertsort
34 * ASORT_EXTRA_ARGS extra arguments for the sort function (they are always
35 * visible in all the macros supplied above), starts with comma
37 * After including this file, a function ASORT_PREFIX(sort)(uns array_size)
38 * or ASORT_PREFIX(sort)(ASORT_KEY_TYPE *array, uns array_size) [if ASORT_ELT
39 * is not defined] is declared and all parameter macros are automatically
44 #define ASORT_LT(x,y) ((x) < (y))
48 #define ASORT_SWAP(i,j) do { ASORT_KEY_TYPE tmp = ASORT_ELT(i); ASORT_ELT(i)=ASORT_ELT(j); ASORT_ELT(j)=tmp; } while (0)
51 #ifndef ASORT_THRESHOLD
52 #define ASORT_THRESHOLD 8 /* Guesswork and experimentation */
55 #ifndef ASORT_EXTRA_ARGS
56 #define ASORT_EXTRA_ARGS
60 #define ASORT_ARRAY_ARG ASORT_KEY_TYPE *array,
61 #define ASORT_ELT(i) array[i]
63 #define ASORT_ARRAY_ARG
67 * The generated sorting function. If `ASORT_ELT` macro is not provided, the
68 * @ASORT_ARRAY_ARG is equal to `ASORT_KEY_TYPE *array` and is the array to be
69 * sorted. If the macro is provided, this parameter is omitted. In that case,
70 * you can sort global variables or pass your structure by @ASORT_EXTRA_ARGS.
72 static void ASORT_PREFIX(sort)(ASORT_ARRAY_ARG uns array_size ASORT_EXTRA_ARGS)
74 struct stk { int l, r; } stack[8*sizeof(uns)];
75 int l, r, left, right, m;
82 /* QuickSort with optimizations a'la Sedgewick, but stop at ASORT_THRESHOLD */
85 right = array_size - 1;
91 if (ASORT_LT(ASORT_ELT(m), ASORT_ELT(l)))
93 if (ASORT_LT(ASORT_ELT(r), ASORT_ELT(m)))
96 if (ASORT_LT(ASORT_ELT(m), ASORT_ELT(l)))
102 while (ASORT_LT(ASORT_ELT(l), pivot))
104 while (ASORT_LT(pivot, ASORT_ELT(r)))
119 if ((r - left) >= ASORT_THRESHOLD && (right - l) >= ASORT_THRESHOLD)
121 /* Both partitions ok => push the larger one */
122 if ((r - left) > (right - l))
136 else if ((r - left) >= ASORT_THRESHOLD)
138 /* Left partition OK, right undersize */
141 else if ((right - l) >= ASORT_THRESHOLD)
143 /* Right partition OK, left undersize */
148 /* Both partitions undersize => pop */
158 * We have a partially sorted array, finish by insertsort. Inspired
159 * by qsort() in GNU libc.
162 /* Find minimal element which will serve as a barrier */
163 r = MIN(array_size, ASORT_THRESHOLD);
166 if (ASORT_LT(ASORT_ELT(l),ASORT_ELT(m)))
171 for (m=1; m<(int)array_size; m++)
174 while (ASORT_LT(ASORT_ELT(m),ASORT_ELT(l-1)))
185 #undef ASORT_KEY_TYPE
189 #undef ASORT_THRESHOLD
190 #undef ASORT_EXTRA_ARGS
191 #undef ASORT_ARRAY_ARG