xref: /csrg-svn/lib/libc/stdlib/qsort.c (revision 61180)
157601Sbostic /*-
2*61180Sbostic  * Copyright (c) 1992, 1993
3*61180Sbostic  *	The Regents of the University of California.  All rights reserved.
434434Sbostic  *
542126Sbostic  * %sccs.include.redist.c%
622102Smckusick  */
71975Swnj 
857601Sbostic #if defined(LIBC_SCCS) && !defined(lint)
9*61180Sbostic static char sccsid[] = "@(#)qsort.c	8.1 (Berkeley) 06/04/93";
1057601Sbostic #endif /* LIBC_SCCS and not lint */
1122102Smckusick 
1245643Sbostic #include <sys/types.h>
1357601Sbostic #include <stdlib.h>
1442179Sbostic 
1557601Sbostic static inline char	*med3 __P((char *, char *, char *, int (*)()));
1657601Sbostic static inline void	 swapfunc __P((char *, char *, int, int));
1754201Sbostic 
1857601Sbostic #define min(a, b)	(a) < (b) ? a : b
191975Swnj 
2045643Sbostic /*
2157056Selan  * Qsort routine from Bentley & McIlroy's "Engineering a Sort Function".
2245643Sbostic  */
2357056Selan #define swapcode(TYPE, parmi, parmj, n) { 		\
2457056Selan 	long i = (n) / sizeof (TYPE); 			\
2557056Selan 	register TYPE *pi = (TYPE *) (parmi); 		\
2657056Selan 	register TYPE *pj = (TYPE *) (parmj); 		\
2757056Selan 	do { 						\
2857056Selan 		register TYPE	t = *pi;		\
2957056Selan 		*pi++ = *pj;				\
3057056Selan 		*pj++ = t;				\
3157056Selan         } while (--i > 0);				\
3257056Selan }
331975Swnj 
3457056Selan #define SWAPINIT(a, es) swaptype = ((char *)a - (char *)0) % sizeof(long) || \
3557056Selan 	es % sizeof(long) ? 2 : es == sizeof(long)? 0 : 1;
3657056Selan 
3757601Sbostic static inline void
swapfunc(a,b,n,swaptype)3857056Selan swapfunc(a, b, n, swaptype)
3957056Selan 	char *a, *b;
4057056Selan 	int n, swaptype;
4145643Sbostic {
4257056Selan 	if(swaptype <= 1)
4357056Selan 		swapcode(long, a, b, n)
4445643Sbostic 	else
4557056Selan 		swapcode(char, a, b, n)
4645643Sbostic }
4745643Sbostic 
4857601Sbostic #define swap(a, b)					\
4957601Sbostic 	if (swaptype == 0) {				\
5057601Sbostic 		long t = *(long *)(a);			\
5157601Sbostic 		*(long *)(a) = *(long *)(b);		\
5257601Sbostic 		*(long *)(b) = t;			\
5357601Sbostic 	} else						\
5457056Selan 		swapfunc(a, b, es, swaptype)
551975Swnj 
5657056Selan #define vecswap(a, b, n) 	if ((n) > 0) swapfunc(a, b, n, swaptype)
5757056Selan 
5857601Sbostic static inline char *
med3(a,b,c,cmp)5957056Selan med3(a, b, c, cmp)
6057056Selan 	char *a, *b, *c;
6157056Selan 	int (*cmp)();
6257056Selan {
6357056Selan 	return cmp(a, b) < 0 ?
6457056Selan 	       (cmp(b, c) < 0 ? b : (cmp(a, c) < 0 ? c : a ))
6557056Selan               :(cmp(b, c) > 0 ? b : (cmp(a, c) < 0 ? a : c ));
6645643Sbostic }
6745643Sbostic 
6857056Selan void
qsort(a,n,es,cmp)6957056Selan qsort(a, n, es, cmp)
7057056Selan 	void *a;
7157056Selan 	size_t n, es;
7257056Selan 	int (*cmp)();
7311449Smckusick {
7457056Selan 	char *pa, *pb, *pc, *pd, *pl, *pm, *pn;
7557056Selan 	int d, r, swaptype, swap_cnt;
761975Swnj 
7757056Selan loop:	SWAPINIT(a, es);
7857056Selan 	swap_cnt = 0;
7957056Selan 	if (n < 7) {
8057056Selan 		for (pm = a + es; pm < (char *) a + n * es; pm += es)
8157056Selan 			for (pl = pm; pl > (char *) a && cmp(pl - es, pl) > 0;
8257056Selan 			     pl -= es)
8357056Selan 				swap(pl, pl - es);
8457056Selan 		return;
8557056Selan 	}
8657056Selan 	pm = a + (n / 2) * es;
8757056Selan 	if (n > 7) {
8857056Selan 		pl = a;
8957056Selan 		pn = a + (n - 1) * es;
9057056Selan 		if (n > 40) {
9157056Selan 			d = (n / 8) * es;
9257056Selan 			pl = med3(pl, pl + d, pl + 2 * d, cmp);
9357056Selan 			pm = med3(pm - d, pm, pm + d, cmp);
9457056Selan 			pn = med3(pn - 2 * d, pn - d, pn, cmp);
9511449Smckusick 		}
9657056Selan 		pm = med3(pl, pm, pn, cmp);
9711449Smckusick 	}
9857056Selan 	swap(a, pm);
9957056Selan 	pa = pb = a + es;
10045643Sbostic 
10157056Selan 	pc = pd = a + (n - 1) * es;
10257056Selan 	for (;;) {
10357056Selan 		while (pb <= pc && (r = cmp(pb, a)) <= 0) {
10457056Selan 			if (r == 0) {
10557056Selan 				swap_cnt = 1;
10657056Selan 				swap(pa, pb);
10757056Selan 				pa += es;
1081975Swnj 			}
10957056Selan 			pb += es;
11057056Selan 		}
11157056Selan 		while (pb <= pc && (r = cmp(pc, a)) >= 0) {
11257056Selan 			if (r == 0) {
11357056Selan 				swap_cnt = 1;
11457056Selan 				swap(pc, pd);
11557056Selan 				pd -= es;
11645643Sbostic 			}
11757056Selan 			pc -= es;
1181975Swnj 		}
11957056Selan 		if (pb > pc)
12045643Sbostic 			break;
12157056Selan 		swap(pb, pc);
12257056Selan 		swap_cnt = 1;
12357056Selan 		pb += es;
12457056Selan 		pc -= es;
12511449Smckusick 	}
12657056Selan 	if (swap_cnt == 0) {  /* Switch to insertion sort */
12757056Selan 		for (pm = a + es; pm < (char *) a + n * es; pm += es)
12857056Selan 			for (pl = pm; pl > (char *) a && cmp(pl - es, pl) > 0;
12957056Selan 			     pl -= es)
13057056Selan 				swap(pl, pl - es);
13145643Sbostic 		return;
13245643Sbostic 	}
13311449Smckusick 
13457056Selan 	pn = a + n * es;
13557056Selan 	r = min(pa - (char *)a, pb - pa);
13657056Selan 	vecswap(a, pb - r, r);
13757056Selan 	r = min(pd - pc, pn - pd - es);
13857056Selan 	vecswap(pb, pn - r, r);
13957588Selan 	if ((r = pb - pa) > es)
14057588Selan 		qsort(a, r / es, es, cmp);
14157588Selan 	if ((r = pd - pc) > es) {
14257588Selan 		/* Iterate rather than recurse to save stack space */
14357588Selan 		a = pn - r;
14457056Selan 		n = r / es;
14557056Selan 		goto loop;
14645643Sbostic 	}
14757588Selan /*		qsort(pn - r, r / es, es, cmp);*/
1481975Swnj }
149