Embedded Artistry libc
C Standard Library Support for Bare-metal Systems
qsort.c
Go to the documentation of this file.
1 /*-
2  * Copyright (c) 1992, 1993
3  * The Regents of the University of California. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  * 4. Neither the name of the University nor the names of its contributors
14  * may be used to endorse or promote products derived from this software
15  * without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29 
30 #include <stdlib.h>
31 #include <string.h>
32 #include <strings.h>
33 
34 #ifdef I_AM_QSORT_R
35 typedef int cmp_t(void*, const void*, const void*);
36 #else
37 typedef int cmp_t(const void*, const void*);
38 #endif
39 static inline char* med3(char* a, char* b, char* c, cmp_t* cmd, void* thunk)
40  __attribute__((always_inline));
41 static inline void swapfunc(char* a, char* b, size_t n, size_t swaptype)
42  __attribute__((always_inline));
43 
44 #define min(a, b) (a) < (b) ? a : b
45 
46 /*
47  * Qsort routine from Bentley & McIlroy's "Engineering a Sort Function".
48  */
49 #define swapcode(TYPE, parmi, parmj, n) \
50  { \
51  size_t i = (n) / sizeof(TYPE); \
52  TYPE* pi = (TYPE*)(parmi); \
53  TYPE* pj = (TYPE*)(parmj); \
54  do \
55  { \
56  TYPE t = *pi; \
57  *pi++ = *pj; \
58  *pj++ = t; \
59  } while(--i > 0); \
60  }
61 
62 #define SWAPINIT(a, es) \
63  swaptype = (uintptr_t)a % sizeof(long) || es % sizeof(long) ? 2 : es == sizeof(long) ? 0 : 1;
64 
65 static inline void swapfunc(char* a, char* b, size_t n, size_t swaptype)
66 {
67  if(swaptype == 0)
68  {
69  long t = *(long*)(void*)(a);
70  *(long*)(void*)(a) = *(long*)(void*)(b);
71  *(long*)(void*)(b) = t;
72  }
73  else if(swaptype == 1)
74  {
75  swapcode(long, (void*)a, (void*)b, n)
76  }
77  else
78  {
79  swapcode(char, a, b, n)
80  }
81 }
82 
83 #define swap(a, b) swapfunc(a, b, (size_t)es, (size_t)swaptype)
84 
85 // this switch exists because we needed to clean up
86 // the swap() macro, and vecswap has a different 0 meaning.
87 // To force the right swapfunc behavior we force it to 1 if it's
88 #define vecswap(a, b, n) \
89  if((n) > 0) \
90  swapfunc(a, b, n, swaptype ? (size_t)swaptype : 1)
91 
92 #ifdef I_AM_QSORT_R
93 #define CMP(t, x, y) (cmp((t), (x), (y)))
94 #else
95 #define CMP(t, x, y) (cmp((x), (y)))
96 #endif
97 
98 static inline char* med3(char* a, char* b, char* c, cmp_t* cmp,
99  void* thunk
100 #ifndef I_AM_QSORT_R
101  __attribute__((unused))
102 #endif
103 )
104 {
105  return CMP(thunk, a, b) < 0 ? (CMP(thunk, b, c) < 0 ? b : (CMP(thunk, a, c) < 0 ? c : a))
106  : (CMP(thunk, b, c) > 0 ? b : (CMP(thunk, a, c) < 0 ? a : c));
107 }
108 
109 #ifdef __LP64__
110 #define DEPTH(x) (2 * (flsl((long)(x)) - 1))
111 #else /* !__LP64__ */
112 #define DEPTH(x) (2 * (fls((int)(x)) - 1))
113 #endif /* __LP64__ */
114 
115 static void _qsort(void* a, size_t n, size_t es,
116 #ifdef I_AM_QSORT_R
117  void* thunk,
118 #else
119 #define thunk NULL
120 #endif
121  cmp_t* cmp, int depth_limit)
122 {
123  char *pa, *pb, *pc, *pd, *pl, *pm, *pn;
124  size_t d, r, swap_cnt;
125  int cmp_result;
126  int swaptype;
127 
128 loop:
129  if(depth_limit-- <= 0)
130  {
131 #ifdef I_AM_QSORT_R
132  heapsort_r(a, n, es, thunk, cmp);
133 #else
134  heapsort(a, n, es, cmp);
135 #endif
136  return;
137  }
138  SWAPINIT(a, es);
139  swap_cnt = 0;
140  if(n < 7)
141  {
142  for(pm = (char*)a + es; pm < (char*)a + n * es; pm += es)
143  {
144  for(pl = pm; pl > (char*)a && CMP(thunk, pl - es, pl) > 0; pl -= es)
145  {
146  swap(pl, pl - es);
147  }
148  }
149  return;
150  }
151  pm = (char*)a + (n / 2) * es;
152  if(n > 7)
153  {
154  pl = a;
155  pn = (char*)a + (n - 1) * es;
156  if(n > 40)
157  {
158  d = (n / 8) * es;
159  pl = med3(pl, pl + d, pl + 2 * d, cmp, thunk);
160  pm = med3(pm - d, pm, pm + d, cmp, thunk);
161  pn = med3(pn - 2 * d, pn - d, pn, cmp, thunk);
162  }
163  pm = med3(pl, pm, pn, cmp, thunk);
164  }
165  swap(a, (void*)pm);
166  pa = pb = (char*)a + es;
167 
168  pc = pd = (char*)a + (n - 1) * es;
169  for(;;)
170  {
171  while(pb <= pc && (cmp_result = CMP(thunk, pb, a)) <= 0)
172  {
173  if(cmp_result == 0)
174  {
175  swap_cnt = 1;
176  swap(pa, pb);
177  pa += es;
178  }
179  pb += es;
180  }
181  while(pb <= pc && (cmp_result = CMP(thunk, pc, a)) >= 0)
182  {
183  if(cmp_result == 0)
184  {
185  swap_cnt = 1;
186  swap(pc, pd);
187  pd -= es;
188  }
189  pc -= es;
190  }
191  if(pb > pc)
192  {
193  break;
194  }
195  swap(pb, pc);
196  swap_cnt = 1;
197  pb += es;
198  pc -= es;
199  }
200 
201  pn = (char*)a + n * es;
202  r = min((uintptr_t)pa - (uintptr_t)a, (uintptr_t)pb - (uintptr_t)pa);
203  vecswap(a, pb - r, r);
204  r = min((uintptr_t)pd - (uintptr_t)pc, (uintptr_t)pn - (uintptr_t)pd - (uintptr_t)es);
205  vecswap(pb, pn - r, r);
206 
207  if(swap_cnt == 0)
208  { /* Switch to insertion sort */
209  r = 1 + n / 4; /* n >= 7, so r >= 2 */
210  for(pm = (char*)a + es; pm < (char*)a + n * es; pm += es)
211  {
212  for(pl = pm; pl > (char*)a && CMP(thunk, pl - es, pl) > 0; pl -= es)
213  {
214  swap(pl, pl - es);
215  if(++swap_cnt > r)
216  {
217  goto nevermind;
218  }
219  }
220  }
221  return;
222  }
223 
224 nevermind:
225  if((r = (uintptr_t)pb - (uintptr_t)pa) > es)
226  {
227 #ifdef I_AM_QSORT_R
228  _qsort(a, r / es, es, thunk, cmp, depth_limit);
229 #else
230  _qsort(a, r / es, es, cmp, depth_limit);
231 #endif
232  }
233  if((r = (uintptr_t)pd - (uintptr_t)pc) > es)
234  {
235  /* Iterate rather than recurse to save stack space */
236  a = pn - r;
237  n = r / es;
238  goto loop;
239  }
240  /* qsort(pn - r, r / es, es, cmp);*/
241 }
242 
243 void
244 #ifdef I_AM_QSORT_R
245 qsort_r(void *a, size_t n, size_t es, void *thunk, cmp_t *cmp)
246 #else
247 qsort(void *a, size_t n, size_t es, cmp_t *cmp)
248 #endif
249 {
250  _qsort(a, n, es,
251 #ifdef I_AM_QSORT_R
252  thunk,
253 #endif
254  cmp, DEPTH(n));
255 }
#define swap(a, b)
Definition: qsort.c:83
__attribute__((noreturn, weak)) void __assert_fail(const char *expr
#define SWAPINIT(a, es)
Definition: qsort.c:62
void qsort_r(void *a, size_t n, size_t es, void *thunk, int(*cmp)(void *, const void *, const void *))
Sorts the given array pointed to by ptr in ascending order.
void qsort(void *a, size_t n, size_t es, cmp_t *cmp)
Definition: qsort.c:247
#define I_AM_QSORT_R
Definition: qsort_r.c:7
int cmp_t(const void *, const void *)
Definition: qsort.c:37
static void swapfunc(char *a, char *b, size_t n, size_t swaptype) __attribute__((always_inline))
Definition: qsort.c:65
#define NULL
Definition: stddef.h:15
#define swapcode(TYPE, parmi, parmj, n)
Definition: qsort.c:49
#define CMP(t, x, y)
Definition: qsort.c:95
static char * med3(char *a, char *b, char *c, cmp_t *cmd, void *thunk) __attribute__((always_inline))
#define vecswap(a, b, n)
Definition: qsort.c:88
int cmp(Bigint *a, Bigint *b)
Definition: misc.c:570
int heapsort(void *vbase, size_t nmemb, size_t size, int(*compar)(const void *, const void *))
Sorts the given array pointed to by vbase in ascending order.
#define DEPTH(x)
Definition: qsort.c:112
#define min(a, b)
Definition: qsort.c:44
static void _qsort(void *a, size_t n, size_t es, #define thunk cmp_t *cmp, int depth_limit)
Definition: qsort.c:115
#define thunk
int heapsort_r(void *vbase, size_t nmemb, size_t size, void *thunk, int(*compar)(void *, const void *, const void *))
Sorts the given array pointed to by vbase in ascending order.