1 | /* GLIB - Library of useful routines for C programming |
---|
2 | * Copyright (C) 1991, 1992, 1996, 1997 Free Software Foundation, Inc. |
---|
3 | * Copyright (C) 2000 Eazel, Inc. |
---|
4 | * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald |
---|
5 | * |
---|
6 | * This library is free software; you can redistribute it and/or |
---|
7 | * modify it under the terms of the GNU Lesser General Public |
---|
8 | * License as published by the Free Software Foundation; either |
---|
9 | * version 2 of the License, or (at your option) any later version. |
---|
10 | * |
---|
11 | * This library is distributed in the hope that it will be useful, |
---|
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
---|
14 | * Lesser General Public License for more details. |
---|
15 | * |
---|
16 | * You should have received a copy of the GNU Lesser General Public |
---|
17 | * License along with this library; if not, write to the |
---|
18 | * Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
---|
19 | * Boston, MA 02111-1307, USA. |
---|
20 | */ |
---|
21 | |
---|
22 | /* |
---|
23 | * This file was originally part of the GNU C Library, and was modified to allow |
---|
24 | * user data to be passed in to the sorting function. |
---|
25 | * |
---|
26 | * Written by Douglas C. Schmidt (schmidt@ics.uci.edu). |
---|
27 | * Modified by Maciej Stachowiak (mjs@eazel.com) |
---|
28 | * |
---|
29 | * Modified by the GLib Team and others 1997-2000. See the AUTHORS |
---|
30 | * file for a list of people on the GLib Team. See the ChangeLog |
---|
31 | * files for a list of changes. These files are distributed with GLib |
---|
32 | * at ftp://ftp.gtk.org/pub/gtk/. |
---|
33 | */ |
---|
34 | |
---|
35 | #include "config.h" |
---|
36 | |
---|
37 | #include <string.h> |
---|
38 | |
---|
39 | #include "glib.h" |
---|
40 | |
---|
41 | |
---|
42 | /* Byte-wise swap two items of size SIZE. */ |
---|
43 | #define SWAP(a, b, size) \ |
---|
44 | do \ |
---|
45 | { \ |
---|
46 | register size_t __size = (size); \ |
---|
47 | register char *__a = (a), *__b = (b); \ |
---|
48 | do \ |
---|
49 | { \ |
---|
50 | char __tmp = *__a; \ |
---|
51 | *__a++ = *__b; \ |
---|
52 | *__b++ = __tmp; \ |
---|
53 | } while (--__size > 0); \ |
---|
54 | } while (0) |
---|
55 | |
---|
56 | /* Discontinue quicksort algorithm when partition gets below this size. |
---|
57 | This particular magic number was chosen to work best on a Sun 4/260. */ |
---|
58 | #define MAX_THRESH 4 |
---|
59 | |
---|
60 | /* Stack node declarations used to store unfulfilled partition obligations. */ |
---|
61 | typedef struct |
---|
62 | { |
---|
63 | char *lo; |
---|
64 | char *hi; |
---|
65 | } |
---|
66 | stack_node; |
---|
67 | |
---|
68 | /* The next 4 #defines implement a very fast in-line stack abstraction. */ |
---|
69 | #define STACK_SIZE (8 * sizeof(unsigned long int)) |
---|
70 | #define PUSH(low, high) ((void) ((top->lo = (low)), (top->hi = (high)), ++top)) |
---|
71 | #define POP(low, high) ((void) (--top, (low = top->lo), (high = top->hi))) |
---|
72 | #define STACK_NOT_EMPTY (stack < top) |
---|
73 | |
---|
74 | |
---|
75 | /* Order size using quicksort. This implementation incorporates |
---|
76 | * four optimizations discussed in Sedgewick: |
---|
77 | * |
---|
78 | * 1. Non-recursive, using an explicit stack of pointer that store the next |
---|
79 | * array partition to sort. To save time, this maximum amount of space |
---|
80 | * required to store an array of MAX_INT is allocated on the stack. Assuming |
---|
81 | * a 32-bit integer, this needs only 32 * sizeof(stack_node) == 136 bits. |
---|
82 | * Pretty cheap, actually. |
---|
83 | * |
---|
84 | * 2. Chose the pivot element using a median-of-three decision tree. This |
---|
85 | * reduces the probability of selecting a bad pivot value and eliminates |
---|
86 | * certain * extraneous comparisons. |
---|
87 | * |
---|
88 | * 3. Only quicksorts TOTAL_ELEMS / MAX_THRESH partitions, leaving insertion |
---|
89 | * sort to order the MAX_THRESH items within each partition. This is a big |
---|
90 | * win, since insertion sort is faster for small, mostly sorted array |
---|
91 | * segments. |
---|
92 | * |
---|
93 | * 4. The larger of the two sub-partitions is always pushed onto the stack |
---|
94 | * first, with the algorithm then concentrating on the smaller partition. |
---|
95 | * This *guarantees* no more than log (n) stack size is needed (actually O(1) |
---|
96 | * in this case)! |
---|
97 | */ |
---|
98 | |
---|
99 | /** |
---|
100 | * g_qsort_with_data: |
---|
101 | * @pbase: start of array to sort |
---|
102 | * @total_elems: elements in the array |
---|
103 | * @size: size of each element |
---|
104 | * @compare_func: function to compare elements |
---|
105 | * @user_data: data to pass to @compare_func |
---|
106 | * |
---|
107 | * This is just like the standard C qsort() function, but |
---|
108 | * the comparison routine accepts a user data argument. |
---|
109 | * |
---|
110 | **/ |
---|
111 | void |
---|
112 | g_qsort_with_data (gconstpointer pbase, |
---|
113 | gint total_elems, |
---|
114 | gsize size, |
---|
115 | GCompareDataFunc compare_func, |
---|
116 | gpointer user_data) |
---|
117 | { |
---|
118 | register char *base_ptr = (char *) pbase; |
---|
119 | |
---|
120 | /* Allocating SIZE bytes for a pivot buffer facilitates a better |
---|
121 | * algorithm below since we can do comparisons directly on the pivot. |
---|
122 | */ |
---|
123 | char *pivot_buffer = (char *) g_alloca (size); |
---|
124 | const size_t max_thresh = MAX_THRESH * size; |
---|
125 | |
---|
126 | g_return_if_fail (total_elems >= 0); |
---|
127 | g_return_if_fail (pbase != NULL || total_elems == 0); |
---|
128 | g_return_if_fail (compare_func != NULL); |
---|
129 | |
---|
130 | if (total_elems == 0) |
---|
131 | return; |
---|
132 | |
---|
133 | if (total_elems > MAX_THRESH) |
---|
134 | { |
---|
135 | char *lo = base_ptr; |
---|
136 | char *hi = &lo[size * (total_elems - 1)]; |
---|
137 | /* Largest size needed for 32-bit int!!! */ |
---|
138 | stack_node stack[STACK_SIZE]; |
---|
139 | stack_node *top = stack + 1; |
---|
140 | |
---|
141 | while (STACK_NOT_EMPTY) |
---|
142 | { |
---|
143 | char *left_ptr; |
---|
144 | char *right_ptr; |
---|
145 | |
---|
146 | char *pivot = pivot_buffer; |
---|
147 | |
---|
148 | /* Select median value from among LO, MID, and HI. Rearrange |
---|
149 | * LO and HI so the three values are sorted. This lowers the |
---|
150 | * probability of picking a pathological pivot value and |
---|
151 | * skips a comparison for both the LEFT_PTR and RIGHT_PTR. */ |
---|
152 | |
---|
153 | char *mid = lo + size * ((hi - lo) / size >> 1); |
---|
154 | |
---|
155 | if ((*compare_func) ((void *) mid, (void *) lo, user_data) < 0) |
---|
156 | SWAP (mid, lo, size); |
---|
157 | if ((*compare_func) ((void *) hi, (void *) mid, user_data) < 0) |
---|
158 | SWAP (mid, hi, size); |
---|
159 | else |
---|
160 | goto jump_over; |
---|
161 | if ((*compare_func) ((void *) mid, (void *) lo, user_data) < 0) |
---|
162 | SWAP (mid, lo, size); |
---|
163 | jump_over:; |
---|
164 | memcpy (pivot, mid, size); |
---|
165 | pivot = pivot_buffer; |
---|
166 | |
---|
167 | left_ptr = lo + size; |
---|
168 | right_ptr = hi - size; |
---|
169 | |
---|
170 | /* Here's the famous ``collapse the walls'' section of quicksort. |
---|
171 | * Gotta like those tight inner loops! They are the main reason |
---|
172 | * that this algorithm runs much faster than others. */ |
---|
173 | do |
---|
174 | { |
---|
175 | while ((*compare_func) |
---|
176 | ((void *) left_ptr, (void *) pivot, |
---|
177 | user_data) < 0) |
---|
178 | left_ptr += size; |
---|
179 | |
---|
180 | while ((*compare_func) |
---|
181 | ((void *) pivot, (void *) right_ptr, |
---|
182 | user_data) < 0) |
---|
183 | right_ptr -= size; |
---|
184 | |
---|
185 | if (left_ptr < right_ptr) |
---|
186 | { |
---|
187 | SWAP (left_ptr, right_ptr, size); |
---|
188 | left_ptr += size; |
---|
189 | right_ptr -= size; |
---|
190 | } |
---|
191 | else if (left_ptr == right_ptr) |
---|
192 | { |
---|
193 | left_ptr += size; |
---|
194 | right_ptr -= size; |
---|
195 | break; |
---|
196 | } |
---|
197 | } |
---|
198 | while (left_ptr <= right_ptr); |
---|
199 | |
---|
200 | /* Set up pointers for next iteration. First determine whether |
---|
201 | * left and right partitions are below the threshold size. If so, |
---|
202 | * ignore one or both. Otherwise, push the larger partition's |
---|
203 | * bounds on the stack and continue sorting the smaller one. */ |
---|
204 | |
---|
205 | if ((size_t) (right_ptr - lo) <= max_thresh) |
---|
206 | { |
---|
207 | if ((size_t) (hi - left_ptr) <= max_thresh) |
---|
208 | /* Ignore both small partitions. */ |
---|
209 | POP (lo, hi); |
---|
210 | else |
---|
211 | /* Ignore small left partition. */ |
---|
212 | lo = left_ptr; |
---|
213 | } |
---|
214 | else if ((size_t) (hi - left_ptr) <= max_thresh) |
---|
215 | /* Ignore small right partition. */ |
---|
216 | hi = right_ptr; |
---|
217 | else if ((right_ptr - lo) > (hi - left_ptr)) |
---|
218 | { |
---|
219 | /* Push larger left partition indices. */ |
---|
220 | PUSH (lo, right_ptr); |
---|
221 | lo = left_ptr; |
---|
222 | |
---|
223 | } |
---|
224 | else |
---|
225 | { |
---|
226 | /* Push larger right partition indices. */ |
---|
227 | PUSH (left_ptr, hi); |
---|
228 | hi = right_ptr; |
---|
229 | } |
---|
230 | } |
---|
231 | } |
---|
232 | |
---|
233 | /* Once the BASE_PTR array is partially sorted by quicksort the rest |
---|
234 | * is completely sorted using insertion sort, since this is efficient |
---|
235 | * for partitions below MAX_THRESH size. BASE_PTR points to the beginning |
---|
236 | * of the array to sort, and END_PTR points at the very last element in |
---|
237 | * the array (*not* one beyond it!). */ |
---|
238 | |
---|
239 | { |
---|
240 | char *const end_ptr = &base_ptr[size * (total_elems - 1)]; |
---|
241 | char *tmp_ptr = base_ptr; |
---|
242 | char *thresh = MIN (end_ptr, base_ptr + max_thresh); |
---|
243 | register char *run_ptr; |
---|
244 | |
---|
245 | /* Find smallest element in first threshold and place it at the |
---|
246 | * array's beginning. This is the smallest array element, |
---|
247 | * and the operation speeds up insertion sort's inner loop. */ |
---|
248 | |
---|
249 | for (run_ptr = tmp_ptr + size; run_ptr <= thresh; |
---|
250 | run_ptr += |
---|
251 | size) if ((*compare_func) ((void *) run_ptr, (void *) tmp_ptr, |
---|
252 | user_data) < 0) |
---|
253 | tmp_ptr = run_ptr; |
---|
254 | |
---|
255 | if (tmp_ptr != base_ptr) |
---|
256 | SWAP (tmp_ptr, base_ptr, size); |
---|
257 | |
---|
258 | /* Insertion sort, running from left-hand-side up to right-hand-side. */ |
---|
259 | |
---|
260 | run_ptr = base_ptr + size; |
---|
261 | while ((run_ptr += size) <= end_ptr) |
---|
262 | { |
---|
263 | tmp_ptr = run_ptr - size; |
---|
264 | while ((*compare_func) |
---|
265 | ((void *) run_ptr, (void *) tmp_ptr, |
---|
266 | user_data) < 0) |
---|
267 | tmp_ptr -= size; |
---|
268 | |
---|
269 | tmp_ptr += size; |
---|
270 | if (tmp_ptr != run_ptr) |
---|
271 | { |
---|
272 | char *trav; |
---|
273 | |
---|
274 | trav = run_ptr + size; |
---|
275 | while (--trav >= run_ptr) |
---|
276 | { |
---|
277 | char c = *trav; |
---|
278 | char *hi, *lo; |
---|
279 | |
---|
280 | for (hi = lo = trav; |
---|
281 | (lo -= size) >= tmp_ptr; hi = lo) |
---|
282 | *hi = *lo; |
---|
283 | *hi = c; |
---|
284 | } |
---|
285 | } |
---|
286 | } |
---|
287 | } |
---|
288 | } |
---|