ListExt.pas 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316
  1. unit ListExt;
  2. {==================================================================
  3. Component TListExt / Version 1.0 / 03.1999
  4. =============================================
  5. Description:
  6. ============
  7. My own version of managing sorted lists.
  8. Author:
  9. =======
  10. (c) Ingo Eckel
  11. Sodener Weg 38
  12. 65812 Bad Soden
  13. Germany
  14. ==================================================================}
  15. {==================================================================}
  16. interface
  17. {==================================================================}
  18. Uses Classes,
  19. SysUtils;
  20. Const InitSize = 500;
  21. ExtendSize = 500;
  22. FLess = -1;
  23. FEqual = 0;
  24. FGreater = 1;
  25. Type IntType = Integer;
  26. TLxDeleteEvent = Procedure(Sender : TObject; Var P : Pointer; Size : Integer) Of Object;
  27. {==================================================================}
  28. TListExt = Class(TInterfacedobject)
  29. {==================================================================}
  30. Private
  31. {==================================================================}
  32. FCount : IntType;
  33. FData : Array of Pointer;
  34. FSorted : Boolean;
  35. fOnDelete: TLxDeleteEvent;
  36. FItemSize: IntType;
  37. MaxCount : IntType;
  38. Function GetItem ( I : IntType) : Pointer;
  39. Procedure FreeItem ( I : IntType);
  40. {==================================================================}
  41. Public
  42. {==================================================================}
  43. property data[i : IntType] : Pointer Read GetItem; default;
  44. Property Sorted : Boolean Read fSorted;
  45. Property Count : IntType Read FCount;
  46. Property ItemSize : IntType Read FItemSize;
  47. Constructor Create(ItemSize : IntType);
  48. Procedure Free;
  49. Procedure Clear;
  50. Procedure Add(P : Pointer);
  51. Function IndexOf(P : Pointer) : IntType;
  52. Procedure Sort(Compare : TListSortCompare);
  53. Function Find(P : Pointer; Compare : TListSortCompare) : Integer;
  54. Function FindSequential(P : Pointer; Compare : TListSortCompare) : Integer;
  55. Function First : Pointer;
  56. Function Last : Pointer;
  57. procedure Delete(I: IntType);
  58. {==================================================================}
  59. Published
  60. {==================================================================}
  61. Property OnDelete: TLxDeleteEvent Read fOnDelete
  62. Write fOnDelete;
  63. End;
  64. {==================================================================}
  65. implementation
  66. {==================================================================}
  67. uses
  68. Math;
  69. Constructor TListExt.Create(ItemSize : IntType);
  70. Var i : IntType;
  71. Begin
  72. IF ItemSize < 0 Then
  73. Raise ERangeError.CreateFmt('TListExt: negative itemsize: %u',[ItemSize]);
  74. Inherited Create;
  75. FCount := 0;
  76. MaxCount := InitSize;
  77. FSorted := TRUE;
  78. FItemSize := ItemSize;
  79. SetLength(FData, MaxCount+1);
  80. For i := 0 To MaxCount Do
  81. FData[i] := NIL;
  82. End; {Create}
  83. Procedure TListExt.Free;
  84. Begin
  85. Clear;
  86. FData := NIL;
  87. Inherited Free;
  88. End;
  89. Procedure TListExt.Add(P : Pointer);
  90. Begin
  91. IF Fcount = MaxCount Then
  92. Begin
  93. INC(MaxCount, ExtendSize);
  94. SetLength(FData, MaxCount + 1);
  95. End;
  96. IF FCount >= MaxCount Then
  97. Raise ERangeError.CreateFmt('TListExt: buffer overflow: %u',[Fcount]);
  98. INC (FCount);
  99. FData[Pred(FCount)] := P;
  100. FSorted := FALSE;
  101. End; {Add}
  102. Function TListExt.IndexOf(P : Pointer) : IntType;
  103. Var i : IntType;
  104. Begin
  105. Result := 0;
  106. IF Not Assigned(P) Then Exit;
  107. For i := 0 To FCount Do
  108. IF P = FData[i] Then
  109. Begin
  110. Result := i;
  111. Exit;
  112. End;
  113. End; {IndexOf}
  114. Procedure TListExt.FreeItem(I : IntType);
  115. Begin
  116. Begin
  117. IF Assigned(FData[i]) Then
  118. Begin
  119. IF Assigned(fOnDelete) Then
  120. Begin
  121. fOnDelete(Self, FData[i], FItemSize);
  122. IF Assigned(FData[i]) Then
  123. FreeMem(FData[i], FItemSize);
  124. End
  125. Else
  126. FreeMem(FData[i], FItemSize);
  127. FData[i] := NIL;
  128. End;
  129. End;
  130. End; {FreeItem}
  131. Procedure TListExt.Clear;
  132. Var i : IntType;
  133. Begin
  134. For i := 0 To Pred(FCount) Do
  135. Begin
  136. IF Assigned(FData[i]) Then
  137. FreeItem(i)
  138. Else
  139. Break;
  140. End;
  141. FCount := 0;
  142. FSorted := TRUE;
  143. MaxCount := InitSize;
  144. SetLength(FData, MaxCount + 1);
  145. End; {Clear}
  146. Function TListExt.GetItem(I : IntType) : Pointer;
  147. Begin
  148. IF (i >= FCount) Then
  149. Begin
  150. Raise ERangeError.CreateFmt('TListExt: index out of range: %u',[i]);
  151. Result := NIL;
  152. Exit;
  153. End;
  154. Result := FData[i];
  155. End; {GetItem}
  156. Function TListExt.First : Pointer;
  157. Begin
  158. Result := NIL;
  159. IF Count > 0 Then
  160. Result := FData[0];
  161. End; {First}
  162. Function TListExt.Last : Pointer;
  163. Begin
  164. Result := NIL;
  165. IF Count > 0 Then
  166. Result := FData[Pred(FCount)];
  167. End; {Last}
  168. Procedure TListExt.Delete(i : IntType);
  169. Begin
  170. IF (FCount = 0) Or (i > Pred(FCount)) Then Exit;
  171. FreeItem(i);
  172. IF FCount - Succ(i) > 0 Then
  173. Move(FData[Succ(i)], FData[i], ( FCount - Succ(i) ) * SizeOf(Pointer));
  174. Dec(FCount);
  175. FData[FCount] := NIL;
  176. End; {Delete}
  177. Function TListExt.Find(P : Pointer; Compare : TListSortCompare) : Integer;
  178. var nResult : integer;
  179. nLow : integer;
  180. nHigh : integer;
  181. nCompare : integer;
  182. nCheckPos : integer;
  183. Begin
  184. Result := -1;
  185. IF Not Assigned(P) Or (FCount < 1) Then
  186. Exit;
  187. IF not Sorted Then
  188. Sort(Compare);
  189. nLow := 0;
  190. nHigh := Count - 1;
  191. nResult := - 1;
  192. { Perform a binary search:}
  193. while (nResult = -1) and (nLow <= nHigh) do
  194. begin
  195. nCheckPos := (nLow + nHigh) div 2;
  196. nCompare := Compare(P, FData[nCheckPos]);
  197. if (nCompare = fLess) Then nHigh := nCheckPos - 1 { less than }
  198. else if (nCompare = fGreater) then nLow := nCheckPos + 1 { greater than }
  199. else nResult := nCheckPos; { equal to }
  200. end;
  201. Result := nResult;
  202. End; {Find}
  203. Function TListExt.FindSequential(P : Pointer; Compare : TListSortCompare) : Integer;
  204. Var i : Integer;
  205. Begin
  206. Result := -1;
  207. IF Not Assigned(P) Then
  208. Exit;
  209. IF Sorted Then
  210. Result := Find(P, Compare)
  211. Else
  212. Begin
  213. For i := 0 To Pred(FCount) Do
  214. Begin
  215. IF Compare(P, FData[i]) = 0 Then
  216. Begin
  217. Result := i;
  218. Exit;
  219. End;
  220. End;
  221. End;
  222. End; {FindSequential}
  223. Procedure TListExt.Sort(Compare : TListSortCompare);
  224. PROCEDURE quicksort(VAR a: Array of Pointer; LO,HI: IntType);
  225. PROCEDURE sort(L,R: IntType);
  226. VAR i,j : IntType;
  227. x,y : Pointer;
  228. BEGIN
  229. i := L;
  230. j := R;
  231. x := a[(L+R) DIV 2];
  232. REPEAT
  233. WHILE Compare(a[i], x) = fLess DO
  234. i := i + 1;
  235. WHILE Compare(x, a[j]) = FLess DO
  236. j := j - 1;
  237. IF i <= j THEN
  238. BEGIN
  239. y:=a[i];
  240. a[i]:=a[j];
  241. a[j]:=y;
  242. i:=i+1;
  243. j:=j-1;
  244. END;
  245. UNTIL i>j;
  246. IF L<j THEN sort(L,j);
  247. IF i<R THEN sort(i,R);
  248. END; (* Sort *)
  249. BEGIN
  250. sort(LO,HI);
  251. END; (* QuickSort *)
  252. Begin
  253. IF (Self.FCount > 1) And Not Sorted Then
  254. QuickSort(Self.FData, 0, Pred(Self.FCount));
  255. FSorted := TRUE;
  256. End; {Sort}
  257. end.