/ stdlib / FreeBSD / qsort.c
qsort.c
  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   * 3. 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  #if defined(LIBC_SCCS) && !defined(lint)
 31  static char sccsid[] = "@(#)qsort.c	8.1 (Berkeley) 6/4/93";
 32  #endif /* LIBC_SCCS and not lint */
 33  #include <sys/cdefs.h>
 34  __FBSDID("$FreeBSD$");
 35  
 36  #include <stdbool.h>
 37  #include <stdlib.h>
 38  #include <string.h>
 39  
 40  #ifdef I_AM_QSORT_R
 41  typedef int		 cmp_t(void *, const void *, const void *);
 42  #else
 43  typedef int		 cmp_t(const void *, const void *);
 44  #endif
 45  static inline char	*med3(char *, char *, char *, cmp_t *, void *);
 46  static inline void	 swapfunc(char *, char *, size_t, int, int);
 47  
 48  #define	MIN(a, b)	((a) < (b) ? a : b)
 49  
 50  /*
 51   * Qsort routine from Bentley & McIlroy's "Engineering a Sort Function".
 52   */
 53  #define	swapcode(TYPE, parmi, parmj, n) {		\
 54  	size_t i = (n) / sizeof (TYPE);			\
 55  	TYPE *pi = (TYPE *) (parmi);		\
 56  	TYPE *pj = (TYPE *) (parmj);		\
 57  	do { 						\
 58  		TYPE	t = *pi;		\
 59  		*pi++ = *pj;				\
 60  		*pj++ = t;				\
 61  	} while (--i > 0);				\
 62  }
 63  
 64  #define	SWAPINIT(TYPE, a, es) swaptype_ ## TYPE =	\
 65  	((char *)a - (char *)0) % sizeof(TYPE) ||	\
 66  	es % sizeof(TYPE) ? 2 : es == sizeof(TYPE) ? 0 : 1;
 67  
 68  static inline void
 69  swapfunc(char *a, char *b, size_t n, int swaptype_long, int swaptype_int)
 70  {
 71  	if (swaptype_long <= 1)
 72  		swapcode(long, a, b, n)
 73  	else if (swaptype_int <= 1)
 74  		swapcode(int, a, b, n)
 75  	else
 76  		swapcode(char, a, b, n)
 77  }
 78  
 79  #define	swap(a, b)					\
 80  	if (swaptype_long == 0) {			\
 81  		long t = *(long *)(a);			\
 82  		*(long *)(a) = *(long *)(b);		\
 83  		*(long *)(b) = t;			\
 84  	} else if (swaptype_int == 0) {			\
 85  		int t = *(int *)(a);			\
 86  		*(int *)(a) = *(int *)(b);		\
 87  		*(int *)(b) = t;			\
 88  	} else						\
 89  		swapfunc(a, b, es, swaptype_long, swaptype_int)
 90  
 91  #define	vecswap(a, b, n)				\
 92  	if ((n) > 0) swapfunc(a, b, n, swaptype_long, swaptype_int)
 93  
 94  #ifdef I_AM_QSORT_R
 95  #define	CMP(t, x, y) (cmp((t), (x), (y)))
 96  #else
 97  #define	CMP(t, x, y) (cmp((x), (y)))
 98  #endif
 99  
100  /*
101   * Find the median of 3 elements
102   */
103  static inline char *
104  med3(char *a, char *b, char *c, cmp_t *cmp, void *thunk
105  #ifndef I_AM_QSORT_R
106  __unused
107  #endif
108  )
109  {
110  	return CMP(thunk, a, b) < 0 ?
111  	       (CMP(thunk, b, c) < 0 ? b : (CMP(thunk, a, c) < 0 ? c : a ))
112  	      :(CMP(thunk, b, c) > 0 ? b : (CMP(thunk, a, c) < 0 ? a : c ));
113  }
114  
115  #ifdef __LP64__
116  #define DEPTH(x)	(2 * (flsl((long)(x)) - 1))
117  #else /* !__LP64__ */
118  #define DEPTH(x)	(2 * (fls((int)(x)) - 1))
119  #endif /* __LP64__ */
120  
121  #ifdef I_AM_QSORT_R
122  int __heapsort_r(void *, size_t, size_t, void *, int (*)(void *, const void *, const void *));
123  #endif
124  
125  /*
126   * Simple insertion sort routine.
127   */
128  static bool
129  _isort(void *a, size_t n, size_t es, void *thunk, cmp_t *cmp, int swap_limit, int swaptype_long, int swaptype_int)
130  {
131  	int swap_cnt = 0;
132  	for (char *pm = (char *)a + es; pm < (char *)a + n * es; pm += es) {
133  		for (char *pl = pm; pl > (char *)a && CMP(thunk, pl - es, pl) > 0;
134  				pl -= es) {
135  			swap(pl, pl - es);
136  			if (swap_limit && ++swap_cnt > swap_limit) return false;
137  		}
138  	}
139  	return true;
140  }
141  
142  #ifdef I_AM_QSORT_R
143  static void
144  _qsort(void *a, size_t n, size_t es, void *thunk, cmp_t *cmp, int depth_limit)
145  #else
146  #define	thunk NULL
147  static void
148  _qsort(void *a, size_t n, size_t es, cmp_t *cmp, int depth_limit)
149  #endif
150  {
151  	char *pa, *pb, *pc, *pd, *pl, *pm, *pn;
152  	size_t d1, d2;
153  	int cmp_result;
154  	int swaptype_long, swaptype_int, swap_cnt;
155  
156  loop:
157  	SWAPINIT(long, a, es);
158  	SWAPINIT(int, a, es);
159  	swap_cnt = 0;
160  
161  	if (depth_limit-- <= 0) {
162  		/*
163  		 * We've hit our recursion limit, switch to heapsort
164  		 */
165  #ifdef I_AM_QSORT_R
166  		__heapsort_r(a, n, es, thunk, cmp);
167  #else
168  		heapsort(a, n, es, cmp);
169  #endif
170  		return;
171  	}
172  
173  	if (n <= 7) {
174  		/*
175  		 * For sufficiently small inputs, we'll just insertion sort.
176  		 *
177  		 * Pass 0 as swap limit, since this must complete.
178  		 */
179  		_isort(a, n, es, thunk, cmp, 0, swaptype_long, swaptype_int);
180  		return;
181  	}
182  
183  	/*
184  	 * Compute the pseudomedian.  Small arrays use 3 samples, large ones use 9.
185  	 */
186  	pl = a;
187  	pm = (char *)a + (n / 2) * es;
188  	pn = (char *)a + (n - 1) * es;
189  	if (n > 40) {
190  		size_t d = (n / 8) * es;
191  
192  		pl = med3(pl, pl + d, pl + 2 * d, cmp, thunk);
193  		pm = med3(pm - d, pm, pm + d, cmp, thunk);
194  		pn = med3(pn - 2 * d, pn - d, pn, cmp, thunk);
195  	}
196  	pm = med3(pl, pm, pn, cmp, thunk);
197  
198  	/*
199  	 * Pull the median to the front, starting us with:
200  	 *
201  	 * +-+-------------+
202  	 * |=|      ?      |
203  	 * +-+-------------+
204  	 * a pa,pb         pc,pd
205  	 */
206  	swap(a, pm);
207  	pa = pb = (char *)a + es;
208  	pc = pd = (char *)a + (n - 1) * es;
209  
210  	for (;;) {
211  		/*
212  		 * - Move b forward while it's less than the median
213  		 * - Move c backwards while it's greater than the median
214  		 * - When equal to the median, swap to the outside
215  		 */
216  		while (pb <= pc && (cmp_result = CMP(thunk, pb, a)) <= 0) {
217  			if (cmp_result == 0) {
218  				swap_cnt = 1;
219  				swap(pa, pb);
220  				pa += es;
221  			}
222  			pb += es;
223  		}
224  		while (pb <= pc && (cmp_result = CMP(thunk, pc, a)) >= 0) {
225  			if (cmp_result == 0) {
226  				swap_cnt = 1;
227  				swap(pc, pd);
228  				pd -= es;
229  			}
230  			pc -= es;
231  		}
232  		if (pb > pc)
233  			break;
234  		swap(pb, pc);
235  		swap_cnt = 1;
236  		pb += es;
237  		pc -= es;
238  	}
239  
240  	/*
241  	 * Now we've got:
242  	 *
243  	 * +---+-----+-----+---+
244  	 * | = |  <  |  >  | = |
245  	 * +---+-----+-----+---+
246  	 * a   pa  pc,pb   pd  pn
247  	 *
248  	 * So swap the '=' into the middle
249  	 */
250  
251  	pn = (char *)a + n * es;
252  	d1 = MIN(pa - (char *)a, pb - pa);
253  	vecswap(a, pb - d1, d1);
254  	d1 = MIN(pd - pc, pn - pd - es);
255  	vecswap(pb, pn - d1, d1);
256  
257  	/*
258  	 * +-----+---+---+-----+
259  	 * |  <  |   =   |  >  |
260  	 * +-----+---+---+-----+
261  	 * a                   pn
262  	 */
263  
264  	if (swap_cnt == 0) {  /* Switch to insertion sort */
265  		int r = 1 + n / 4; /* n > 7, so r >= 2 */
266  		if (!_isort(a, n, es, thunk, cmp, r, swaptype_long, swaptype_int)) {
267  			goto nevermind;
268  		}
269  		return;
270  	}
271  nevermind:
272  
273  	d1 = pb - pa;
274  	d2 = pd - pc;
275  	if (d1 <= d2) {
276  		/* Recurse on left partition, then iterate on right partition */
277  		if (d1 > es) {
278  #ifdef I_AM_QSORT_R
279  			_qsort(a, d1 / es, es, thunk, cmp, depth_limit);
280  #else
281  			_qsort(a, d1 / es, es, cmp, depth_limit);
282  #endif
283  		}
284  		if (d2 > es) {
285  			/* Iterate rather than recurse to save stack space */
286  			/* qsort(pn - d2, d2 / es, es, cmp); */
287  			a = pn - d2;
288  			n = d2 / es;
289  			goto loop;
290  		}
291  	} else {
292  		/* Recurse on right partition, then iterate on left partition */
293  		if (d2 > es) {
294  #ifdef I_AM_QSORT_R
295  			_qsort(pn - d2, d2 / es, es, thunk, cmp, depth_limit);
296  #else
297  			_qsort(pn - d2, d2 / es, es, cmp, depth_limit);
298  #endif
299  		}
300  		if (d1 > es) {
301  			/* Iterate rather than recurse to save stack space */
302  			/* qsort(a, d1 / es, es, cmp); */
303  			n = d1 / es;
304  			goto loop;
305  		}
306  	}
307  }
308  
309  void
310  #ifdef I_AM_QSORT_R
311  qsort_r(void *a, size_t n, size_t es, void *thunk, cmp_t *cmp)
312  #else
313  qsort(void *a, size_t n, size_t es, cmp_t *cmp)
314  #endif
315  {
316  	_qsort(a, n, es,
317  #ifdef I_AM_QSORT_R
318  		thunk,
319  #endif
320  		cmp, DEPTH(n));
321  }