sortbase.pp 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  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. Move((Items + ItemSize*I)^, TempBuf^, ItemSize);
  165. Move((Items + ItemSize*J)^, (Items + ItemSize*I)^, ItemSize);
  166. Move(TempBuf^, (Items + ItemSize*J)^, ItemSize);
  167. Inc(I);
  168. Dec(J);
  169. end;
  170. until I > J;
  171. // sort the smaller range recursively
  172. // sort the bigger range via the loop
  173. // Reasons: memory usage is O(log(n)) instead of O(n) and loop is faster than recursion
  174. if J - L < R - I then
  175. begin
  176. if L < J then
  177. QuickSort(L, J);
  178. L := I;
  179. end
  180. else
  181. begin
  182. if I < R then
  183. QuickSort(I, R);
  184. R := J;
  185. end;
  186. until L >= R;
  187. end;
  188. begin
  189. if not Assigned(Items) or (ItemCount < 2) or (ItemSize < 1) then
  190. exit;
  191. GetMem(TempBuf, ItemSize);
  192. QuickSort(0, ItemCount - 1);
  193. FreeMem(TempBuf, ItemSize);
  194. end;
  195. procedure QuickSort_ItemList_CustomItemExchanger_Context(
  196. Items: Pointer;
  197. ItemCount, ItemSize: SizeUInt;
  198. Comparer: TListSortComparer_Context;
  199. Exchanger: TListSortCustomItemExchanger_Context;
  200. Context: Pointer);
  201. procedure QuickSort(L, R : Longint);
  202. var
  203. I, J : Longint;
  204. P : Pointer;
  205. begin
  206. repeat
  207. I := L;
  208. J := R;
  209. P := Items + ItemSize*((L + R) div 2);
  210. repeat
  211. while Comparer(P, Items + ItemSize*I, Context) > 0 do
  212. Inc(I);
  213. while Comparer(P, Items + ItemSize*J, Context) < 0 do
  214. Dec(J);
  215. If I <= J then
  216. begin
  217. Exchanger(Items + ItemSize*I, Items + ItemSize*J, Context);
  218. Inc(I);
  219. Dec(J);
  220. end;
  221. until I > J;
  222. // sort the smaller range recursively
  223. // sort the bigger range via the loop
  224. // Reasons: memory usage is O(log(n)) instead of O(n) and loop is faster than recursion
  225. if J - L < R - I then
  226. begin
  227. if L < J then
  228. QuickSort(L, J);
  229. L := I;
  230. end
  231. else
  232. begin
  233. if I < R then
  234. QuickSort(I, R);
  235. R := J;
  236. end;
  237. until L >= R;
  238. end;
  239. begin
  240. if not Assigned(Items) or (ItemCount < 2) or (ItemSize < 1) then
  241. exit;
  242. QuickSort(0, ItemCount - 1);
  243. end;
  244. end.