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