~ubuntu-branches/ubuntu/breezy/avr-libc/breezy

« back to all changes in this revision

Viewing changes to libc/gnu/qsort.c

  • Committer: Bazaar Package Importer
  • Author(s): Hakan Ardo
  • Date: 2002-04-15 14:53:38 UTC
  • Revision ID: james.westby@ubuntu.com-20020415145338-c8hi0tn5bx74w7o3
Tags: upstream-20020203
ImportĀ upstreamĀ versionĀ 20020203

Show diffs side-by-side

added added

removed removed

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