sortbase.pp 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  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. TPtrListSorter_Context = procedure(ItemPtrs: PPointer; ItemCount: SizeUInt; Comparer: TListSortComparer_Context; Context: Pointer);
  21. TItemListSorter_Context = procedure(Items: Pointer; ItemCount, ItemSize: SizeUInt; Comparer: TListSortComparer_Context; Context: Pointer);
  22. PSortingAlgorithm = ^TSortingAlgorithm;
  23. TSortingAlgorithm = record
  24. PtrListSorter_NoContextComparer: TPtrListSorter_NoContext;
  25. PtrListSorter_ContextComparer: TPtrListSorter_Context;
  26. ItemListSorter_ContextComparer: TItemListSorter_Context;
  27. end;
  28. procedure QuickSort_PtrList_NoContext(ItemPtrs: PPointer; ItemCount: SizeUInt; Comparer: TListSortComparer_NoContext);
  29. procedure QuickSort_PtrList_Context(ItemPtrs: PPointer; ItemCount: SizeUInt; Comparer: TListSortComparer_Context; Context: Pointer);
  30. procedure QuickSort_ItemList_Context(Items: Pointer; ItemCount, ItemSize: SizeUInt; Comparer: TListSortComparer_Context; Context: Pointer);
  31. const
  32. QuickSort: TSortingAlgorithm = (
  33. PtrListSorter_NoContextComparer: @QuickSort_PtrList_NoContext;
  34. PtrListSorter_ContextComparer: @QuickSort_PtrList_Context;
  35. ItemListSorter_ContextComparer: @QuickSort_ItemList_Context;
  36. );
  37. var
  38. DefaultSortingAlgorithm: PSortingAlgorithm = @QuickSort;
  39. implementation
  40. Procedure QuickSort_PtrList_NoContext(ItemPtrs: PPointer; L, R : Longint;
  41. Comparer: TListSortComparer_NoContext);
  42. var
  43. I, J : Longint;
  44. P, Q : Pointer;
  45. begin
  46. repeat
  47. I := L;
  48. J := R;
  49. P := ItemPtrs[ (L + R) div 2 ];
  50. repeat
  51. while Comparer(P, ItemPtrs[i]) > 0 do
  52. Inc(I);
  53. while Comparer(P, ItemPtrs[J]) < 0 do
  54. Dec(J);
  55. If I <= J then
  56. begin
  57. Q := ItemPtrs[I];
  58. ItemPtrs[I] := ItemPtrs[J];
  59. ItemPtrs[J] := Q;
  60. Inc(I);
  61. Dec(J);
  62. end;
  63. until I > J;
  64. // sort the smaller range recursively
  65. // sort the bigger range via the loop
  66. // Reasons: memory usage is O(log(n)) instead of O(n) and loop is faster than recursion
  67. if J - L < R - I then
  68. begin
  69. if L < J then
  70. QuickSort_PtrList_NoContext(ItemPtrs, L, J, Comparer);
  71. L := I;
  72. end
  73. else
  74. begin
  75. if I < R then
  76. QuickSort_PtrList_NoContext(ItemPtrs, I, R, Comparer);
  77. R := J;
  78. end;
  79. until L >= R;
  80. end;
  81. procedure QuickSort_PtrList_NoContext(ItemPtrs: PPointer; ItemCount: SizeUInt; Comparer: TListSortComparer_NoContext);
  82. begin
  83. if not Assigned(ItemPtrs) or (ItemCount < 2) then
  84. exit;
  85. QuickSort_PtrList_NoContext(ItemPtrs, 0, ItemCount - 1, Comparer);
  86. end;
  87. procedure QuickSort_PtrList_Context(ItemPtrs: PPointer; ItemCount: SizeUInt; Comparer: TListSortComparer_Context; Context: Pointer);
  88. procedure QuickSort(L, R : Longint);
  89. var
  90. I, J : Longint;
  91. P, Q : Pointer;
  92. begin
  93. repeat
  94. I := L;
  95. J := R;
  96. P := ItemPtrs[ (L + R) div 2 ];
  97. repeat
  98. while Comparer(P, ItemPtrs[I], Context) > 0 do
  99. Inc(I);
  100. while Comparer(P, ItemPtrs[J], Context) < 0 do
  101. Dec(J);
  102. If I <= J then
  103. begin
  104. Q := ItemPtrs[I];
  105. ItemPtrs[I] := ItemPtrs[J];
  106. ItemPtrs[J] := Q;
  107. Inc(I);
  108. Dec(J);
  109. end;
  110. until I > J;
  111. // sort the smaller range recursively
  112. // sort the bigger range via the loop
  113. // Reasons: memory usage is O(log(n)) instead of O(n) and loop is faster than recursion
  114. if J - L < R - I then
  115. begin
  116. if L < J then
  117. QuickSort(L, J);
  118. L := I;
  119. end
  120. else
  121. begin
  122. if I < R then
  123. QuickSort(I, R);
  124. R := J;
  125. end;
  126. until L >= R;
  127. end;
  128. begin
  129. if not Assigned(ItemPtrs) or (ItemCount < 2) then
  130. exit;
  131. QuickSort(0, ItemCount - 1);
  132. end;
  133. procedure QuickSort_ItemList_Context(Items: Pointer; ItemCount, ItemSize: SizeUInt; Comparer: TListSortComparer_Context; Context: Pointer);
  134. var
  135. TempBuf: Pointer;
  136. procedure QuickSort(L, R : Longint);
  137. var
  138. I, J : Longint;
  139. P : Pointer;
  140. begin
  141. repeat
  142. I := L;
  143. J := R;
  144. P := Items + ItemSize*((L + R) div 2);
  145. repeat
  146. while Comparer(P, Items + ItemSize*I, Context) > 0 do
  147. Inc(I);
  148. while Comparer(P, Items + ItemSize*J, Context) < 0 do
  149. Dec(J);
  150. If I <= J then
  151. begin
  152. Move((Items + ItemSize*I)^, TempBuf^, ItemSize);
  153. Move((Items + ItemSize*J)^, (Items + ItemSize*I)^, ItemSize);
  154. Move(TempBuf^, (Items + ItemSize*J)^, ItemSize);
  155. Inc(I);
  156. Dec(J);
  157. end;
  158. until I > J;
  159. // sort the smaller range recursively
  160. // sort the bigger range via the loop
  161. // Reasons: memory usage is O(log(n)) instead of O(n) and loop is faster than recursion
  162. if J - L < R - I then
  163. begin
  164. if L < J then
  165. QuickSort(L, J);
  166. L := I;
  167. end
  168. else
  169. begin
  170. if I < R then
  171. QuickSort(I, R);
  172. R := J;
  173. end;
  174. until L >= R;
  175. end;
  176. begin
  177. if not Assigned(Items) or (ItemCount < 2) or (ItemSize < 1) then
  178. exit;
  179. GetMem(TempBuf, ItemSize);
  180. QuickSort(0, ItemCount - 1);
  181. FreeMem(TempBuf, ItemSize);
  182. end;
  183. end.