lists.inc 22 KB

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