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