2
0

lists.inc 23 KB

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