158f0484fSRodney W. Grimes /*- 258f0484fSRodney W. Grimes * Copyright (c) 1990, 1993 358f0484fSRodney W. Grimes * The Regents of the University of California. All rights reserved. 458f0484fSRodney W. Grimes * 558f0484fSRodney W. Grimes * This code is derived from software contributed to Berkeley by 658f0484fSRodney W. Grimes * Peter McIlroy and by Dan Bernstein at New York University, 758f0484fSRodney W. Grimes * 858f0484fSRodney W. Grimes * Redistribution and use in source and binary forms, with or without 958f0484fSRodney W. Grimes * modification, are permitted provided that the following conditions 1058f0484fSRodney W. Grimes * are met: 1158f0484fSRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 1258f0484fSRodney W. Grimes * notice, this list of conditions and the following disclaimer. 1358f0484fSRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 1458f0484fSRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 1558f0484fSRodney W. Grimes * documentation and/or other materials provided with the distribution. 1658f0484fSRodney W. Grimes * 3. All advertising materials mentioning features or use of this software 1758f0484fSRodney W. Grimes * must display the following acknowledgement: 1858f0484fSRodney W. Grimes * This product includes software developed by the University of 1958f0484fSRodney W. Grimes * California, Berkeley and its contributors. 2058f0484fSRodney W. Grimes * 4. Neither the name of the University nor the names of its contributors 2158f0484fSRodney W. Grimes * may be used to endorse or promote products derived from this software 2258f0484fSRodney W. Grimes * without specific prior written permission. 2358f0484fSRodney W. Grimes * 2458f0484fSRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2558f0484fSRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2658f0484fSRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2758f0484fSRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2858f0484fSRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2958f0484fSRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 3058f0484fSRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3158f0484fSRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3258f0484fSRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3358f0484fSRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3458f0484fSRodney W. Grimes * SUCH DAMAGE. 3558f0484fSRodney W. Grimes */ 3658f0484fSRodney W. Grimes 3758f0484fSRodney W. Grimes #if defined(LIBC_SCCS) && !defined(lint) 384381233dSPeter Wemm static char sccsid[] = "@(#)radixsort.c 8.2 (Berkeley) 4/28/95"; 3958f0484fSRodney W. Grimes #endif /* LIBC_SCCS and not lint */ 408fb3f3f6SDavid E. O'Brien #include <sys/cdefs.h> 418fb3f3f6SDavid E. O'Brien __FBSDID("$FreeBSD$"); 4258f0484fSRodney W. Grimes 4358f0484fSRodney W. Grimes /* 4458f0484fSRodney W. Grimes * Radixsort routines. 4558f0484fSRodney W. Grimes * 4658f0484fSRodney W. Grimes * Program r_sort_a() is unstable but uses O(logN) extra memory for a stack. 4758f0484fSRodney W. Grimes * Use radixsort(a, n, trace, endchar) for this case. 4858f0484fSRodney W. Grimes * 4958f0484fSRodney W. Grimes * For stable sorting (using N extra pointers) use sradixsort(), which calls 5058f0484fSRodney W. Grimes * r_sort_b(). 5158f0484fSRodney W. Grimes * 5258f0484fSRodney W. Grimes * For a description of this code, see D. McIlroy, P. McIlroy, K. Bostic, 5358f0484fSRodney W. Grimes * "Engineering Radix Sort". 5458f0484fSRodney W. Grimes */ 5558f0484fSRodney W. Grimes 5658f0484fSRodney W. Grimes #include <sys/types.h> 5758f0484fSRodney W. Grimes #include <stdlib.h> 5858f0484fSRodney W. Grimes #include <stddef.h> 5958f0484fSRodney W. Grimes #include <errno.h> 6058f0484fSRodney W. Grimes 6158f0484fSRodney W. Grimes typedef struct { 6258f0484fSRodney W. Grimes const u_char **sa; 6358f0484fSRodney W. Grimes int sn, si; 6458f0484fSRodney W. Grimes } stack; 6558f0484fSRodney W. Grimes 6658f0484fSRodney W. Grimes static inline void simplesort 6758f0484fSRodney W. Grimes __P((const u_char **, int, int, const u_char *, u_int)); 6858f0484fSRodney W. Grimes static void r_sort_a __P((const u_char **, int, int, const u_char *, u_int)); 6958f0484fSRodney W. Grimes static void r_sort_b __P((const u_char **, 7058f0484fSRodney W. Grimes const u_char **, int, int, const u_char *, u_int)); 7158f0484fSRodney W. Grimes 7258f0484fSRodney W. Grimes #define THRESHOLD 20 /* Divert to simplesort(). */ 7358f0484fSRodney W. Grimes #define SIZE 512 /* Default stack size. */ 7458f0484fSRodney W. Grimes 7558f0484fSRodney W. Grimes #define SETUP { \ 7658f0484fSRodney W. Grimes if (tab == NULL) { \ 7758f0484fSRodney W. Grimes tr = tr0; \ 7858f0484fSRodney W. Grimes for (c = 0; c < endch; c++) \ 7958f0484fSRodney W. Grimes tr0[c] = c + 1; \ 8058f0484fSRodney W. Grimes tr0[c] = 0; \ 8158f0484fSRodney W. Grimes for (c++; c < 256; c++) \ 8258f0484fSRodney W. Grimes tr0[c] = c; \ 8358f0484fSRodney W. Grimes endch = 0; \ 8458f0484fSRodney W. Grimes } else { \ 8558f0484fSRodney W. Grimes endch = tab[endch]; \ 8658f0484fSRodney W. Grimes tr = tab; \ 8758f0484fSRodney W. Grimes if (endch != 0 && endch != 255) { \ 8858f0484fSRodney W. Grimes errno = EINVAL; \ 8958f0484fSRodney W. Grimes return (-1); \ 9058f0484fSRodney W. Grimes } \ 9158f0484fSRodney W. Grimes } \ 9258f0484fSRodney W. Grimes } 9358f0484fSRodney W. Grimes 9458f0484fSRodney W. Grimes int 9558f0484fSRodney W. Grimes radixsort(a, n, tab, endch) 9658f0484fSRodney W. Grimes const u_char **a, *tab; 9758f0484fSRodney W. Grimes int n; 9858f0484fSRodney W. Grimes u_int endch; 9958f0484fSRodney W. Grimes { 10058f0484fSRodney W. Grimes const u_char *tr; 10158f0484fSRodney W. Grimes int c; 10258f0484fSRodney W. Grimes u_char tr0[256]; 10358f0484fSRodney W. Grimes 10458f0484fSRodney W. Grimes SETUP; 10558f0484fSRodney W. Grimes r_sort_a(a, n, 0, tr, endch); 10658f0484fSRodney W. Grimes return (0); 10758f0484fSRodney W. Grimes } 10858f0484fSRodney W. Grimes 10958f0484fSRodney W. Grimes int 11058f0484fSRodney W. Grimes sradixsort(a, n, tab, endch) 11158f0484fSRodney W. Grimes const u_char **a, *tab; 11258f0484fSRodney W. Grimes int n; 11358f0484fSRodney W. Grimes u_int endch; 11458f0484fSRodney W. Grimes { 11558f0484fSRodney W. Grimes const u_char *tr, **ta; 11658f0484fSRodney W. Grimes int c; 11758f0484fSRodney W. Grimes u_char tr0[256]; 11858f0484fSRodney W. Grimes 11958f0484fSRodney W. Grimes SETUP; 12058f0484fSRodney W. Grimes if (n < THRESHOLD) 12158f0484fSRodney W. Grimes simplesort(a, n, 0, tr, endch); 12258f0484fSRodney W. Grimes else { 12358f0484fSRodney W. Grimes if ((ta = malloc(n * sizeof(a))) == NULL) 12458f0484fSRodney W. Grimes return (-1); 12558f0484fSRodney W. Grimes r_sort_b(a, ta, n, 0, tr, endch); 12658f0484fSRodney W. Grimes free(ta); 12758f0484fSRodney W. Grimes } 12858f0484fSRodney W. Grimes return (0); 12958f0484fSRodney W. Grimes } 13058f0484fSRodney W. Grimes 13158f0484fSRodney W. Grimes #define empty(s) (s >= sp) 13258f0484fSRodney W. Grimes #define pop(a, n, i) a = (--sp)->sa, n = sp->sn, i = sp->si 13358f0484fSRodney W. Grimes #define push(a, n, i) sp->sa = a, sp->sn = n, (sp++)->si = i 13458f0484fSRodney W. Grimes #define swap(a, b, t) t = a, a = b, b = t 13558f0484fSRodney W. Grimes 13658f0484fSRodney W. Grimes /* Unstable, in-place sort. */ 1374381233dSPeter Wemm static void 13858f0484fSRodney W. Grimes r_sort_a(a, n, i, tr, endch) 13958f0484fSRodney W. Grimes const u_char **a; 14058f0484fSRodney W. Grimes int n, i; 14158f0484fSRodney W. Grimes const u_char *tr; 14258f0484fSRodney W. Grimes u_int endch; 14358f0484fSRodney W. Grimes { 14458f0484fSRodney W. Grimes static int count[256], nc, bmin; 1458fb3f3f6SDavid E. O'Brien int c; 1468fb3f3f6SDavid E. O'Brien const u_char **ak, *r; 14758f0484fSRodney W. Grimes stack s[SIZE], *sp, *sp0, *sp1, temp; 14858f0484fSRodney W. Grimes int *cp, bigc; 14958f0484fSRodney W. Grimes const u_char **an, *t, **aj, **top[256]; 15058f0484fSRodney W. Grimes 15158f0484fSRodney W. Grimes /* Set up stack. */ 15258f0484fSRodney W. Grimes sp = s; 15358f0484fSRodney W. Grimes push(a, n, i); 15458f0484fSRodney W. Grimes while (!empty(s)) { 15558f0484fSRodney W. Grimes pop(a, n, i); 15658f0484fSRodney W. Grimes if (n < THRESHOLD) { 15758f0484fSRodney W. Grimes simplesort(a, n, i, tr, endch); 15858f0484fSRodney W. Grimes continue; 15958f0484fSRodney W. Grimes } 16058f0484fSRodney W. Grimes an = a + n; 16158f0484fSRodney W. Grimes 16258f0484fSRodney W. Grimes /* Make character histogram. */ 16358f0484fSRodney W. Grimes if (nc == 0) { 16458f0484fSRodney W. Grimes bmin = 255; /* First occupied bin, excluding eos. */ 16558f0484fSRodney W. Grimes for (ak = a; ak < an;) { 16658f0484fSRodney W. Grimes c = tr[(*ak++)[i]]; 16758f0484fSRodney W. Grimes if (++count[c] == 1 && c != endch) { 16858f0484fSRodney W. Grimes if (c < bmin) 16958f0484fSRodney W. Grimes bmin = c; 17058f0484fSRodney W. Grimes nc++; 17158f0484fSRodney W. Grimes } 17258f0484fSRodney W. Grimes } 17358f0484fSRodney W. Grimes if (sp + nc > s + SIZE) { /* Get more stack. */ 17458f0484fSRodney W. Grimes r_sort_a(a, n, i, tr, endch); 17558f0484fSRodney W. Grimes continue; 17658f0484fSRodney W. Grimes } 17758f0484fSRodney W. Grimes } 17858f0484fSRodney W. Grimes 17958f0484fSRodney W. Grimes /* 18058f0484fSRodney W. Grimes * Set top[]; push incompletely sorted bins onto stack. 18158f0484fSRodney W. Grimes * top[] = pointers to last out-of-place element in bins. 18258f0484fSRodney W. Grimes * count[] = counts of elements in bins. 18358f0484fSRodney W. Grimes * Before permuting: top[c-1] + count[c] = top[c]; 18458f0484fSRodney W. Grimes * during deal: top[c] counts down to top[c-1]. 18558f0484fSRodney W. Grimes */ 18658f0484fSRodney W. Grimes sp0 = sp1 = sp; /* Stack position of biggest bin. */ 18758f0484fSRodney W. Grimes bigc = 2; /* Size of biggest bin. */ 18858f0484fSRodney W. Grimes if (endch == 0) /* Special case: set top[eos]. */ 18958f0484fSRodney W. Grimes top[0] = ak = a + count[0]; 19058f0484fSRodney W. Grimes else { 19158f0484fSRodney W. Grimes ak = a; 19258f0484fSRodney W. Grimes top[255] = an; 19358f0484fSRodney W. Grimes } 19458f0484fSRodney W. Grimes for (cp = count + bmin; nc > 0; cp++) { 19558f0484fSRodney W. Grimes while (*cp == 0) /* Find next non-empty pile. */ 19658f0484fSRodney W. Grimes cp++; 19758f0484fSRodney W. Grimes if (*cp > 1) { 19858f0484fSRodney W. Grimes if (*cp > bigc) { 19958f0484fSRodney W. Grimes bigc = *cp; 20058f0484fSRodney W. Grimes sp1 = sp; 20158f0484fSRodney W. Grimes } 20258f0484fSRodney W. Grimes push(ak, *cp, i+1); 20358f0484fSRodney W. Grimes } 20458f0484fSRodney W. Grimes top[cp-count] = ak += *cp; 20558f0484fSRodney W. Grimes nc--; 20658f0484fSRodney W. Grimes } 20758f0484fSRodney W. Grimes swap(*sp0, *sp1, temp); /* Play it safe -- biggest bin last. */ 20858f0484fSRodney W. Grimes 20958f0484fSRodney W. Grimes /* 21058f0484fSRodney W. Grimes * Permute misplacements home. Already home: everything 21158f0484fSRodney W. Grimes * before aj, and in bin[c], items from top[c] on. 21258f0484fSRodney W. Grimes * Inner loop: 21358f0484fSRodney W. Grimes * r = next element to put in place; 21458f0484fSRodney W. Grimes * ak = top[r[i]] = location to put the next element. 21558f0484fSRodney W. Grimes * aj = bottom of 1st disordered bin. 21658f0484fSRodney W. Grimes * Outer loop: 21758f0484fSRodney W. Grimes * Once the 1st disordered bin is done, ie. aj >= ak, 21858f0484fSRodney W. Grimes * aj<-aj + count[c] connects the bins in a linked list; 21958f0484fSRodney W. Grimes * reset count[c]. 22058f0484fSRodney W. Grimes */ 22158f0484fSRodney W. Grimes for (aj = a; aj < an; *aj = r, aj += count[c], count[c] = 0) 22258f0484fSRodney W. Grimes for (r = *aj; aj < (ak = --top[c = tr[r[i]]]);) 22358f0484fSRodney W. Grimes swap(*ak, r, t); 22458f0484fSRodney W. Grimes } 22558f0484fSRodney W. Grimes } 22658f0484fSRodney W. Grimes 22758f0484fSRodney W. Grimes /* Stable sort, requiring additional memory. */ 2284381233dSPeter Wemm static void 22958f0484fSRodney W. Grimes r_sort_b(a, ta, n, i, tr, endch) 23058f0484fSRodney W. Grimes const u_char **a, **ta; 23158f0484fSRodney W. Grimes int n, i; 23258f0484fSRodney W. Grimes const u_char *tr; 23358f0484fSRodney W. Grimes u_int endch; 23458f0484fSRodney W. Grimes { 23558f0484fSRodney W. Grimes static int count[256], nc, bmin; 2368fb3f3f6SDavid E. O'Brien int c; 2378fb3f3f6SDavid E. O'Brien const u_char **ak, **ai; 23858f0484fSRodney W. Grimes stack s[512], *sp, *sp0, *sp1, temp; 23958f0484fSRodney W. Grimes const u_char **top[256]; 24058f0484fSRodney W. Grimes int *cp, bigc; 24158f0484fSRodney W. Grimes 24258f0484fSRodney W. Grimes sp = s; 24358f0484fSRodney W. Grimes push(a, n, i); 24458f0484fSRodney W. Grimes while (!empty(s)) { 24558f0484fSRodney W. Grimes pop(a, n, i); 24658f0484fSRodney W. Grimes if (n < THRESHOLD) { 24758f0484fSRodney W. Grimes simplesort(a, n, i, tr, endch); 24858f0484fSRodney W. Grimes continue; 24958f0484fSRodney W. Grimes } 25058f0484fSRodney W. Grimes 25158f0484fSRodney W. Grimes if (nc == 0) { 25258f0484fSRodney W. Grimes bmin = 255; 25358f0484fSRodney W. Grimes for (ak = a + n; --ak >= a;) { 25458f0484fSRodney W. Grimes c = tr[(*ak)[i]]; 25558f0484fSRodney W. Grimes if (++count[c] == 1 && c != endch) { 25658f0484fSRodney W. Grimes if (c < bmin) 25758f0484fSRodney W. Grimes bmin = c; 25858f0484fSRodney W. Grimes nc++; 25958f0484fSRodney W. Grimes } 26058f0484fSRodney W. Grimes } 26158f0484fSRodney W. Grimes if (sp + nc > s + SIZE) { 26258f0484fSRodney W. Grimes r_sort_b(a, ta, n, i, tr, endch); 26358f0484fSRodney W. Grimes continue; 26458f0484fSRodney W. Grimes } 26558f0484fSRodney W. Grimes } 26658f0484fSRodney W. Grimes 26758f0484fSRodney W. Grimes sp0 = sp1 = sp; 26858f0484fSRodney W. Grimes bigc = 2; 26958f0484fSRodney W. Grimes if (endch == 0) { 27058f0484fSRodney W. Grimes top[0] = ak = a + count[0]; 27158f0484fSRodney W. Grimes count[0] = 0; 27258f0484fSRodney W. Grimes } else { 27358f0484fSRodney W. Grimes ak = a; 27458f0484fSRodney W. Grimes top[255] = a + n; 27558f0484fSRodney W. Grimes count[255] = 0; 27658f0484fSRodney W. Grimes } 27758f0484fSRodney W. Grimes for (cp = count + bmin; nc > 0; cp++) { 27858f0484fSRodney W. Grimes while (*cp == 0) 27958f0484fSRodney W. Grimes cp++; 28058f0484fSRodney W. Grimes if ((c = *cp) > 1) { 28158f0484fSRodney W. Grimes if (c > bigc) { 28258f0484fSRodney W. Grimes bigc = c; 28358f0484fSRodney W. Grimes sp1 = sp; 28458f0484fSRodney W. Grimes } 28558f0484fSRodney W. Grimes push(ak, c, i+1); 28658f0484fSRodney W. Grimes } 28758f0484fSRodney W. Grimes top[cp-count] = ak += c; 28858f0484fSRodney W. Grimes *cp = 0; /* Reset count[]. */ 28958f0484fSRodney W. Grimes nc--; 29058f0484fSRodney W. Grimes } 29158f0484fSRodney W. Grimes swap(*sp0, *sp1, temp); 29258f0484fSRodney W. Grimes 29358f0484fSRodney W. Grimes for (ak = ta + n, ai = a+n; ak > ta;) /* Copy to temp. */ 29458f0484fSRodney W. Grimes *--ak = *--ai; 29558f0484fSRodney W. Grimes for (ak = ta+n; --ak >= ta;) /* Deal to piles. */ 29658f0484fSRodney W. Grimes *--top[tr[(*ak)[i]]] = *ak; 29758f0484fSRodney W. Grimes } 29858f0484fSRodney W. Grimes } 29958f0484fSRodney W. Grimes 30058f0484fSRodney W. Grimes static inline void 30158f0484fSRodney W. Grimes simplesort(a, n, b, tr, endch) /* insertion sort */ 3028fb3f3f6SDavid E. O'Brien const u_char **a; 30358f0484fSRodney W. Grimes int n, b; 3048fb3f3f6SDavid E. O'Brien const u_char *tr; 30558f0484fSRodney W. Grimes u_int endch; 30658f0484fSRodney W. Grimes { 3078fb3f3f6SDavid E. O'Brien u_char ch; 30858f0484fSRodney W. Grimes const u_char **ak, **ai, *s, *t; 30958f0484fSRodney W. Grimes 31058f0484fSRodney W. Grimes for (ak = a+1; --n >= 1; ak++) 31158f0484fSRodney W. Grimes for (ai = ak; ai > a; ai--) { 31258f0484fSRodney W. Grimes for (s = ai[0] + b, t = ai[-1] + b; 31358f0484fSRodney W. Grimes (ch = tr[*s]) != endch; s++, t++) 31458f0484fSRodney W. Grimes if (ch != tr[*t]) 31558f0484fSRodney W. Grimes break; 31658f0484fSRodney W. Grimes if (ch >= tr[*t]) 31758f0484fSRodney W. Grimes break; 31858f0484fSRodney W. Grimes swap(ai[0], ai[-1], s); 31958f0484fSRodney W. Grimes } 32058f0484fSRodney W. Grimes } 321