My build of nnn with minor changes
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.
 
 
 
 
 
 

187 lignes
7.3 KiB

  1. /*
  2. * Copyright (c) 2013, 2017 Alexey Tourbin
  3. *
  4. * Permission is hereby granted, free of charge, to any person obtaining a copy
  5. * of this software and associated documentation files (the "Software"), to deal
  6. * in the Software without restriction, including without limitation the rights
  7. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. * copies of the Software, and to permit persons to whom the Software is
  9. * furnished to do so, subject to the following conditions:
  10. *
  11. * The above copyright notice and this permission notice shall be included in
  12. * all copies or substantial portions of the Software.
  13. *
  14. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  20. * SOFTWARE.
  21. */
  22. /*
  23. * This is a traditional Quicksort implementation which mostly follows
  24. * [Sedgewick 1978]. Sorting is performed entirely on array indices,
  25. * while actual access to the array elements is abstracted out with the
  26. * user-defined `LESS` and `SWAP` primitives.
  27. *
  28. * Synopsis:
  29. * QSORT(N, LESS, SWAP);
  30. * where
  31. * N - the number of elements in A[];
  32. * LESS(i, j) - compares A[i] to A[j];
  33. * SWAP(i, j) - exchanges A[i] with A[j].
  34. */
  35. #ifndef QSORT_H
  36. #define QSORT_H
  37. /* Sort 3 elements. */
  38. #define Q_SORT3(q_a1, q_a2, q_a3, Q_LESS, Q_SWAP) \
  39. do { \
  40. if (Q_LESS(q_a2, q_a1)) { \
  41. if (Q_LESS(q_a3, q_a2)) \
  42. Q_SWAP(q_a1, q_a3); \
  43. else { \
  44. Q_SWAP(q_a1, q_a2); \
  45. if (Q_LESS(q_a3, q_a2)) \
  46. Q_SWAP(q_a2, q_a3); \
  47. } \
  48. } \
  49. else if (Q_LESS(q_a3, q_a2)) { \
  50. Q_SWAP(q_a2, q_a3); \
  51. if (Q_LESS(q_a2, q_a1)) \
  52. Q_SWAP(q_a1, q_a2); \
  53. } \
  54. } while (0)
  55. /* Partition [q_l,q_r] around a pivot. After partitioning,
  56. * [q_l,q_j] are the elements that are less than or equal to the pivot,
  57. * while [q_i,q_r] are the elements greater than or equal to the pivot. */
  58. #define Q_PARTITION(q_l, q_r, q_i, q_j, Q_UINT, Q_LESS, Q_SWAP) \
  59. do { \
  60. /* The middle element, not to be confused with the median. */ \
  61. Q_UINT q_m = (q_l) + (((q_r) - (q_l)) >> 1); \
  62. /* Reorder the second, the middle, and the last items. \
  63. * As [Edelkamp Weiss 2016] explain, using the second element \
  64. * instead of the first one helps avoid bad behaviour for \
  65. * decreasingly sorted arrays. This method is used in recent \
  66. * versions of gcc's std::sort, see gcc bug 58437#c13, although \
  67. * the details are somewhat different (cf. #c14). */ \
  68. Q_SORT3((q_l) + 1, q_m, q_r, Q_LESS, Q_SWAP); \
  69. /* Place the median at the beginning. */ \
  70. Q_SWAP(q_l, q_m); \
  71. /* Partition [q_l+2, q_r-1] around the median which is in q_l. \
  72. * q_i and q_j are initially off by one, they get decremented \
  73. * in the do-while loops. */ \
  74. (q_i) = (q_l) + 1; (q_j) = q_r; \
  75. while (1) { \
  76. do (q_i)++; while (Q_LESS(q_i, q_l)); \
  77. do (q_j)--; while (Q_LESS(q_l, q_j)); \
  78. if ((q_i) >= (q_j)) break; /* Sedgewick says "until j < i" */ \
  79. Q_SWAP(q_i, q_j); \
  80. } \
  81. /* Compensate for the i==j case. */ \
  82. (q_i) = (q_j) + 1; \
  83. /* Put the median to its final place. */ \
  84. Q_SWAP(q_l, q_j); \
  85. /* The median is not part of the left subfile. */ \
  86. (q_j)--; \
  87. } while (0)
  88. /* Insertion sort is applied to small subfiles - this is contrary to
  89. * Sedgewick's suggestion to run a separate insertion sort pass after
  90. * the partitioning is done. The reason I don't like a separate pass
  91. * is that it triggers extra comparisons, because it can't see that the
  92. * medians are already in their final positions and need not be rechecked.
  93. * Since I do not assume that comparisons are cheap, I also do not try
  94. * to eliminate the (q_j > q_l) boundary check. */
  95. #define Q_INSERTION_SORT(q_l, q_r, Q_UINT, Q_LESS, Q_SWAP) \
  96. do { \
  97. Q_UINT q_i, q_j; \
  98. /* For each item starting with the second... */ \
  99. for (q_i = (q_l) + 1; q_i <= (q_r); q_i++) \
  100. /* move it down the array so that the first part is sorted. */ \
  101. for (q_j = q_i; q_j > (q_l) && (Q_LESS(q_j, q_j - 1)); q_j--) \
  102. Q_SWAP(q_j, q_j - 1); \
  103. } while (0)
  104. /* When the size of [q_l,q_r], i.e. q_r-q_l+1, is greater than or equal to
  105. * Q_THRESH, the algorithm performs recursive partitioning. When the size
  106. * drops below Q_THRESH, the algorithm switches to insertion sort.
  107. * The minimum valid value is probably 5 (with 5 items, the second and
  108. * the middle items, the middle itself being rounded down, are distinct). */
  109. #define Q_THRESH 16
  110. /* The main loop. */
  111. #define Q_LOOP(Q_UINT, Q_N, Q_LESS, Q_SWAP) \
  112. do { \
  113. Q_UINT q_l = 0; \
  114. Q_UINT q_r = (Q_N) - 1; \
  115. Q_UINT q_sp = 0; /* the number of frames pushed to the stack */ \
  116. struct { Q_UINT q_l, q_r; } \
  117. /* On 32-bit platforms, to sort a "char[3GB+]" array, \
  118. * it may take full 32 stack frames. On 64-bit CPUs, \
  119. * though, the address space is limited to 48 bits. \
  120. * The usage is further reduced if Q_N has a 32-bit type. */ \
  121. q_st[sizeof(Q_UINT) > 4 && sizeof(Q_N) > 4 ? 48 : 32]; \
  122. while (1) { \
  123. if (q_r - q_l + 1 >= Q_THRESH) { \
  124. Q_UINT q_i, q_j; \
  125. Q_PARTITION(q_l, q_r, q_i, q_j, Q_UINT, Q_LESS, Q_SWAP); \
  126. /* Now have two subfiles: [q_l,q_j] and [q_i,q_r]. \
  127. * Dealing with them depends on which one is bigger. */ \
  128. if (q_j - q_l >= q_r - q_i) \
  129. Q_SUBFILES(q_l, q_j, q_i, q_r); \
  130. else \
  131. Q_SUBFILES(q_i, q_r, q_l, q_j); \
  132. } \
  133. else { \
  134. Q_INSERTION_SORT(q_l, q_r, Q_UINT, Q_LESS, Q_SWAP); \
  135. /* Pop subfiles from the stack, until it gets empty. */ \
  136. if (q_sp == 0) break; \
  137. q_sp--; \
  138. q_l = q_st[q_sp].q_l; \
  139. q_r = q_st[q_sp].q_r; \
  140. } \
  141. } \
  142. } while (0)
  143. /* The missing part: dealing with subfiles.
  144. * Assumes that the first subfile is not smaller than the second. */
  145. #define Q_SUBFILES(q_l1, q_r1, q_l2, q_r2) \
  146. do { \
  147. /* If the second subfile is only a single element, it needs \
  148. * no further processing. The first subfile will be processed \
  149. * on the next iteration (both subfiles cannot be only a single \
  150. * element, due to Q_THRESH). */ \
  151. if ((q_l2) == (q_r2)) { \
  152. q_l = q_l1; \
  153. q_r = q_r1; \
  154. } \
  155. else { \
  156. /* Otherwise, both subfiles need processing. \
  157. * Push the larger subfile onto the stack. */ \
  158. q_st[q_sp].q_l = q_l1; \
  159. q_st[q_sp].q_r = q_r1; \
  160. q_sp++; \
  161. /* Process the smaller subfile on the next iteration. */ \
  162. q_l = q_l2; \
  163. q_r = q_r2; \
  164. } \
  165. } while (0)
  166. /* And now, ladies and gentlemen, may I proudly present to you... */
  167. #define QSORT(Q_N, Q_LESS, Q_SWAP) \
  168. do { \
  169. if ((Q_N) > 1) \
  170. /* We could check sizeof(Q_N) and use "unsigned", but at least \
  171. * on x86_64, this has the performance penalty of up to 5%. */ \
  172. Q_LOOP(unsigned long, Q_N, Q_LESS, Q_SWAP); \
  173. } while (0)
  174. #endif
  175. /* ex:set ts=8 sts=4 sw=4 noet: */