home *** CD-ROM | disk | FTP | other *** search
/ Aminet 18 / aminetcdnumber181997.iso / Aminet / misc / emu / AROSdev.lha / AROS / compiler / clib / qsort.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-01-09  |  4.7 KB  |  199 lines

  1. /*
  2.     (C) 1995-96 AROS - The Amiga Replacement OS
  3.     $Id: qsort.c,v 1.6 1997/01/01 03:40:49 ldp Exp $
  4.  
  5.     Desc: ANSI C function qsort()
  6.     Lang: english
  7. */
  8. /* Original source from NetBSD */
  9. #include <exec/types.h>
  10. #include <sys/types.h>
  11. #include <stdlib.h>
  12.  
  13. static inline const char *med3 (const char *, const char *, const char *, int (*)());
  14. static inline void     swapfunc (char *, char *, int, int);
  15.  
  16. #define min(a, b)       (a) < (b) ? a : b
  17.  
  18. /*
  19.  * Qsort routine from Bentley & McIlroy's "Engineering a Sort Function".
  20.  */
  21. #define swapcode(TYPE, parmi, parmj, n) {               \
  22.     long i = (n) / sizeof (TYPE);                   \
  23.     register TYPE *pi = (TYPE *) (parmi);           \
  24.     register TYPE *pj = (TYPE *) (parmj);           \
  25.     do {                        \
  26.         register TYPE    t = *pi;        \
  27.         *pi++ = *pj;                \
  28.         *pj++ = t;                \
  29.     } while (--i > 0);                              \
  30. }
  31.  
  32. #define SWAPINIT(a, es) swaptype = ((char *)a - (char *)0) % sizeof(long) || \
  33.     es % sizeof(long) ? 2 : es == sizeof(long)? 0 : 1;
  34.  
  35. static inline void
  36. swapfunc (char *a, char *b, int n, int swaptype)
  37. {
  38.     if(swaptype <= 1)
  39.         swapcode(long, a, b, n)
  40.     else
  41.         swapcode(char, a, b, n)
  42. }
  43.  
  44. #define swap(a, b)                                      \
  45.     if (swaptype == 0) {                            \
  46.         long t = *(long *)(a);                  \
  47.         *(long *)(a) = *(long *)(b);            \
  48.         *(long *)(b) = t;                       \
  49.     } else                        \
  50.         swapfunc(a, b, es, swaptype)
  51.  
  52. #define vecswap(a, b, n)        if ((n) > 0) swapfunc(a, b, n, swaptype)
  53.  
  54. static inline const char *
  55. med3(const char *a, const char *b, const char *c, int (*cmp)(const void *, const void *))
  56. {
  57.     return cmp(a, b) < 0 ?
  58.            (cmp(b, c) < 0 ? b : (cmp(a, c) < 0 ? c : a ))
  59.           :(cmp(b, c) > 0 ? b : (cmp(a, c) < 0 ? a : c ));
  60. }
  61.  
  62. /*****************************************************************************
  63.  
  64.     NAME */
  65.  
  66.     void qsort (
  67.  
  68. /*  SYNOPSIS */
  69.     void * a,
  70.     size_t n,
  71.     size_t es,
  72.     int (* cmp)(const void *, const void *))
  73.  
  74. /*  FUNCTION
  75.     Sort the array a. It contains n elements of the size es. Elements
  76.     are compares using the function cmp().
  77.  
  78.     INPUTS
  79.     a - The array to sort
  80.     n - The number of elements in the array
  81.     es - The size of a single element in the array
  82.     cmp - The function which is called when two elements must be
  83.         compared. The function gets the addresses of two elements
  84.         of the array and must return 0 is both are equal, < 0 if
  85.         the first element is less than the second and > 0 otherwise.
  86.  
  87.     RESULT
  88.     None.
  89.  
  90.     NOTES
  91.  
  92.     EXAMPLE
  93.     // Use this function to compare to stringpointers
  94.     int cmp_strptr (const char ** sptr1, const char ** sptr2)
  95.     {
  96.         return strcmp (*sptr1, *sptr2);
  97.     }
  98.  
  99.     // Sort an array of strings
  100.     char ** strings;
  101.  
  102.     // fill the array
  103.     strings = malloc (sizeof (char *)*4);
  104.     strings[0] = strdup ("h");
  105.     strings[1] = strdup ("a");
  106.     strings[2] = strdup ("f");
  107.     strings[3] = strdup ("d");
  108.  
  109.     // Sort it
  110.     qsort (strings, sizeof (char *), 4, (void *)cmp_strptr);
  111.  
  112.     BUGS
  113.  
  114.     SEE ALSO
  115.     strcmp(), strncmp(), memcmp(), strcasecmp(), strncasecmp()
  116.  
  117.     INTERNALS
  118.  
  119.     HISTORY
  120.     29.07.1996 digulla copied from NetBSD
  121.  
  122. ******************************************************************************/
  123. {
  124.     char *pa, *pb, *pc, *pd, *pl, *pm, *pn;
  125.     int d, r, swaptype, swap_cnt;
  126.  
  127. loop:    SWAPINIT(a, es);
  128.     swap_cnt = 0;
  129.     if (n < 7) {
  130.         for (pm = a + es; pm < (char *) a + n * es; pm += es)
  131.             for (pl = pm; pl > (char *) a && cmp(pl - es, pl) > 0;
  132.                  pl -= es)
  133.                 swap(pl, pl - es);
  134.         return;
  135.     }
  136.     pm = a + (n / 2) * es;
  137.     if (n > 7) {
  138.         pl = a;
  139.         pn = a + (n - 1) * es;
  140.         if (n > 40) {
  141.             d = (n / 8) * es;
  142.             pl = (char *)med3(pl, pl + d, pl + 2 * d, cmp);
  143.             pm = (char *)med3(pm - d, pm, pm + d, cmp);
  144.             pn = (char *)med3(pn - 2 * d, pn - d, pn, cmp);
  145.         }
  146.         pm = (char *)med3(pl, pm, pn, cmp);
  147.     }
  148.     swap(a, pm);
  149.     pa = pb = a + es;
  150.  
  151.     pc = pd = a + (n - 1) * es;
  152.     for (;;) {
  153.         while (pb <= pc && (r = cmp(pb, a)) <= 0) {
  154.             if (r == 0) {
  155.                 swap_cnt = 1;
  156.                 swap(pa, pb);
  157.                 pa += es;
  158.             }
  159.             pb += es;
  160.         }
  161.         while (pb <= pc && (r = cmp(pc, a)) >= 0) {
  162.             if (r == 0) {
  163.                 swap_cnt = 1;
  164.                 swap(pc, pd);
  165.                 pd -= es;
  166.             }
  167.             pc -= es;
  168.         }
  169.         if (pb > pc)
  170.             break;
  171.         swap(pb, pc);
  172.         swap_cnt = 1;
  173.         pb += es;
  174.         pc -= es;
  175.     }
  176.     if (swap_cnt == 0) {  /* Switch to insertion sort */
  177.         for (pm = a + es; pm < (char *) a + n * es; pm += es)
  178.             for (pl = pm; pl > (char *) a && cmp(pl - es, pl) > 0;
  179.                  pl -= es)
  180.                 swap(pl, pl - es);
  181.         return;
  182.     }
  183.  
  184.     pn = a + n * es;
  185.     r = min(pa - (char *)a, pb - pa);
  186.     vecswap(a, pb - r, r);
  187.     r = min(pd - pc, pn - pd - es);
  188.     vecswap(pb, pn - r, r);
  189.     if ((r = pb - pa) > es)
  190.         qsort(a, r / es, es, cmp);
  191.     if ((r = pd - pc) > es) {
  192.         /* Iterate rather than recurse to save stack space */
  193.         a = pn - r;
  194.         n = r / es;
  195.         goto loop;
  196.     }
  197. /*        qsort(pn - r, r / es, es, cmp);*/
  198. }
  199.