msort.c 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310
  1. /* An alternative to qsort, with an identical interface.
  2. This file is part of the GNU C Library.
  3. Copyright (C) 1992-2019 Free Software Foundation, Inc.
  4. Written by Mike Haertel, September 1988.
  5. The GNU C Library is free software; you can redistribute it and/or
  6. modify it under the terms of the GNU Lesser General Public
  7. License as published by the Free Software Foundation; either
  8. version 2.1 of the License, or (at your option) any later version.
  9. The GNU C Library is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. Lesser General Public License for more details.
  13. You should have received a copy of the GNU Lesser General Public
  14. License along with the GNU C Library; if not, see
  15. <http://www.gnu.org/licenses/>. */
  16. #include <alloca.h>
  17. #include <stdint.h>
  18. #include <stdlib.h>
  19. #include <string.h>
  20. #include <unistd.h>
  21. #include <memcopy.h>
  22. #include <errno.h>
  23. #include <atomic.h>
  24. struct msort_param
  25. {
  26. size_t s;
  27. size_t var;
  28. __compar_d_fn_t cmp;
  29. void *arg;
  30. char *t;
  31. };
  32. static void msort_with_tmp (const struct msort_param *p, void *b, size_t n);
  33. static void
  34. msort_with_tmp (const struct msort_param *p, void *b, size_t n)
  35. {
  36. char *b1, *b2;
  37. size_t n1, n2;
  38. if (n <= 1)
  39. return;
  40. n1 = n / 2;
  41. n2 = n - n1;
  42. b1 = b;
  43. b2 = (char *) b + (n1 * p->s);
  44. msort_with_tmp (p, b1, n1);
  45. msort_with_tmp (p, b2, n2);
  46. char *tmp = p->t;
  47. const size_t s = p->s;
  48. __compar_d_fn_t cmp = p->cmp;
  49. void *arg = p->arg;
  50. switch (p->var)
  51. {
  52. case 0:
  53. while (n1 > 0 && n2 > 0)
  54. {
  55. if ((*cmp) (b1, b2, arg) <= 0)
  56. {
  57. *(uint32_t *) tmp = *(uint32_t *) b1;
  58. b1 += sizeof (uint32_t);
  59. --n1;
  60. }
  61. else
  62. {
  63. *(uint32_t *) tmp = *(uint32_t *) b2;
  64. b2 += sizeof (uint32_t);
  65. --n2;
  66. }
  67. tmp += sizeof (uint32_t);
  68. }
  69. break;
  70. case 1:
  71. while (n1 > 0 && n2 > 0)
  72. {
  73. if ((*cmp) (b1, b2, arg) <= 0)
  74. {
  75. *(uint64_t *) tmp = *(uint64_t *) b1;
  76. b1 += sizeof (uint64_t);
  77. --n1;
  78. }
  79. else
  80. {
  81. *(uint64_t *) tmp = *(uint64_t *) b2;
  82. b2 += sizeof (uint64_t);
  83. --n2;
  84. }
  85. tmp += sizeof (uint64_t);
  86. }
  87. break;
  88. case 2:
  89. while (n1 > 0 && n2 > 0)
  90. {
  91. unsigned long *tmpl = (unsigned long *) tmp;
  92. unsigned long *bl;
  93. tmp += s;
  94. if ((*cmp) (b1, b2, arg) <= 0)
  95. {
  96. bl = (unsigned long *) b1;
  97. b1 += s;
  98. --n1;
  99. }
  100. else
  101. {
  102. bl = (unsigned long *) b2;
  103. b2 += s;
  104. --n2;
  105. }
  106. while (tmpl < (unsigned long *) tmp)
  107. *tmpl++ = *bl++;
  108. }
  109. break;
  110. case 3:
  111. while (n1 > 0 && n2 > 0)
  112. {
  113. if ((*cmp) (*(const void **) b1, *(const void **) b2, arg) <= 0)
  114. {
  115. *(void **) tmp = *(void **) b1;
  116. b1 += sizeof (void *);
  117. --n1;
  118. }
  119. else
  120. {
  121. *(void **) tmp = *(void **) b2;
  122. b2 += sizeof (void *);
  123. --n2;
  124. }
  125. tmp += sizeof (void *);
  126. }
  127. break;
  128. default:
  129. while (n1 > 0 && n2 > 0)
  130. {
  131. if ((*cmp) (b1, b2, arg) <= 0)
  132. {
  133. tmp = (char *) __mempcpy (tmp, b1, s);
  134. b1 += s;
  135. --n1;
  136. }
  137. else
  138. {
  139. tmp = (char *) __mempcpy (tmp, b2, s);
  140. b2 += s;
  141. --n2;
  142. }
  143. }
  144. break;
  145. }
  146. if (n1 > 0)
  147. memcpy (tmp, b1, n1 * s);
  148. memcpy (b, p->t, (n - n2) * s);
  149. }
  150. void
  151. __qsort_r (void *b, size_t n, size_t s, __compar_d_fn_t cmp, void *arg)
  152. {
  153. size_t size = n * s;
  154. char *tmp = NULL;
  155. struct msort_param p;
  156. /* For large object sizes use indirect sorting. */
  157. if (s > 32)
  158. size = 2 * n * sizeof (void *) + s;
  159. if (size < 1024)
  160. /* The temporary array is small, so put it on the stack. */
  161. p.t = __alloca (size);
  162. else
  163. {
  164. /* We should avoid allocating too much memory since this might
  165. have to be backed up by swap space. */
  166. static long int phys_pages;
  167. static int pagesize;
  168. if (pagesize == 0)
  169. {
  170. phys_pages = __sysconf (_SC_PHYS_PAGES);
  171. if (phys_pages == -1)
  172. /* Error while determining the memory size. So let's
  173. assume there is enough memory. Otherwise the
  174. implementer should provide a complete implementation of
  175. the `sysconf' function. */
  176. phys_pages = (long int) (~0ul >> 1);
  177. /* The following determines that we will never use more than
  178. a quarter of the physical memory. */
  179. phys_pages /= 4;
  180. /* Make sure phys_pages is written to memory. */
  181. atomic_write_barrier ();
  182. pagesize = __sysconf (_SC_PAGESIZE);
  183. }
  184. /* Just a comment here. We cannot compute
  185. phys_pages * pagesize
  186. and compare the needed amount of memory against this value.
  187. The problem is that some systems might have more physical
  188. memory then can be represented with a `size_t' value (when
  189. measured in bytes. */
  190. /* If the memory requirements are too high don't allocate memory. */
  191. if (size / pagesize > (size_t) phys_pages)
  192. {
  193. _quicksort (b, n, s, cmp, arg);
  194. return;
  195. }
  196. /* It's somewhat large, so malloc it. */
  197. int save = errno;
  198. tmp = malloc (size);
  199. __set_errno (save);
  200. if (tmp == NULL)
  201. {
  202. /* Couldn't get space, so use the slower algorithm
  203. that doesn't need a temporary array. */
  204. _quicksort (b, n, s, cmp, arg);
  205. return;
  206. }
  207. p.t = tmp;
  208. }
  209. p.s = s;
  210. p.var = 4;
  211. p.cmp = cmp;
  212. p.arg = arg;
  213. if (s > 32)
  214. {
  215. /* Indirect sorting. */
  216. char *ip = (char *) b;
  217. void **tp = (void **) (p.t + n * sizeof (void *));
  218. void **t = tp;
  219. void *tmp_storage = (void *) (tp + n);
  220. while ((void *) t < tmp_storage)
  221. {
  222. *t++ = ip;
  223. ip += s;
  224. }
  225. p.s = sizeof (void *);
  226. p.var = 3;
  227. msort_with_tmp (&p, p.t + n * sizeof (void *), n);
  228. /* tp[0] .. tp[n - 1] is now sorted, copy around entries of
  229. the original array. Knuth vol. 3 (2nd ed.) exercise 5.2-10. */
  230. char *kp;
  231. size_t i;
  232. for (i = 0, ip = (char *) b; i < n; i++, ip += s)
  233. if ((kp = tp[i]) != ip)
  234. {
  235. size_t j = i;
  236. char *jp = ip;
  237. memcpy (tmp_storage, ip, s);
  238. do
  239. {
  240. size_t k = (kp - (char *) b) / s;
  241. tp[j] = jp;
  242. memcpy (jp, kp, s);
  243. j = k;
  244. jp = kp;
  245. kp = tp[k];
  246. }
  247. while (kp != ip);
  248. tp[j] = jp;
  249. memcpy (jp, tmp_storage, s);
  250. }
  251. }
  252. else
  253. {
  254. if ((s & (sizeof (uint32_t) - 1)) == 0
  255. && ((char *) b - (char *) 0) % __alignof__ (uint32_t) == 0)
  256. {
  257. if (s == sizeof (uint32_t))
  258. p.var = 0;
  259. else if (s == sizeof (uint64_t)
  260. && ((char *) b - (char *) 0) % __alignof__ (uint64_t) == 0)
  261. p.var = 1;
  262. else if ((s & (sizeof (unsigned long) - 1)) == 0
  263. && ((char *) b - (char *) 0)
  264. % __alignof__ (unsigned long) == 0)
  265. p.var = 2;
  266. }
  267. msort_with_tmp (&p, b, n);
  268. }
  269. free (tmp);
  270. }
  271. libc_hidden_def (__qsort_r)
  272. weak_alias (__qsort_r, qsort_r)
  273. void
  274. qsort (void *b, size_t n, size_t s, __compar_fn_t cmp)
  275. {
  276. return __qsort_r (b, n, s, (__compar_d_fn_t) cmp, NULL);
  277. }
  278. libc_hidden_def (qsort)