lists.inc 23 KB

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