Home | History | Annotate | Line # | Download | only in libiberty
      1      1.1     skrll /* Sorting algorithms.
      2  1.1.1.7  christos    Copyright (C) 2000-2026 Free Software Foundation, Inc.
      3      1.1     skrll    Contributed by Mark Mitchell <mark (at) codesourcery.com>.
      4      1.1     skrll 
      5      1.1     skrll This file is part of GNU CC.
      6      1.1     skrll 
      7      1.1     skrll GNU CC is free software; you can redistribute it and/or modify it
      8      1.1     skrll under the terms of the GNU General Public License as published by
      9      1.1     skrll the Free Software Foundation; either version 2, or (at your option)
     10      1.1     skrll any later version.
     11      1.1     skrll 
     12      1.1     skrll GNU CC is distributed in the hope that it will be useful, but
     13      1.1     skrll WITHOUT ANY WARRANTY; without even the implied warranty of
     14      1.1     skrll MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     15      1.1     skrll General Public License for more details.
     16      1.1     skrll 
     17      1.1     skrll You should have received a copy of the GNU General Public License
     18      1.1     skrll along with GNU CC; see the file COPYING.  If not, write to
     19      1.1     skrll the Free Software Foundation, 51 Franklin Street - Fifth Floor,
     20      1.1     skrll Boston, MA 02110-1301, USA.  */
     21      1.1     skrll 
     22      1.1     skrll #ifdef HAVE_CONFIG_H
     23      1.1     skrll #include "config.h"
     24      1.1     skrll #endif
     25      1.1     skrll #include "libiberty.h"
     26      1.1     skrll #include "sort.h"
     27      1.1     skrll #ifdef HAVE_LIMITS_H
     28      1.1     skrll #include <limits.h>
     29      1.1     skrll #endif
     30      1.1     skrll #ifdef HAVE_SYS_PARAM_H
     31      1.1     skrll #include <sys/param.h>
     32      1.1     skrll #endif
     33      1.1     skrll #ifdef HAVE_STDLIB_H
     34      1.1     skrll #include <stdlib.h>
     35      1.1     skrll #endif
     36      1.1     skrll #ifdef HAVE_STRING_H
     37      1.1     skrll #include <string.h>
     38      1.1     skrll #endif
     39      1.1     skrll 
     40      1.1     skrll #ifndef UCHAR_MAX
     41      1.1     skrll #define UCHAR_MAX ((unsigned char)(-1))
     42      1.1     skrll #endif
     43      1.1     skrll 
     44      1.1     skrll /* POINTERS and WORK are both arrays of N pointers.  When this
     45      1.1     skrll    function returns POINTERS will be sorted in ascending order.  */
     46      1.1     skrll 
     47      1.1     skrll void sort_pointers (size_t n, void **pointers, void **work)
     48      1.1     skrll {
     49      1.1     skrll   /* The type of a single digit.  This can be any unsigned integral
     50      1.1     skrll      type.  When changing this, DIGIT_MAX should be changed as
     51      1.1     skrll      well.  */
     52      1.1     skrll   typedef unsigned char digit_t;
     53      1.1     skrll 
     54      1.1     skrll   /* The maximum value a single digit can have.  */
     55      1.1     skrll #define DIGIT_MAX (UCHAR_MAX + 1)
     56      1.1     skrll 
     57      1.1     skrll   /* The Ith entry is the number of elements in *POINTERSP that have I
     58      1.1     skrll      in the digit on which we are currently sorting.  */
     59      1.1     skrll   unsigned int count[DIGIT_MAX];
     60      1.1     skrll   /* Nonzero if we are running on a big-endian machine.  */
     61      1.1     skrll   int big_endian_p;
     62      1.1     skrll   size_t i;
     63      1.1     skrll   size_t j;
     64      1.1     skrll 
     65      1.1     skrll   /* The algorithm used here is radix sort which takes time linear in
     66      1.1     skrll      the number of elements in the array.  */
     67      1.1     skrll 
     68      1.1     skrll   /* The algorithm here depends on being able to swap the two arrays
     69      1.1     skrll      an even number of times.  */
     70      1.1     skrll   if ((sizeof (void *) / sizeof (digit_t)) % 2 != 0)
     71      1.1     skrll     abort ();
     72      1.1     skrll 
     73      1.1     skrll   /* Figure out the endianness of the machine.  */
     74      1.1     skrll   for (i = 0, j = 0; i < sizeof (size_t); ++i)
     75      1.1     skrll     {
     76      1.1     skrll       j *= (UCHAR_MAX + 1);
     77      1.1     skrll       j += i;
     78      1.1     skrll     }
     79      1.1     skrll   big_endian_p = (((char *)&j)[0] == 0);
     80      1.1     skrll 
     81      1.1     skrll   /* Move through the pointer values from least significant to most
     82      1.1     skrll      significant digits.  */
     83      1.1     skrll   for (i = 0; i < sizeof (void *) / sizeof (digit_t); ++i)
     84      1.1     skrll     {
     85      1.1     skrll       digit_t *digit;
     86      1.1     skrll       digit_t *bias;
     87      1.1     skrll       digit_t *top;
     88      1.1     skrll       unsigned int *countp;
     89      1.1     skrll       void **pointerp;
     90      1.1     skrll 
     91      1.1     skrll       /* The offset from the start of the pointer will depend on the
     92      1.1     skrll 	 endianness of the machine.  */
     93      1.1     skrll       if (big_endian_p)
     94      1.1     skrll 	j = sizeof (void *) / sizeof (digit_t) - i;
     95      1.1     skrll       else
     96      1.1     skrll 	j = i;
     97      1.1     skrll 
     98      1.1     skrll       /* Now, perform a stable sort on this digit.  We use counting
     99      1.1     skrll 	 sort.  */
    100      1.1     skrll       memset (count, 0, DIGIT_MAX * sizeof (unsigned int));
    101      1.1     skrll 
    102      1.1     skrll       /* Compute the address of the appropriate digit in the first and
    103      1.1     skrll 	 one-past-the-end elements of the array.  On a little-endian
    104      1.1     skrll 	 machine, the least-significant digit is closest to the front.  */
    105      1.1     skrll       bias = ((digit_t *) pointers) + j;
    106      1.1     skrll       top = ((digit_t *) (pointers + n)) + j;
    107      1.1     skrll 
    108      1.1     skrll       /* Count how many there are of each value.  At the end of this
    109      1.1     skrll 	 loop, COUNT[K] will contain the number of pointers whose Ith
    110      1.1     skrll 	 digit is K.  */
    111      1.1     skrll       for (digit = bias;
    112      1.1     skrll 	   digit < top;
    113      1.1     skrll 	   digit += sizeof (void *) / sizeof (digit_t))
    114      1.1     skrll 	++count[*digit];
    115      1.1     skrll 
    116      1.1     skrll       /* Now, make COUNT[K] contain the number of pointers whose Ith
    117      1.1     skrll 	 digit is less than or equal to K.  */
    118      1.1     skrll       for (countp = count + 1; countp < count + DIGIT_MAX; ++countp)
    119      1.1     skrll 	*countp += countp[-1];
    120      1.1     skrll 
    121      1.1     skrll       /* Now, drop the pointers into their correct locations.  */
    122      1.1     skrll       for (pointerp = pointers + n - 1; pointerp >= pointers; --pointerp)
    123      1.1     skrll 	work[--count[((digit_t *) pointerp)[j]]] = *pointerp;
    124      1.1     skrll 
    125      1.1     skrll       /* Swap WORK and POINTERS so that POINTERS contains the sorted
    126      1.1     skrll 	 array.  */
    127      1.1     skrll       pointerp = pointers;
    128      1.1     skrll       pointers = work;
    129      1.1     skrll       work = pointerp;
    130      1.1     skrll     }
    131      1.1     skrll }
    132      1.1     skrll 
    133      1.1     skrll /* Everything below here is a unit test for the routines in this
    134      1.1     skrll    file.  */
    135      1.1     skrll 
    136      1.1     skrll #ifdef UNIT_TEST
    137      1.1     skrll 
    138      1.1     skrll #include <stdio.h>
    139      1.1     skrll 
    140      1.1     skrll void *xmalloc (size_t n)
    141      1.1     skrll {
    142      1.1     skrll   return malloc (n);
    143      1.1     skrll }
    144      1.1     skrll 
    145      1.1     skrll int main (int argc, char **argv)
    146      1.1     skrll {
    147      1.1     skrll   int k;
    148      1.1     skrll   int result;
    149      1.1     skrll   size_t i;
    150      1.1     skrll   void **pointers;
    151      1.1     skrll   void **work;
    152      1.1     skrll 
    153      1.1     skrll   if (argc > 1)
    154      1.1     skrll     k = atoi (argv[1]);
    155      1.1     skrll   else
    156      1.1     skrll     k = 10;
    157      1.1     skrll 
    158      1.1     skrll   pointers = XNEWVEC (void*, k);
    159      1.1     skrll   work = XNEWVEC (void*, k);
    160      1.1     skrll 
    161      1.1     skrll   for (i = 0; i < k; ++i)
    162      1.1     skrll     {
    163      1.1     skrll       pointers[i] = (void *) random ();
    164      1.1     skrll       printf ("%x\n", pointers[i]);
    165      1.1     skrll     }
    166      1.1     skrll 
    167      1.1     skrll   sort_pointers (k, pointers, work);
    168      1.1     skrll 
    169      1.1     skrll   printf ("\nSorted\n\n");
    170      1.1     skrll 
    171      1.1     skrll   result = 0;
    172      1.1     skrll 
    173      1.1     skrll   for (i = 0; i < k; ++i)
    174      1.1     skrll     {
    175      1.1     skrll       printf ("%x\n", pointers[i]);
    176      1.1     skrll       if (i > 0 && (char*) pointers[i] < (char*) pointers[i - 1])
    177      1.1     skrll 	result = 1;
    178      1.1     skrll     }
    179      1.1     skrll 
    180      1.1     skrll   free (pointers);
    181      1.1     skrll   free (work);
    182      1.1     skrll 
    183      1.1     skrll   return result;
    184      1.1     skrll }
    185      1.1     skrll 
    186      1.1     skrll #endif
    187