sort.c 4.8 KB

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