lists.inc 22 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025
  1. {
  2. This file is part of the Free Pascal Run Time Library (rtl)
  3. Copyright (c) 1999-2005 by the Free Pascal development team
  4. See the file COPYING.FPC, included in this distribution,
  5. for details about the copyright.
  6. This program is distributed in the hope that it will be useful,
  7. but WITHOUT ANY WARRANTY; without even the implied warranty of
  8. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  9. **********************************************************************}
  10. {$if defined(VER2_0) or not defined(FPC_TESTGENERICS)}
  11. {****************************************************************************}
  12. {* TFPListEnumerator *}
  13. {****************************************************************************}
  14. constructor TFPListEnumerator.Create(AList: TFPList);
  15. begin
  16. inherited Create;
  17. FList := AList;
  18. FPosition := -1;
  19. end;
  20. function TFPListEnumerator.GetCurrent: Pointer;
  21. begin
  22. Result := FList[FPosition];
  23. end;
  24. function TFPListEnumerator.MoveNext: Boolean;
  25. begin
  26. Inc(FPosition);
  27. Result := FPosition < FList.Count;
  28. end;
  29. {****************************************************************************}
  30. {* TFPList *}
  31. {****************************************************************************}
  32. Const
  33. // Ratio of Pointer and Word Size.
  34. WordRatio = SizeOf(Pointer) Div SizeOf(Word);
  35. procedure TFPList.RaiseIndexError(Index : Integer);
  36. begin
  37. Error(SListIndexError, Index);
  38. end;
  39. function TFPList.Get(Index: Integer): Pointer;
  40. begin
  41. If (Index < 0) or (Index >= FCount) then
  42. RaiseIndexError(Index);
  43. Result:=FList^[Index];
  44. end;
  45. procedure TFPList.Put(Index: Integer; Item: Pointer);
  46. begin
  47. if (Index < 0) or (Index >= FCount) then
  48. RaiseIndexError(Index);
  49. Flist^[Index] := Item;
  50. end;
  51. function TFPList.Extract(Item: Pointer): Pointer;
  52. var
  53. i : Integer;
  54. begin
  55. i := IndexOf(item);
  56. if i >= 0 then
  57. begin
  58. Result := item;
  59. Delete(i);
  60. end
  61. else
  62. result := nil;
  63. end;
  64. procedure TFPList.SetCapacity(NewCapacity: Integer);
  65. begin
  66. If (NewCapacity < FCount) or (NewCapacity > MaxListSize) then
  67. Error (SListCapacityError, NewCapacity);
  68. if NewCapacity = FCapacity then
  69. exit;
  70. ReallocMem(FList, SizeOf(Pointer)*NewCapacity);
  71. FCapacity := NewCapacity;
  72. end;
  73. procedure TFPList.SetCount(NewCount: Integer);
  74. begin
  75. if (NewCount < 0) or (NewCount > MaxListSize)then
  76. Error(SListCountError, NewCount);
  77. If NewCount > FCount then
  78. begin
  79. If NewCount > FCapacity then
  80. SetCapacity(NewCount);
  81. If FCount < NewCount then
  82. FillWord(Flist^[FCount], (NewCount-FCount) * WordRatio, 0);
  83. end;
  84. FCount := Newcount;
  85. end;
  86. destructor TFPList.Destroy;
  87. begin
  88. Self.Clear;
  89. inherited Destroy;
  90. end;
  91. Procedure TFPList.AddList(AList : TFPList);
  92. Var
  93. I : Integer;
  94. begin
  95. If (Capacity<Count+AList.Count) then
  96. Capacity:=Count+AList.Count;
  97. For I:=0 to AList.Count-1 do
  98. Add(AList[i]);
  99. end;
  100. function TFPList.Add(Item: Pointer): Integer;
  101. begin
  102. if FCount = FCapacity then
  103. Self.Expand;
  104. FList^[FCount] := Item;
  105. Result := FCount;
  106. FCount := FCount + 1;
  107. end;
  108. procedure TFPList.Clear;
  109. begin
  110. if Assigned(FList) then
  111. begin
  112. SetCount(0);
  113. SetCapacity(0);
  114. FList := nil;
  115. end;
  116. end;
  117. procedure TFPList.Delete(Index: Integer);
  118. begin
  119. If (Index<0) or (Index>=FCount) then
  120. Error (SListIndexError, Index);
  121. FCount := FCount-1;
  122. System.Move (FList^[Index+1], FList^[Index], (FCount - Index) * SizeOf(Pointer));
  123. // Shrink the list if appropriate
  124. if (FCapacity > 256) and (FCount < FCapacity shr 2) then
  125. begin
  126. FCapacity := FCapacity shr 1;
  127. ReallocMem(FList, SizeOf(Pointer) * FCapacity);
  128. end;
  129. end;
  130. class procedure TFPList.Error(const Msg: string; Data: PtrInt);
  131. begin
  132. Raise EListError.CreateFmt(Msg,[Data]) at get_caller_addr(get_frame), get_caller_frame(get_frame);
  133. end;
  134. procedure TFPList.Exchange(Index1, Index2: Integer);
  135. var
  136. Temp : Pointer;
  137. begin
  138. If ((Index1 >= FCount) or (Index1 < 0)) then
  139. Error(SListIndexError, Index1);
  140. If ((Index2 >= FCount) or (Index2 < 0)) then
  141. Error(SListIndexError, Index2);
  142. Temp := FList^[Index1];
  143. FList^[Index1] := FList^[Index2];
  144. FList^[Index2] := Temp;
  145. end;
  146. function TFPList.Expand: TFPList;
  147. var
  148. IncSize : Longint;
  149. begin
  150. if FCount < FCapacity then exit(self);
  151. if FCapacity > 128*1024*1024 then IncSize := 16*1024*1024
  152. else if FCapacity > 8*1024*1024 then IncSize := FCapacity shr 3
  153. else if FCapacity > 128 then IncSize := FCapacity shr 2
  154. else if FCapacity > 8 then IncSize := 16
  155. else IncSize := 4;
  156. SetCapacity(FCapacity + IncSize);
  157. Result := Self;
  158. end;
  159. function TFPList.First: Pointer;
  160. begin
  161. If FCount = 0 then
  162. Result := Nil
  163. else
  164. Result := Items[0];
  165. end;
  166. function TFPList.GetEnumerator: TFPListEnumerator;
  167. begin
  168. Result := TFPListEnumerator.Create(Self);
  169. end;
  170. function TFPList.IndexOf(Item: Pointer): Integer;
  171. Var
  172. C : Integer;
  173. begin
  174. Result:=0;
  175. C:=Count;
  176. while (Result<C) and (Flist^[Result]<>Item) do
  177. Inc(Result);
  178. If Result>=C then
  179. Result:=-1;
  180. end;
  181. function TFPList.IndexOfItem(Item: Pointer; Direction: TDirection): Integer;
  182. begin
  183. if Direction=fromBeginning then
  184. Result:=IndexOf(Item)
  185. else
  186. begin
  187. Result:=Count-1;
  188. while (Result >=0) and (Flist^[Result]<>Item) do
  189. Result:=Result - 1;
  190. end;
  191. end;
  192. procedure TFPList.Insert(Index: Integer; Item: Pointer);
  193. begin
  194. if (Index < 0) or (Index > FCount )then
  195. Error(SlistIndexError, Index);
  196. iF FCount = FCapacity then Self.Expand;
  197. if Index<FCount then
  198. System.Move(Flist^[Index], Flist^[Index+1], (FCount - Index) * SizeOf(Pointer));
  199. FList^[Index] := Item;
  200. FCount := FCount + 1;
  201. end;
  202. function TFPList.Last: Pointer;
  203. begin
  204. { Wouldn't it be better to return nil if the count is zero ?}
  205. If FCount = 0 then
  206. Result := nil
  207. else
  208. Result := Items[FCount - 1];
  209. end;
  210. procedure TFPList.Move(CurIndex, NewIndex: Integer);
  211. var
  212. Temp : Pointer;
  213. begin
  214. if ((CurIndex < 0) or (CurIndex > Count - 1)) then
  215. Error(SListIndexError, CurIndex);
  216. if ((NewIndex < 0) or (NewIndex > Count -1)) then
  217. Error(SlistIndexError, NewIndex);
  218. Temp := FList^[CurIndex];
  219. if NewIndex > CurIndex then
  220. System.Move(FList^[CurIndex+1], FList^[CurIndex], (NewIndex - CurIndex) * SizeOf(Pointer))
  221. else
  222. System.Move(FList^[NewIndex], FList^[NewIndex+1], (CurIndex - NewIndex) * SizeOf(Pointer));
  223. FList^[NewIndex] := Temp;
  224. end;
  225. function TFPList.Remove(Item: Pointer): Integer;
  226. begin
  227. Result := IndexOf(Item);
  228. If Result <> -1 then
  229. Self.Delete(Result);
  230. end;
  231. procedure TFPList.Pack;
  232. var
  233. NewCount,
  234. i : integer;
  235. pdest,
  236. psrc : PPointer;
  237. begin
  238. NewCount:=0;
  239. psrc:=@FList^[0];
  240. pdest:=psrc;
  241. For I:=0 To FCount-1 Do
  242. begin
  243. if assigned(psrc^) then
  244. begin
  245. pdest^:=psrc^;
  246. inc(pdest);
  247. inc(NewCount);
  248. end;
  249. inc(psrc);
  250. end;
  251. FCount:=NewCount;
  252. end;
  253. // Needed by Sort method.
  254. Procedure QuickSort(FList: PPointerList; L, R : Longint;
  255. Compare: TListSortCompare);
  256. var
  257. I, J : Longint;
  258. P, Q : Pointer;
  259. begin
  260. repeat
  261. I := L;
  262. J := R;
  263. P := FList^[ (L + R) div 2 ];
  264. repeat
  265. while Compare(P, FList^[i]) > 0 do
  266. I := I + 1;
  267. while Compare(P, FList^[J]) < 0 do
  268. J := J - 1;
  269. If I <= J then
  270. begin
  271. Q := FList^[I];
  272. Flist^[I] := FList^[J];
  273. FList^[J] := Q;
  274. I := I + 1;
  275. J := J - 1;
  276. end;
  277. until I > J;
  278. // sort the smaller range recursively
  279. // sort the bigger range via the loop
  280. // Reasons: memory usage is O(log(n)) instead of O(n) and loop is faster than recursion
  281. if J - L < R - I then
  282. begin
  283. if L < J then
  284. QuickSort(FList, L, J, Compare);
  285. L := I;
  286. end
  287. else
  288. begin
  289. if I < R then
  290. QuickSort(FList, I, R, Compare);
  291. R := J;
  292. end;
  293. until L >= R;
  294. end;
  295. procedure TFPList.Sort(Compare: TListSortCompare);
  296. begin
  297. if Not Assigned(FList) or (FCount < 2) then exit;
  298. QuickSort(Flist, 0, FCount-1, Compare);
  299. end;
  300. procedure TFPList.ForEachCall(proc2call:TListCallback;arg:pointer);
  301. var
  302. i : integer;
  303. p : pointer;
  304. begin
  305. For I:=0 To Count-1 Do
  306. begin
  307. p:=FList^[i];
  308. if assigned(p) then
  309. proc2call(p,arg);
  310. end;
  311. end;
  312. procedure TFPList.ForEachCall(proc2call:TListStaticCallback;arg:pointer);
  313. var
  314. i : integer;
  315. p : pointer;
  316. begin
  317. For I:=0 To Count-1 Do
  318. begin
  319. p:=FList^[i];
  320. if assigned(p) then
  321. proc2call(p,arg);
  322. end;
  323. end;
  324. procedure TFPList.CopyMove (aList : TFPList);
  325. var r : integer;
  326. begin
  327. Clear;
  328. for r := 0 to aList.count-1 do
  329. Add (aList[r]);
  330. end;
  331. procedure TFPList.MergeMove (aList : TFPList);
  332. var r : integer;
  333. begin
  334. For r := 0 to aList.count-1 do
  335. if self.indexof(aList[r]) < 0 then
  336. self.Add (aList[r]);
  337. end;
  338. procedure TFPList.DoCopy(ListA, ListB : TFPList);
  339. begin
  340. if assigned (ListB) then
  341. CopyMove (ListB)
  342. else
  343. CopyMove (ListA);
  344. end;
  345. procedure TFPList.DoDestUnique(ListA, ListB : TFPList);
  346. procedure MoveElements (src, dest : TFPList);
  347. var r : integer;
  348. begin
  349. self.clear;
  350. for r := 0 to src.count-1 do
  351. if dest.indexof(src[r]) < 0 then
  352. self.Add (src[r]);
  353. end;
  354. var dest : TFPList;
  355. begin
  356. if assigned (ListB) then
  357. MoveElements (ListB, ListA)
  358. else
  359. try
  360. dest := TFPList.Create;
  361. dest.CopyMove (self);
  362. MoveElements (ListA, dest)
  363. finally
  364. dest.Free;
  365. end;
  366. end;
  367. procedure TFPList.DoAnd(ListA, ListB : TFPList);
  368. var r : integer;
  369. begin
  370. if assigned (ListB) then
  371. begin
  372. self.clear;
  373. for r := 0 to ListA.count-1 do
  374. if ListB.indexOf (ListA[r]) >= 0 then
  375. self.Add (ListA[r]);
  376. end
  377. else
  378. begin
  379. for r := self.Count-1 downto 0 do
  380. if ListA.indexof (Self[r]) < 0 then
  381. self.delete (r);
  382. end;
  383. end;
  384. procedure TFPList.DoSrcUnique(ListA, ListB : TFPList);
  385. var r : integer;
  386. begin
  387. if assigned (ListB) then
  388. begin
  389. self.Clear;
  390. for r := 0 to ListA.Count-1 do
  391. if ListB.indexof (ListA[r]) < 0 then
  392. self.Add (ListA[r]);
  393. end
  394. else
  395. begin
  396. for r := self.count-1 downto 0 do
  397. if ListA.indexof (self[r]) >= 0 then
  398. self.delete (r);
  399. end;
  400. end;
  401. procedure TFPList.DoOr(ListA, ListB : TFPList);
  402. begin
  403. if assigned (ListB) then
  404. begin
  405. CopyMove (ListA);
  406. MergeMove (ListB);
  407. end
  408. else
  409. MergeMove (ListA);
  410. end;
  411. procedure TFPList.DoXOr(ListA, ListB : TFPList);
  412. var r : integer;
  413. l : TFPList;
  414. begin
  415. if assigned (ListB) then
  416. begin
  417. self.Clear;
  418. for r := 0 to ListA.count-1 do
  419. if ListB.indexof (ListA[r]) < 0 then
  420. self.Add (ListA[r]);
  421. for r := 0 to ListB.count-1 do
  422. if ListA.indexof (ListB[r]) < 0 then
  423. self.Add (ListB[r]);
  424. end
  425. else
  426. try
  427. l := TFPList.Create;
  428. l.CopyMove (Self);
  429. for r := self.count-1 downto 0 do
  430. if listA.indexof (self[r]) >= 0 then
  431. self.delete (r);
  432. for r := 0 to ListA.count-1 do
  433. if l.indexof (ListA[r]) < 0 then
  434. self.add (ListA[r]);
  435. finally
  436. l.Free;
  437. end;
  438. end;
  439. procedure TFPList.Assign (ListA: TFPList; AOperator: TListAssignOp=laCopy; ListB: TFPList=nil);
  440. begin
  441. case AOperator of
  442. laCopy : DoCopy (ListA, ListB); // replace dest with src
  443. laSrcUnique : DoSrcUnique (ListA, ListB); // replace dest with src that are not in dest
  444. laAnd : DoAnd (ListA, ListB); // remove from dest that are not in src
  445. laDestUnique : DoDestUnique (ListA, ListB); // remove from dest that are in src
  446. laOr : DoOr (ListA, ListB); // add to dest from src and not in dest
  447. laXOr : DoXOr (ListA, ListB); // add to dest from src and not in dest, remove from dest that are in src
  448. end;
  449. end;
  450. {$else}
  451. { generics based implementation of TFPList follows }
  452. procedure TFPList.Assign(Source: TFPList);
  453. begin
  454. inherited Assign(Source);
  455. end;
  456. type
  457. TFPPtrListSortCompare = function(const Item1, Item2: Pointer): Integer;
  458. procedure TFPList.Sort(Compare: TListSortCompare);
  459. begin
  460. inherited Sort(TFPPtrListSortCompare(Compare));
  461. end;
  462. procedure TFPList.ForEachCall(Proc2call: TListCallback; Arg: Pointer);
  463. var
  464. I: integer;
  465. begin
  466. for I:=0 to Count-1 do
  467. proc2call(InternalItems[I],arg);
  468. end;
  469. procedure TFPList.ForEachCall(Proc2call: TListStaticCallback; Arg: Pointer);
  470. var
  471. I: integer;
  472. begin
  473. for I:=0 to Count-1 do
  474. Proc2call(InternalItems[I], Arg);
  475. end;
  476. {$endif}
  477. {****************************************************************************}
  478. {* TListEnumerator *}
  479. {****************************************************************************}
  480. constructor TListEnumerator.Create(AList: TList);
  481. begin
  482. inherited Create;
  483. FList := AList;
  484. FPosition := -1;
  485. end;
  486. function TListEnumerator.GetCurrent: Pointer;
  487. begin
  488. Result := FList[FPosition];
  489. end;
  490. function TListEnumerator.MoveNext: Boolean;
  491. begin
  492. Inc(FPosition);
  493. Result := FPosition < FList.Count;
  494. end;
  495. {****************************************************************************}
  496. {* TList *}
  497. {****************************************************************************}
  498. { TList = class(TObject)
  499. private
  500. FList: TFPList;
  501. }
  502. function TList.Get(Index: Integer): Pointer;
  503. begin
  504. Result := FList.Get(Index);
  505. end;
  506. procedure TList.Grow;
  507. begin
  508. // Only for compatibility with Delphi. Not needed.
  509. end;
  510. procedure TList.Put(Index: Integer; Item: Pointer);
  511. var p : pointer;
  512. begin
  513. p := get(Index);
  514. FList.Put(Index, Item);
  515. if assigned (p) then
  516. Notify (p, lnDeleted);
  517. if assigned (Item) then
  518. Notify (Item, lnAdded);
  519. end;
  520. function TList.Extract(item: Pointer): Pointer;
  521. var c : integer;
  522. begin
  523. c := FList.Count;
  524. Result := FList.Extract(item);
  525. if c <> FList.Count then
  526. Notify (Result, lnExtracted);
  527. end;
  528. procedure TList.Notify(Ptr: Pointer; Action: TListNotification);
  529. begin
  530. if Assigned(FObservers) then
  531. Case ACtion of
  532. lnAdded : FPONotifyObservers(Self,ooAddItem,Ptr);
  533. lnExtracted : FPONotifyObservers(Self,ooDeleteItem,Ptr);
  534. lnDeleted : FPONotifyObservers(Self,ooDeleteItem,Ptr);
  535. end;
  536. end;
  537. function TList.GetCapacity: integer;
  538. begin
  539. Result := FList.Capacity;
  540. end;
  541. procedure TList.SetCapacity(NewCapacity: Integer);
  542. begin
  543. FList.SetCapacity(NewCapacity);
  544. end;
  545. function TList.GetCount: Integer;
  546. begin
  547. Result := FList.Count;
  548. end;
  549. procedure TList.SetCount(NewCount: Integer);
  550. begin
  551. if NewCount < FList.Count then
  552. while FList.Count > NewCount do
  553. Delete(FList.Count - 1)
  554. else
  555. FList.SetCount(NewCount);
  556. end;
  557. constructor TList.Create;
  558. begin
  559. inherited Create;
  560. FList := TFPList.Create;
  561. end;
  562. destructor TList.Destroy;
  563. begin
  564. if Assigned(Flist) then
  565. Clear;
  566. If Assigned(FObservers) then
  567. begin
  568. FPONotifyObservers(Self,ooFree,Nil);
  569. FreeAndNil(FObservers);
  570. end;
  571. FreeAndNil(FList);
  572. inherited Destroy;
  573. end;
  574. procedure TList.FPOAttachObserver(AObserver: TObject);
  575. Var
  576. I : IFPObserver;
  577. begin
  578. If Not AObserver.GetInterface(SGUIDObserver,I) then
  579. Raise EObserver.CreateFmt(SErrNotObserver,[AObserver.ClassName]);
  580. If not Assigned(FObservers) then
  581. FObservers:=TFPList.Create;
  582. FObservers.Add(I);
  583. end;
  584. procedure TList.FPODetachObserver(AObserver: TObject);
  585. Var
  586. I : IFPObserver;
  587. begin
  588. If Not AObserver.GetInterface(SGUIDObserver,I) then
  589. Raise EObserver.CreateFmt(SErrNotObserver,[AObserver.ClassName]);
  590. If Assigned(FObservers) then
  591. begin
  592. FObservers.Remove(I);
  593. If (FObservers.Count=0) then
  594. FreeAndNil(FObservers);
  595. end;
  596. end;
  597. procedure TList.FPONotifyObservers(ASender: TObject;
  598. AOperation: TFPObservedOperation; Data : Pointer);
  599. Var
  600. I : Integer;
  601. Obs : IFPObserver;
  602. begin
  603. If Assigned(FObservers) then
  604. For I:=FObservers.Count-1 downto 0 do
  605. begin
  606. Obs:=IFPObserver(FObservers[i]);
  607. Obs.FPOObservedChanged(ASender,AOperation,Data);
  608. end;
  609. end;
  610. function TList.Add(Item: Pointer): Integer;
  611. begin
  612. Result := FList.Add(Item);
  613. if Item <> nil then
  614. Notify(Item, lnAdded);
  615. end;
  616. Procedure TList.AddList(AList : TList);
  617. var
  618. I: Integer;
  619. begin
  620. { this only does FList.AddList(AList.FList), avoiding notifications }
  621. FList.AddList(AList.FList);
  622. { make lnAdded notifications }
  623. for I := 0 to AList.Count - 1 do
  624. if AList[I] <> nil then
  625. Notify(AList[I], lnAdded);
  626. end;
  627. procedure TList.Clear;
  628. begin
  629. While (FList.Count>0) do
  630. Delete(Count-1);
  631. end;
  632. procedure TList.Delete(Index: Integer);
  633. var P : pointer;
  634. begin
  635. P:=FList.Get(Index);
  636. FList.Delete(Index);
  637. if assigned(p) then
  638. Notify(p, lnDeleted);
  639. end;
  640. class procedure TList.Error(const Msg: string; Data: PtrInt);
  641. begin
  642. Raise EListError.CreateFmt(Msg,[Data]) at get_caller_addr(get_frame), get_caller_frame(get_frame);
  643. end;
  644. procedure TList.Exchange(Index1, Index2: Integer);
  645. begin
  646. FList.Exchange(Index1, Index2);
  647. FPONotifyObservers(Self,ooChange,Nil);
  648. end;
  649. function TList.Expand: TList;
  650. begin
  651. FList.Expand;
  652. Result:=Self;
  653. end;
  654. function TList.First: Pointer;
  655. begin
  656. Result := FList.First;
  657. end;
  658. function TList.GetEnumerator: TListEnumerator;
  659. begin
  660. Result := TListEnumerator.Create(Self);
  661. end;
  662. function TList.IndexOf(Item: Pointer): Integer;
  663. begin
  664. Result := FList.IndexOf(Item);
  665. end;
  666. procedure TList.Insert(Index: Integer; Item: Pointer);
  667. begin
  668. FList.Insert(Index, Item);
  669. if Item <> nil then
  670. Notify(Item,lnAdded);
  671. end;
  672. function TList.Last: Pointer;
  673. begin
  674. Result := FList.Last;
  675. end;
  676. procedure TList.Move(CurIndex, NewIndex: Integer);
  677. begin
  678. FList.Move(CurIndex, NewIndex);
  679. end;
  680. function TList.Remove(Item: Pointer): Integer;
  681. begin
  682. Result := IndexOf(Item);
  683. if Result <> -1 then
  684. Self.Delete(Result);
  685. end;
  686. procedure TList.Pack;
  687. begin
  688. FList.Pack;
  689. end;
  690. procedure TList.Sort(Compare: TListSortCompare);
  691. begin
  692. FList.Sort(Compare);
  693. end;
  694. procedure TList.CopyMove (aList : TList);
  695. var r : integer;
  696. begin
  697. Clear;
  698. for r := 0 to aList.count-1 do
  699. Add (aList[r]);
  700. end;
  701. procedure TList.MergeMove (aList : TList);
  702. var r : integer;
  703. begin
  704. For r := 0 to aList.count-1 do
  705. if self.indexof(aList[r]) < 0 then
  706. self.Add (aList[r]);
  707. end;
  708. procedure TList.DoCopy(ListA, ListB : TList);
  709. begin
  710. if assigned (ListB) then
  711. CopyMove (ListB)
  712. else
  713. CopyMove (ListA);
  714. end;
  715. procedure TList.DoDestUnique(ListA, ListB : TList);
  716. procedure MoveElements (src, dest : TList);
  717. var r : integer;
  718. begin
  719. self.clear;
  720. for r := 0 to src.count-1 do
  721. if dest.indexof(src[r]) < 0 then
  722. self.Add (src[r]);
  723. end;
  724. var dest : TList;
  725. begin
  726. if assigned (ListB) then
  727. MoveElements (ListB, ListA)
  728. else
  729. try
  730. dest := TList.Create;
  731. dest.CopyMove (self);
  732. MoveElements (ListA, dest)
  733. finally
  734. dest.Free;
  735. end;
  736. end;
  737. procedure TList.DoAnd(ListA, ListB : TList);
  738. var r : integer;
  739. begin
  740. if assigned (ListB) then
  741. begin
  742. self.clear;
  743. for r := 0 to ListA.count-1 do
  744. if ListB.indexOf (ListA[r]) >= 0 then
  745. self.Add (ListA[r]);
  746. end
  747. else
  748. begin
  749. for r := self.Count-1 downto 0 do
  750. if ListA.indexof (Self[r]) < 0 then
  751. self.delete (r);
  752. end;
  753. end;
  754. procedure TList.DoSrcUnique(ListA, ListB : TList);
  755. var r : integer;
  756. begin
  757. if assigned (ListB) then
  758. begin
  759. self.Clear;
  760. for r := 0 to ListA.Count-1 do
  761. if ListB.indexof (ListA[r]) < 0 then
  762. self.Add (ListA[r]);
  763. end
  764. else
  765. begin
  766. for r := self.count-1 downto 0 do
  767. if ListA.indexof (self[r]) >= 0 then
  768. self.delete (r);
  769. end;
  770. end;
  771. procedure TList.DoOr(ListA, ListB : TList);
  772. begin
  773. if assigned (ListB) then
  774. begin
  775. CopyMove (ListA);
  776. MergeMove (ListB);
  777. end
  778. else
  779. MergeMove (ListA);
  780. end;
  781. procedure TList.DoXOr(ListA, ListB : TList);
  782. var r : integer;
  783. l : TList;
  784. begin
  785. if assigned (ListB) then
  786. begin
  787. self.Clear;
  788. for r := 0 to ListA.count-1 do
  789. if ListB.indexof (ListA[r]) < 0 then
  790. self.Add (ListA[r]);
  791. for r := 0 to ListB.count-1 do
  792. if ListA.indexof (ListB[r]) < 0 then
  793. self.Add (ListB[r]);
  794. end
  795. else
  796. try
  797. l := TList.Create;
  798. l.CopyMove (Self);
  799. for r := self.count-1 downto 0 do
  800. if listA.indexof (self[r]) >= 0 then
  801. self.delete (r);
  802. for r := 0 to ListA.count-1 do
  803. if l.indexof (ListA[r]) < 0 then
  804. self.add (ListA[r]);
  805. finally
  806. l.Free;
  807. end;
  808. end;
  809. procedure TList.Assign (ListA: TList; AOperator: TListAssignOp=laCopy; ListB: TList=nil);
  810. begin
  811. case AOperator of
  812. laCopy : DoCopy (ListA, ListB); // replace dest with src
  813. laSrcUnique : DoSrcUnique (ListA, ListB); // replace dest with src that are not in dest
  814. laAnd : DoAnd (ListA, ListB); // remove from dest that are not in src
  815. laDestUnique : DoDestUnique (ListA, ListB); // remove from dest that are in src
  816. laOr : DoOr (ListA, ListB); // add to dest from src and not in dest
  817. laXOr : DoXOr (ListA, ListB); // add to dest from src and not in dest, remove from dest that are in src
  818. end;
  819. end;
  820. function TList.GetList: PPointerList;
  821. begin
  822. Result := PPointerList(FList.List);
  823. end;
  824. {****************************************************************************}
  825. {* TThreadList *}
  826. {****************************************************************************}
  827. constructor TThreadList.Create;
  828. begin
  829. inherited Create;
  830. FDuplicates:=dupIgnore;
  831. InitCriticalSection(FLock);
  832. FList:=TList.Create;
  833. end;
  834. destructor TThreadList.Destroy;
  835. begin
  836. LockList;
  837. try
  838. FList.Free;
  839. inherited Destroy;
  840. finally
  841. UnlockList;
  842. DoneCriticalSection(FLock);
  843. end;
  844. end;
  845. procedure TThreadList.Add(Item: Pointer);
  846. begin
  847. LockList;
  848. try
  849. if (Duplicates=dupAccept) or
  850. // make sure it's not already in the list
  851. (FList.IndexOf(Item)=-1) then
  852. FList.Add(Item)
  853. else if (Duplicates=dupError) then
  854. FList.Error(SDuplicateItem,PtrUInt(Item));
  855. finally
  856. UnlockList;
  857. end;
  858. end;
  859. procedure TThreadList.Clear;
  860. begin
  861. Locklist;
  862. try
  863. FList.Clear;
  864. finally
  865. UnLockList;
  866. end;
  867. end;
  868. function TThreadList.LockList: TList;
  869. begin
  870. Result:=FList;
  871. System.EnterCriticalSection(FLock);
  872. end;
  873. procedure TThreadList.Remove(Item: Pointer);
  874. begin
  875. LockList;
  876. try
  877. FList.Remove(Item);
  878. finally
  879. UnlockList;
  880. end;
  881. end;
  882. procedure TThreadList.UnlockList;
  883. begin
  884. System.LeaveCriticalSection(FLock);
  885. end;