11573Srgrimes/*-
21573Srgrimes * Copyright (c) 1992, 1993
31573Srgrimes *	The Regents of the University of California.  All rights reserved.
41573Srgrimes *
51573Srgrimes * Redistribution and use in source and binary forms, with or without
61573Srgrimes * modification, are permitted provided that the following conditions
71573Srgrimes * are met:
81573Srgrimes * 1. Redistributions of source code must retain the above copyright
91573Srgrimes *    notice, this list of conditions and the following disclaimer.
101573Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
111573Srgrimes *    notice, this list of conditions and the following disclaimer in the
121573Srgrimes *    documentation and/or other materials provided with the distribution.
13251672Semaste * 3. Neither the name of the University nor the names of its contributors
141573Srgrimes *    may be used to endorse or promote products derived from this software
151573Srgrimes *    without specific prior written permission.
161573Srgrimes *
171573Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
181573Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
191573Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
201573Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
211573Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
221573Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
231573Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
241573Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
251573Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
261573Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
271573Srgrimes * SUCH DAMAGE.
281573Srgrimes */
291573Srgrimes
301573Srgrimes#if defined(LIBC_SCCS) && !defined(lint)
311573Srgrimesstatic char sccsid[] = "@(#)qsort.c	8.1 (Berkeley) 6/4/93";
321573Srgrimes#endif /* LIBC_SCCS and not lint */
3392986Sobrien#include <sys/cdefs.h>
3492986Sobrien__FBSDID("$FreeBSD$");
351573Srgrimes
361573Srgrimes#include <stdlib.h>
371573Srgrimes
38103165Swollman#ifdef I_AM_QSORT_R
39103165Swollmantypedef int		 cmp_t(void *, const void *, const void *);
40103165Swollman#else
4192905Sobrientypedef int		 cmp_t(const void *, const void *);
42103165Swollman#endif
43103165Swollmanstatic inline char	*med3(char *, char *, char *, cmp_t *, void *);
4492905Sobrienstatic inline void	 swapfunc(char *, char *, int, int);
451573Srgrimes
461573Srgrimes#define min(a, b)	(a) < (b) ? a : b
471573Srgrimes
481573Srgrimes/*
491573Srgrimes * Qsort routine from Bentley & McIlroy's "Engineering a Sort Function".
501573Srgrimes */
511573Srgrimes#define swapcode(TYPE, parmi, parmj, n) { 		\
521573Srgrimes	long i = (n) / sizeof (TYPE); 			\
5392889Sobrien	TYPE *pi = (TYPE *) (parmi); 		\
5492889Sobrien	TYPE *pj = (TYPE *) (parmj); 		\
551573Srgrimes	do { 						\
5692889Sobrien		TYPE	t = *pi;		\
571573Srgrimes		*pi++ = *pj;				\
581573Srgrimes		*pj++ = t;				\
591573Srgrimes        } while (--i > 0);				\
601573Srgrimes}
611573Srgrimes
621573Srgrimes#define SWAPINIT(a, es) swaptype = ((char *)a - (char *)0) % sizeof(long) || \
631573Srgrimes	es % sizeof(long) ? 2 : es == sizeof(long)? 0 : 1;
641573Srgrimes
651573Srgrimesstatic inline void
661573Srgrimesswapfunc(a, b, n, swaptype)
671573Srgrimes	char *a, *b;
681573Srgrimes	int n, swaptype;
691573Srgrimes{
708870Srgrimes	if(swaptype <= 1)
711573Srgrimes		swapcode(long, a, b, n)
721573Srgrimes	else
731573Srgrimes		swapcode(char, a, b, n)
741573Srgrimes}
751573Srgrimes
761573Srgrimes#define swap(a, b)					\
771573Srgrimes	if (swaptype == 0) {				\
781573Srgrimes		long t = *(long *)(a);			\
791573Srgrimes		*(long *)(a) = *(long *)(b);		\
801573Srgrimes		*(long *)(b) = t;			\
811573Srgrimes	} else						\
821573Srgrimes		swapfunc(a, b, es, swaptype)
831573Srgrimes
841573Srgrimes#define vecswap(a, b, n) 	if ((n) > 0) swapfunc(a, b, n, swaptype)
851573Srgrimes
86103165Swollman#ifdef I_AM_QSORT_R
87103165Swollman#define	CMP(t, x, y) (cmp((t), (x), (y)))
88103165Swollman#else
89103165Swollman#define	CMP(t, x, y) (cmp((x), (y)))
90103165Swollman#endif
91103165Swollman
921573Srgrimesstatic inline char *
93103165Swollmanmed3(char *a, char *b, char *c, cmp_t *cmp, void *thunk
94103165Swollman#ifndef I_AM_QSORT_R
95103165Swollman__unused
96103165Swollman#endif
97103165Swollman)
981573Srgrimes{
99103165Swollman	return CMP(thunk, a, b) < 0 ?
100103165Swollman	       (CMP(thunk, b, c) < 0 ? b : (CMP(thunk, a, c) < 0 ? c : a ))
101103165Swollman              :(CMP(thunk, b, c) > 0 ? b : (CMP(thunk, a, c) < 0 ? a : c ));
1021573Srgrimes}
1031573Srgrimes
104103165Swollman#ifdef I_AM_QSORT_R
1051573Srgrimesvoid
106103165Swollmanqsort_r(void *a, size_t n, size_t es, void *thunk, cmp_t *cmp)
107103165Swollman#else
108103165Swollman#define thunk NULL
109103165Swollmanvoid
110103165Swollmanqsort(void *a, size_t n, size_t es, cmp_t *cmp)
111103165Swollman#endif
1121573Srgrimes{
1131573Srgrimes	char *pa, *pb, *pc, *pd, *pl, *pm, *pn;
114175259Sdas	size_t d, r;
115175317Sdas	int cmp_result;
116175259Sdas	int swaptype, swap_cnt;
1171573Srgrimes
1181573Srgrimesloop:	SWAPINIT(a, es);
1191573Srgrimes	swap_cnt = 0;
1201573Srgrimes	if (n < 7) {
12117971Sbde		for (pm = (char *)a + es; pm < (char *)a + n * es; pm += es)
122103165Swollman			for (pl = pm;
123103165Swollman			     pl > (char *)a && CMP(thunk, pl - es, pl) > 0;
1241573Srgrimes			     pl -= es)
1251573Srgrimes				swap(pl, pl - es);
1261573Srgrimes		return;
1271573Srgrimes	}
12817971Sbde	pm = (char *)a + (n / 2) * es;
1291573Srgrimes	if (n > 7) {
1301573Srgrimes		pl = a;
13117971Sbde		pn = (char *)a + (n - 1) * es;
1321573Srgrimes		if (n > 40) {
1331573Srgrimes			d = (n / 8) * es;
134103165Swollman			pl = med3(pl, pl + d, pl + 2 * d, cmp, thunk);
135103165Swollman			pm = med3(pm - d, pm, pm + d, cmp, thunk);
136103165Swollman			pn = med3(pn - 2 * d, pn - d, pn, cmp, thunk);
1371573Srgrimes		}
138103165Swollman		pm = med3(pl, pm, pn, cmp, thunk);
1391573Srgrimes	}
1401573Srgrimes	swap(a, pm);
14117971Sbde	pa = pb = (char *)a + es;
1421573Srgrimes
14317971Sbde	pc = pd = (char *)a + (n - 1) * es;
1441573Srgrimes	for (;;) {
145175317Sdas		while (pb <= pc && (cmp_result = CMP(thunk, pb, a)) <= 0) {
146175317Sdas			if (cmp_result == 0) {
1471573Srgrimes				swap_cnt = 1;
1481573Srgrimes				swap(pa, pb);
1491573Srgrimes				pa += es;
1501573Srgrimes			}
1511573Srgrimes			pb += es;
1521573Srgrimes		}
153175317Sdas		while (pb <= pc && (cmp_result = CMP(thunk, pc, a)) >= 0) {
154175317Sdas			if (cmp_result == 0) {
1551573Srgrimes				swap_cnt = 1;
1561573Srgrimes				swap(pc, pd);
1571573Srgrimes				pd -= es;
1581573Srgrimes			}
1591573Srgrimes			pc -= es;
1601573Srgrimes		}
1611573Srgrimes		if (pb > pc)
1621573Srgrimes			break;
1631573Srgrimes		swap(pb, pc);
1641573Srgrimes		swap_cnt = 1;
1651573Srgrimes		pb += es;
1661573Srgrimes		pc -= es;
1671573Srgrimes	}
1681573Srgrimes	if (swap_cnt == 0) {  /* Switch to insertion sort */
16917971Sbde		for (pm = (char *)a + es; pm < (char *)a + n * es; pm += es)
170103165Swollman			for (pl = pm;
171103165Swollman			     pl > (char *)a && CMP(thunk, pl - es, pl) > 0;
1721573Srgrimes			     pl -= es)
1731573Srgrimes				swap(pl, pl - es);
1741573Srgrimes		return;
1751573Srgrimes	}
1761573Srgrimes
17717971Sbde	pn = (char *)a + n * es;
1781573Srgrimes	r = min(pa - (char *)a, pb - pa);
1791573Srgrimes	vecswap(a, pb - r, r);
1801573Srgrimes	r = min(pd - pc, pn - pd - es);
1811573Srgrimes	vecswap(pb, pn - r, r);
1821573Srgrimes	if ((r = pb - pa) > es)
183103165Swollman#ifdef I_AM_QSORT_R
184103165Swollman		qsort_r(a, r / es, es, thunk, cmp);
185103165Swollman#else
1861573Srgrimes		qsort(a, r / es, es, cmp);
187103165Swollman#endif
1888870Srgrimes	if ((r = pd - pc) > es) {
1891573Srgrimes		/* Iterate rather than recurse to save stack space */
1901573Srgrimes		a = pn - r;
1911573Srgrimes		n = r / es;
1921573Srgrimes		goto loop;
1931573Srgrimes	}
1941573Srgrimes/*		qsort(pn - r, r / es, es, cmp);*/
1951573Srgrimes}
196