lists.inc 23 KB

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