source: trunk/third/glib2/glib/gqsort.c @ 20721

Revision 20721, 8.8 KB checked in by ghudson, 20 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r20720, which included commits to RCS files with non-trunk default branches.
Line 
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. */
61typedef struct
62{
63  char *lo;
64  char *hi;
65}
66stack_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 **/
111void
112g_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}
Note: See TracBrowser for help on using the repository browser.