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