lists.inc 22 KB

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