Odamex
Setting the Standard in Multiplayer Doom
common/qsort.h
Go to the documentation of this file.
00001 /* $Id: qsort.h,v 1.5 2008-01-28 18:16:49 mjt Exp $
00002  * Adopted from GNU glibc by Mjt.
00003  * See stdlib/qsort.c in glibc */
00004 
00005 /* Copyright (C) 1991, 1992, 1996, 1997, 1999 Free Software Foundation, Inc.
00006    This file is part of the GNU C Library.
00007    Written by Douglas C. Schmidt (schmidt@ics.uci.edu).
00008 
00009    The GNU C Library is free software; you can redistribute it and/or
00010    modify it under the terms of the GNU Lesser General Public
00011    License as published by the Free Software Foundation; either
00012    version 2.1 of the License, or (at your option) any later version.
00013 
00014    The GNU C Library is distributed in the hope that it will be useful,
00015    but WITHOUT ANY WARRANTY; without even the implied warranty of
00016    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00017    Lesser General Public License for more details.
00018 
00019    You should have received a copy of the GNU Lesser General Public
00020    License along with the GNU C Library; if not, write to the Free
00021    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00022    02111-1307 USA.  */
00023 
00024 /* in-line qsort implementation.  Differs from traditional qsort() routine
00025  * in that it is a macro, not a function, and instead of passing an address
00026  * of a comparison routine to the function, it is possible to inline
00027  * comparison routine, thus speeding up sorting a lot.
00028  *
00029  * Usage:
00030  *  #include "iqsort.h"
00031  *  #define islt(a,b) (strcmp((*a),(*b))<0)
00032  *  char *arr[];
00033  *  int n;
00034  *  QSORT(char*, arr, n, islt);
00035  *
00036  * The "prototype" and 4 arguments are:
00037  *  QSORT(TYPE,BASE,NELT,ISLT)
00038  *  1) type of each element, TYPE,
00039  *  2) address of the beginning of the array, of type TYPE*,
00040  *  3) number of elements in the array, and
00041  *  4) comparision routine.
00042  * Array pointer and number of elements are referenced only once.
00043  * This is similar to a call
00044  *  qsort(BASE,NELT,sizeof(TYPE),ISLT)
00045  * with the difference in last parameter.
00046  * Note the islt macro/routine (it receives pointers to two elements):
00047  * the only condition of interest is whenever one element is less than
00048  * another, no other conditions (greather than, equal to etc) are tested.
00049  * So, for example, to define integer sort, use:
00050  *  #define islt(a,b) ((*a)<(*b))
00051  *  QSORT(int, arr, n, islt)
00052  *
00053  * The macro could be used to implement a sorting function (see examples
00054  * below), or to implement the sorting algorithm inline.  That is, either
00055  * create a sorting function and use it whenever you want to sort something,
00056  * or use QSORT() macro directly instead a call to such routine.  Note that
00057  * the macro expands to quite some code (compiled size of int qsort on x86
00058  * is about 700..800 bytes).
00059  *
00060  * Using this macro directly it isn't possible to implement traditional
00061  * qsort() routine, because the macro assumes sizeof(element) == sizeof(TYPE),
00062  * while qsort() allows element size to be different.
00063  *
00064  * Several ready-to-use examples:
00065  *
00066  * Sorting array of integers:
00067  * void int_qsort(int *arr, unsigned n) {
00068  * #define int_lt(a,b) ((*a)<(*b))
00069  *   QSORT(int, arr, n, int_lt);
00070  * }
00071  *
00072  * Sorting array of string pointers:
00073  * void str_qsort(char *arr[], unsigned n) {
00074  * #define str_lt(a,b) (strcmp((*a),(*b)) < 0)
00075  *   QSORT(char*, arr, n, str_lt);
00076  * }
00077  *
00078  * Sorting array of structures:
00079  *
00080  * struct elt {
00081  *   int key;
00082  *   ...
00083  * };
00084  * void elt_qsort(struct elt *arr, unsigned n) {
00085  * #define elt_lt(a,b) ((a)->key < (b)->key)
00086  *  QSORT(struct elt, arr, n, elt_lt);
00087  * }
00088  *
00089  * And so on.
00090  */
00091 
00092 /* Swap two items pointed to by A and B using temporary buffer t. */
00093 #define _QSORT_SWAP(a, b, t) ((void)((t = *a), (*a = *b), (*b = t)))
00094 
00095 /* Discontinue quicksort algorithm when partition gets below this size.
00096    This particular magic number was chosen to work best on a Sun 4/260. */
00097 #define _QSORT_MAX_THRESH 4
00098 
00099 /* Stack node declarations used to store unfulfilled partition obligations
00100  * (inlined in QSORT).
00101 typedef struct {
00102   QSORT_TYPE *_lo, *_hi;
00103 } qsort_stack_node;
00104  */
00105 
00106 /* The next 4 #defines implement a very fast in-line stack abstraction. */
00107 /* The stack needs log (total_elements) entries (we could even subtract
00108    log(MAX_THRESH)).  Since total_elements has type unsigned, we get as
00109    upper bound for log (total_elements):
00110    bits per byte (CHAR_BIT) * sizeof(unsigned).  */
00111 #define _QSORT_STACK_SIZE       (8 * sizeof(unsigned))
00112 #define _QSORT_PUSH(top, low, high)     \
00113         (((top->_lo = (low)), (top->_hi = (high)), ++top))
00114 #define _QSORT_POP(low, high, top)      \
00115         ((--top, (low = top->_lo), (high = top->_hi)))
00116 #define _QSORT_STACK_NOT_EMPTY  (_stack < _top)
00117 
00118 
00119 /* Order size using quicksort.  This implementation incorporates
00120    four optimizations discussed in Sedgewick:
00121 
00122    1. Non-recursive, using an explicit stack of pointer that store the
00123       next array partition to sort.  To save time, this maximum amount
00124       of space required to store an array of SIZE_MAX is allocated on the
00125       stack.  Assuming a 32-bit (64 bit) integer for size_t, this needs
00126       only 32 * sizeof(stack_node) == 256 bytes (for 64 bit: 1024 bytes).
00127       Pretty cheap, actually.
00128 
00129    2. Chose the pivot element using a median-of-three decision tree.
00130       This reduces the probability of selecting a bad pivot value and
00131       eliminates certain extraneous comparisons.
00132 
00133    3. Only quicksorts TOTAL_ELEMS / MAX_THRESH partitions, leaving
00134       insertion sort to order the MAX_THRESH items within each partition.
00135       This is a big win, since insertion sort is faster for small, mostly
00136       sorted array segments.
00137 
00138    4. The larger of the two sub-partitions is always pushed onto the
00139       stack first, with the algorithm then concentrating on the
00140       smaller partition.  This *guarantees* no more than log (total_elems)
00141       stack size is needed (actually O(1) in this case)!  */
00142 
00143 /* The main code starts here... */
00144 #define QSORT(QSORT_TYPE,QSORT_BASE,QSORT_NELT,QSORT_LT)                \
00145 {                                                                       \
00146   QSORT_TYPE *const _base = (QSORT_BASE);                               \
00147   const unsigned _elems = (QSORT_NELT);                                 \
00148   QSORT_TYPE _hold;                                                     \
00149                                                                         \
00150   /* Don't declare two variables of type QSORT_TYPE in a single         \
00151    * statement: eg `TYPE a, b;', in case if TYPE is a pointer,          \
00152    * expands to `type* a, b;' wich isn't what we want.                  \
00153    */                                                                   \
00154                                                                         \
00155   if (_elems > _QSORT_MAX_THRESH) {                                     \
00156     QSORT_TYPE *_lo = _base;                                            \
00157     QSORT_TYPE *_hi = _lo + _elems - 1;                                 \
00158     struct {                                                            \
00159       QSORT_TYPE *_hi; QSORT_TYPE *_lo;                                 \
00160     } _stack[_QSORT_STACK_SIZE], *_top = _stack + 1;                    \
00161                                                                         \
00162     while (_QSORT_STACK_NOT_EMPTY) {                                    \
00163       QSORT_TYPE *_left_ptr; QSORT_TYPE *_right_ptr;                    \
00164                                                                         \
00165       /* Select median value from among LO, MID, and HI. Rearrange      \
00166          LO and HI so the three values are sorted. This lowers the      \
00167          probability of picking a pathological pivot value and          \
00168          skips a comparison for both the LEFT_PTR and RIGHT_PTR in      \
00169          the while loops. */                                            \
00170                                                                         \
00171       QSORT_TYPE *_mid = _lo + ((_hi - _lo) >> 1);                      \
00172                                                                         \
00173       if (QSORT_LT (_mid, _lo))                                         \
00174         _QSORT_SWAP (_mid, _lo, _hold);                                 \
00175       if (QSORT_LT (_hi, _mid)) {                                       \
00176         _QSORT_SWAP (_mid, _hi, _hold);                                 \
00177         if (QSORT_LT (_mid, _lo))                                       \
00178           _QSORT_SWAP (_mid, _lo, _hold);                               \
00179       }                                                                 \
00180                                                                         \
00181       _left_ptr  = _lo + 1;                                             \
00182       _right_ptr = _hi - 1;                                             \
00183                                                                         \
00184       /* Here's the famous ``collapse the walls'' section of quicksort. \
00185          Gotta like those tight inner loops!  They are the main reason  \
00186          that this algorithm runs much faster than others. */           \
00187       do {                                                              \
00188         while (QSORT_LT (_left_ptr, _mid))                              \
00189          ++_left_ptr;                                                   \
00190                                                                         \
00191         while (QSORT_LT (_mid, _right_ptr))                             \
00192           --_right_ptr;                                                 \
00193                                                                         \
00194         if (_left_ptr < _right_ptr) {                                   \
00195           _QSORT_SWAP (_left_ptr, _right_ptr, _hold);                   \
00196           if (_mid == _left_ptr)                                        \
00197             _mid = _right_ptr;                                          \
00198           else if (_mid == _right_ptr)                                  \
00199             _mid = _left_ptr;                                           \
00200           ++_left_ptr;                                                  \
00201           --_right_ptr;                                                 \
00202         }                                                               \
00203         else if (_left_ptr == _right_ptr) {                             \
00204           ++_left_ptr;                                                  \
00205           --_right_ptr;                                                 \
00206           break;                                                        \
00207         }                                                               \
00208       } while (_left_ptr <= _right_ptr);                                \
00209                                                                         \
00210      /* Set up pointers for next iteration.  First determine whether    \
00211         left and right partitions are below the threshold size.  If so, \
00212         ignore one or both.  Otherwise, push the larger partition's     \
00213         bounds on the stack and continue sorting the smaller one. */    \
00214                                                                         \
00215       if (_right_ptr - _lo <= _QSORT_MAX_THRESH) {                      \
00216         if (_hi - _left_ptr <= _QSORT_MAX_THRESH)                       \
00217           /* Ignore both small partitions. */                           \
00218           _QSORT_POP (_lo, _hi, _top);                                  \
00219         else                                                            \
00220           /* Ignore small left partition. */                            \
00221           _lo = _left_ptr;                                              \
00222       }                                                                 \
00223       else if (_hi - _left_ptr <= _QSORT_MAX_THRESH)                    \
00224         /* Ignore small right partition. */                             \
00225         _hi = _right_ptr;                                               \
00226       else if (_right_ptr - _lo > _hi - _left_ptr) {                    \
00227         /* Push larger left partition indices. */                       \
00228         _QSORT_PUSH (_top, _lo, _right_ptr);                            \
00229         _lo = _left_ptr;                                                \
00230       }                                                                 \
00231       else {                                                            \
00232         /* Push larger right partition indices. */                      \
00233         _QSORT_PUSH (_top, _left_ptr, _hi);                             \
00234         _hi = _right_ptr;                                               \
00235       }                                                                 \
00236     }                                                                   \
00237   }                                                                     \
00238                                                                         \
00239   /* Once the BASE array is partially sorted by quicksort the rest      \
00240      is completely sorted using insertion sort, since this is efficient \
00241      for partitions below MAX_THRESH size. BASE points to the           \
00242      beginning of the array to sort, and END_PTR points at the very     \
00243      last element in the array (*not* one beyond it!). */               \
00244                                                                         \
00245   {                                                                     \
00246     QSORT_TYPE *const _end_ptr = _base + _elems - 1;                    \
00247     QSORT_TYPE *_tmp_ptr = _base;                                       \
00248     register QSORT_TYPE *_run_ptr;                                      \
00249     QSORT_TYPE *_thresh;                                                \
00250                                                                         \
00251     _thresh = _base + _QSORT_MAX_THRESH;                                \
00252     if (_thresh > _end_ptr)                                             \
00253       _thresh = _end_ptr;                                               \
00254                                                                         \
00255     /* Find smallest element in first threshold and place it at the     \
00256        array's beginning.  This is the smallest array element,          \
00257        and the operation speeds up insertion sort's inner loop. */      \
00258                                                                         \
00259     for (_run_ptr = _tmp_ptr + 1; _run_ptr <= _thresh; ++_run_ptr)      \
00260       if (QSORT_LT (_run_ptr, _tmp_ptr))                                \
00261         _tmp_ptr = _run_ptr;                                            \
00262                                                                         \
00263     if (_tmp_ptr != _base)                                              \
00264       _QSORT_SWAP (_tmp_ptr, _base, _hold);                             \
00265                                                                         \
00266     /* Insertion sort, running from left-hand-side                      \
00267      * up to right-hand-side.  */                                       \
00268                                                                         \
00269     _run_ptr = _base + 1;                                               \
00270     while (++_run_ptr <= _end_ptr) {                                    \
00271       _tmp_ptr = _run_ptr - 1;                                          \
00272       while (QSORT_LT (_run_ptr, _tmp_ptr))                             \
00273         --_tmp_ptr;                                                     \
00274                                                                         \
00275       ++_tmp_ptr;                                                       \
00276       if (_tmp_ptr != _run_ptr) {                                       \
00277         QSORT_TYPE *_trav = _run_ptr + 1;                               \
00278         while (--_trav >= _run_ptr) {                                   \
00279           QSORT_TYPE *_hi; QSORT_TYPE *_lo;                             \
00280           _hold = *_trav;                                               \
00281                                                                         \
00282           for (_hi = _lo = _trav; --_lo >= _tmp_ptr; _hi = _lo)         \
00283             *_hi = *_lo;                                                \
00284           *_hi = _hold;                                                 \
00285         }                                                               \
00286       }                                                                 \
00287     }                                                                   \
00288   }                                                                     \
00289                                                                         \
00290 }
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends