lists.inc 23 KB

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