sortbase.pp 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285
  1. {
  2. This file is part of the Free Pascal Run Time Library (rtl)
  3. Copyright (c) 1999-2019 by the Free Pascal development team
  4. This file provides the base for the pluggable sorting algorithm
  5. support. It also provides a default QuickSort implementation.
  6. See the file COPYING.FPC, included in this distribution,
  7. for details about the copyright.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11. **********************************************************************}
  12. unit sortbase;
  13. {$MODE objfpc}
  14. interface
  15. type
  16. TListSortComparer_NoContext = function(Item1, Item2: Pointer): Integer;
  17. TPtrListSorter_NoContext = procedure(ItemPtrs: PPointer; ItemCount: SizeUInt; Comparer: TListSortComparer_NoContext);
  18. TItemListSorter_NoContext = procedure(Items: Pointer; ItemCount, ItemSize: SizeUInt; Comparer: TListSortComparer_NoContext);
  19. TListSortComparer_Context = function(Item1, Item2, Context: Pointer): Integer;
  20. TListSortCustomItemExchanger_Context = procedure(Item1, Item2, Context: Pointer);
  21. TPtrListSorter_Context = procedure(ItemPtrs: PPointer; ItemCount: SizeUInt; Comparer: TListSortComparer_Context; Context: Pointer);
  22. TItemListSorter_Context = procedure(Items: Pointer; ItemCount, ItemSize: SizeUInt; Comparer: TListSortComparer_Context; Context: Pointer);
  23. TItemListSorter_CustomItemExchanger_Context = procedure(Items: Pointer;
  24. ItemCount, ItemSize: SizeUInt; Comparer: TListSortComparer_Context;
  25. Exchanger: TListSortCustomItemExchanger_Context; Context: Pointer);
  26. PSortingAlgorithm = ^TSortingAlgorithm;
  27. TSortingAlgorithm = record
  28. PtrListSorter_NoContextComparer: TPtrListSorter_NoContext;
  29. PtrListSorter_ContextComparer: TPtrListSorter_Context;
  30. ItemListSorter_ContextComparer: TItemListSorter_Context;
  31. ItemListSorter_CustomItemExchanger_ContextComparer: TItemListSorter_CustomItemExchanger_Context;
  32. end;
  33. procedure QuickSort_PtrList_NoContext(ItemPtrs: PPointer; ItemCount: SizeUInt; Comparer: TListSortComparer_NoContext);
  34. procedure QuickSort_PtrList_Context(ItemPtrs: PPointer; ItemCount: SizeUInt; Comparer: TListSortComparer_Context; Context: Pointer);
  35. procedure QuickSort_ItemList_Context(Items: Pointer; ItemCount, ItemSize: SizeUInt; Comparer: TListSortComparer_Context; Context: Pointer);
  36. procedure QuickSort_ItemList_CustomItemExchanger_Context(
  37. Items: Pointer;
  38. ItemCount, ItemSize: SizeUInt;
  39. Comparer: TListSortComparer_Context;
  40. Exchanger: TListSortCustomItemExchanger_Context;
  41. Context: Pointer);
  42. const
  43. QuickSort: TSortingAlgorithm = (
  44. PtrListSorter_NoContextComparer: @QuickSort_PtrList_NoContext;
  45. PtrListSorter_ContextComparer: @QuickSort_PtrList_Context;
  46. ItemListSorter_ContextComparer: @QuickSort_ItemList_Context;
  47. ItemListSorter_CustomItemExchanger_ContextComparer: @QuickSort_ItemList_CustomItemExchanger_Context;
  48. );
  49. var
  50. DefaultSortingAlgorithm: PSortingAlgorithm = @QuickSort;
  51. implementation
  52. Procedure QuickSort_PtrList_NoContext(ItemPtrs: PPointer; L, R : Longint;
  53. Comparer: TListSortComparer_NoContext);
  54. var
  55. I, J : Longint;
  56. P, Q : Pointer;
  57. begin
  58. repeat
  59. I := L;
  60. J := R;
  61. P := ItemPtrs[ (L + R) div 2 ];
  62. repeat
  63. while Comparer(P, ItemPtrs[i]) > 0 do
  64. Inc(I);
  65. while Comparer(P, ItemPtrs[J]) < 0 do
  66. Dec(J);
  67. If I <= J then
  68. begin
  69. Q := ItemPtrs[I];
  70. ItemPtrs[I] := ItemPtrs[J];
  71. ItemPtrs[J] := Q;
  72. Inc(I);
  73. Dec(J);
  74. end;
  75. until I > J;
  76. // sort the smaller range recursively
  77. // sort the bigger range via the loop
  78. // Reasons: memory usage is O(log(n)) instead of O(n) and loop is faster than recursion
  79. if J - L < R - I then
  80. begin
  81. if L < J then
  82. QuickSort_PtrList_NoContext(ItemPtrs, L, J, Comparer);
  83. L := I;
  84. end
  85. else
  86. begin
  87. if I < R then
  88. QuickSort_PtrList_NoContext(ItemPtrs, I, R, Comparer);
  89. R := J;
  90. end;
  91. until L >= R;
  92. end;
  93. procedure QuickSort_PtrList_NoContext(ItemPtrs: PPointer; ItemCount: SizeUInt; Comparer: TListSortComparer_NoContext);
  94. begin
  95. if not Assigned(ItemPtrs) or (ItemCount < 2) then
  96. exit;
  97. QuickSort_PtrList_NoContext(ItemPtrs, 0, ItemCount - 1, Comparer);
  98. end;
  99. procedure QuickSort_PtrList_Context(ItemPtrs: PPointer; ItemCount: SizeUInt; Comparer: TListSortComparer_Context; Context: Pointer);
  100. procedure QuickSort(L, R : Longint);
  101. var
  102. I, J : Longint;
  103. P, Q : Pointer;
  104. begin
  105. repeat
  106. I := L;
  107. J := R;
  108. P := ItemPtrs[ (L + R) div 2 ];
  109. repeat
  110. while Comparer(P, ItemPtrs[I], Context) > 0 do
  111. Inc(I);
  112. while Comparer(P, ItemPtrs[J], Context) < 0 do
  113. Dec(J);
  114. If I <= J then
  115. begin
  116. Q := ItemPtrs[I];
  117. ItemPtrs[I] := ItemPtrs[J];
  118. ItemPtrs[J] := Q;
  119. Inc(I);
  120. Dec(J);
  121. end;
  122. until I > J;
  123. // sort the smaller range recursively
  124. // sort the bigger range via the loop
  125. // Reasons: memory usage is O(log(n)) instead of O(n) and loop is faster than recursion
  126. if J - L < R - I then
  127. begin
  128. if L < J then
  129. QuickSort(L, J);
  130. L := I;
  131. end
  132. else
  133. begin
  134. if I < R then
  135. QuickSort(I, R);
  136. R := J;
  137. end;
  138. until L >= R;
  139. end;
  140. begin
  141. if not Assigned(ItemPtrs) or (ItemCount < 2) then
  142. exit;
  143. QuickSort(0, ItemCount - 1);
  144. end;
  145. procedure QuickSort_ItemList_Context(Items: Pointer; ItemCount, ItemSize: SizeUInt; Comparer: TListSortComparer_Context; Context: Pointer);
  146. var
  147. TempBuf: Pointer;
  148. procedure QuickSort(L, R : Longint);
  149. var
  150. I, J : Longint;
  151. P : Pointer;
  152. begin
  153. repeat
  154. I := L;
  155. J := R;
  156. P := Items + ItemSize*((L + R) div 2);
  157. repeat
  158. while Comparer(P, Items + ItemSize*I, Context) > 0 do
  159. Inc(I);
  160. while Comparer(P, Items + ItemSize*J, Context) < 0 do
  161. Dec(J);
  162. If I <= J then
  163. begin
  164. if I < J then
  165. begin
  166. Move((Items + ItemSize*I)^, TempBuf^, ItemSize);
  167. Move((Items + ItemSize*J)^, (Items + ItemSize*I)^, ItemSize);
  168. Move(TempBuf^, (Items + ItemSize*J)^, ItemSize);
  169. if P = (Items + ItemSize*I) then
  170. P := Items + ItemSize*J
  171. else if P = (Items + ItemSize*J) then
  172. P := Items + ItemSize*I;
  173. end;
  174. Inc(I);
  175. Dec(J);
  176. end;
  177. until I > J;
  178. // sort the smaller range recursively
  179. // sort the bigger range via the loop
  180. // Reasons: memory usage is O(log(n)) instead of O(n) and loop is faster than recursion
  181. if J - L < R - I then
  182. begin
  183. if L < J then
  184. QuickSort(L, J);
  185. L := I;
  186. end
  187. else
  188. begin
  189. if I < R then
  190. QuickSort(I, R);
  191. R := J;
  192. end;
  193. until L >= R;
  194. end;
  195. begin
  196. if not Assigned(Items) or (ItemCount < 2) or (ItemSize < 1) then
  197. exit;
  198. GetMem(TempBuf, ItemSize);
  199. QuickSort(0, ItemCount - 1);
  200. FreeMem(TempBuf, ItemSize);
  201. end;
  202. procedure QuickSort_ItemList_CustomItemExchanger_Context(
  203. Items: Pointer;
  204. ItemCount, ItemSize: SizeUInt;
  205. Comparer: TListSortComparer_Context;
  206. Exchanger: TListSortCustomItemExchanger_Context;
  207. Context: Pointer);
  208. procedure QuickSort(L, R : Longint);
  209. var
  210. I, J : Longint;
  211. P : Pointer;
  212. begin
  213. repeat
  214. I := L;
  215. J := R;
  216. P := Items + ItemSize*((L + R) div 2);
  217. repeat
  218. while Comparer(P, Items + ItemSize*I, Context) > 0 do
  219. Inc(I);
  220. while Comparer(P, Items + ItemSize*J, Context) < 0 do
  221. Dec(J);
  222. If I <= J then
  223. begin
  224. if I < J then
  225. begin
  226. Exchanger(Items + ItemSize*I, Items + ItemSize*J, Context);
  227. if P = (Items + ItemSize*I) then
  228. P := Items + ItemSize*J
  229. else if P = (Items + ItemSize*J) then
  230. P := Items + ItemSize*I;
  231. end;
  232. Inc(I);
  233. Dec(J);
  234. end;
  235. until I > J;
  236. // sort the smaller range recursively
  237. // sort the bigger range via the loop
  238. // Reasons: memory usage is O(log(n)) instead of O(n) and loop is faster than recursion
  239. if J - L < R - I then
  240. begin
  241. if L < J then
  242. QuickSort(L, J);
  243. L := I;
  244. end
  245. else
  246. begin
  247. if I < R then
  248. QuickSort(I, R);
  249. R := J;
  250. end;
  251. until L >= R;
  252. end;
  253. begin
  254. if not Assigned(Items) or (ItemCount < 2) or (ItemSize < 1) then
  255. exit;
  256. QuickSort(0, ItemCount - 1);
  257. end;
  258. end.