qsort.c 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. /* Copyright (C) 2011 by Valentin Ochs
  2. *
  3. * Permission is hereby granted, free of charge, to any person obtaining a copy
  4. * of this software and associated documentation files (the "Software"), to
  5. * deal in the Software without restriction, including without limitation the
  6. * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  7. * sell copies of the Software, and to permit persons to whom the Software is
  8. * furnished to do so, subject to the following conditions:
  9. *
  10. * The above copyright notice and this permission notice shall be included in
  11. * all copies or substantial portions of the Software.
  12. *
  13. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  14. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  15. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  16. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  17. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  18. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  19. * IN THE SOFTWARE.
  20. */
  21. /* Minor changes by Rich Felker for integration in musl, 2011-04-27. */
  22. #include <stdint.h>
  23. #include <stdlib.h>
  24. #include <string.h>
  25. #include "atomic.h"
  26. #define ntz(x) a_ctz_l((x))
  27. typedef int (*cmpfun)(const void *, const void *);
  28. static inline int pntz(size_t p[2]) {
  29. int r = ntz(p[0] - 1);
  30. if(r != 0 || (r = 8*sizeof(size_t) + ntz(p[1])) != 8*sizeof(size_t)) {
  31. return r;
  32. }
  33. return 0;
  34. }
  35. static void cycle(size_t width, unsigned char* ar[], int n)
  36. {
  37. unsigned char tmp[256];
  38. size_t l;
  39. int i;
  40. if(n < 2) {
  41. return;
  42. }
  43. ar[n] = tmp;
  44. while(width) {
  45. l = sizeof(tmp) < width ? sizeof(tmp) : width;
  46. memcpy(ar[n], ar[0], l);
  47. for(i = 0; i < n; i++) {
  48. memcpy(ar[i], ar[i + 1], l);
  49. ar[i] += l;
  50. }
  51. width -= l;
  52. }
  53. }
  54. /* shl() and shr() need n > 0 */
  55. static inline void shl(size_t p[2], int n)
  56. {
  57. if(n >= 8 * sizeof(size_t)) {
  58. n -= 8 * sizeof(size_t);
  59. p[1] = p[0];
  60. p[0] = 0;
  61. }
  62. p[1] <<= n;
  63. p[1] |= p[0] >> (sizeof(size_t) * 8 - n);
  64. p[0] <<= n;
  65. }
  66. static inline void shr(size_t p[2], int n)
  67. {
  68. if(n >= 8 * sizeof(size_t)) {
  69. n -= 8 * sizeof(size_t);
  70. p[0] = p[1];
  71. p[1] = 0;
  72. }
  73. p[0] >>= n;
  74. p[0] |= p[1] << (sizeof(size_t) * 8 - n);
  75. p[1] >>= n;
  76. }
  77. static void sift(unsigned char *head, size_t width, cmpfun cmp, int pshift, size_t lp[])
  78. {
  79. unsigned char *rt, *lf;
  80. unsigned char *ar[14 * sizeof(size_t) + 1];
  81. int i = 1;
  82. ar[0] = head;
  83. while(pshift > 1) {
  84. rt = head - width;
  85. lf = head - width - lp[pshift - 2];
  86. if((*cmp)(ar[0], lf) >= 0 && (*cmp)(ar[0], rt) >= 0) {
  87. break;
  88. }
  89. if((*cmp)(lf, rt) >= 0) {
  90. ar[i++] = lf;
  91. head = lf;
  92. pshift -= 1;
  93. } else {
  94. ar[i++] = rt;
  95. head = rt;
  96. pshift -= 2;
  97. }
  98. }
  99. cycle(width, ar, i);
  100. }
  101. static void trinkle(unsigned char *head, size_t width, cmpfun cmp, size_t pp[2], int pshift, int trusty, size_t lp[])
  102. {
  103. unsigned char *stepson,
  104. *rt, *lf;
  105. size_t p[2];
  106. unsigned char *ar[14 * sizeof(size_t) + 1];
  107. int i = 1;
  108. int trail;
  109. p[0] = pp[0];
  110. p[1] = pp[1];
  111. ar[0] = head;
  112. while(p[0] != 1 || p[1] != 0) {
  113. stepson = head - lp[pshift];
  114. if((*cmp)(stepson, ar[0]) <= 0) {
  115. break;
  116. }
  117. if(!trusty && pshift > 1) {
  118. rt = head - width;
  119. lf = head - width - lp[pshift - 2];
  120. if((*cmp)(rt, stepson) >= 0 || (*cmp)(lf, stepson) >= 0) {
  121. break;
  122. }
  123. }
  124. ar[i++] = stepson;
  125. head = stepson;
  126. trail = pntz(p);
  127. shr(p, trail);
  128. pshift += trail;
  129. trusty = 0;
  130. }
  131. if(!trusty) {
  132. cycle(width, ar, i);
  133. sift(head, width, cmp, pshift, lp);
  134. }
  135. }
  136. void qsort(void *base, size_t nel, size_t width, cmpfun cmp)
  137. {
  138. size_t lp[12*sizeof(size_t)];
  139. size_t i, size = width * nel;
  140. unsigned char *head, *high;
  141. size_t p[2] = {1, 0};
  142. int pshift = 1;
  143. int trail;
  144. if (!size) return;
  145. head = base;
  146. high = head + size - width;
  147. /* Precompute Leonardo numbers, scaled by element width */
  148. for(lp[0]=lp[1]=width, i=2; (lp[i]=lp[i-2]+lp[i-1]+width) < size; i++);
  149. while(head < high) {
  150. if((p[0] & 3) == 3) {
  151. sift(head, width, cmp, pshift, lp);
  152. shr(p, 2);
  153. pshift += 2;
  154. } else {
  155. if(lp[pshift - 1] >= high - head) {
  156. trinkle(head, width, cmp, p, pshift, 0, lp);
  157. } else {
  158. sift(head, width, cmp, pshift, lp);
  159. }
  160. if(pshift == 1) {
  161. shl(p, 1);
  162. pshift = 0;
  163. } else {
  164. shl(p, pshift - 1);
  165. pshift = 1;
  166. }
  167. }
  168. p[0] |= 1;
  169. head += width;
  170. }
  171. trinkle(head, width, cmp, p, pshift, 0, lp);
  172. while(pshift != 1 || p[0] != 1 || p[1] != 0) {
  173. if(pshift <= 1) {
  174. trail = pntz(p);
  175. shr(p, trail);
  176. pshift += trail;
  177. } else {
  178. shl(p, 2);
  179. pshift -= 2;
  180. p[0] ^= 7;
  181. shr(p, 1);
  182. trinkle(head - lp[pshift] - width, width, cmp, p, pshift + 1, 1, lp);
  183. shl(p, 1);
  184. p[0] |= 1;
  185. trinkle(head - width, width, cmp, p, pshift, 1, lp);
  186. }
  187. head -= width;
  188. }
  189. }