My build of nnn with minor changes
Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.
 
 
 
 
 
 

187 рядки
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: */