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