lists.inc 23 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024
  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 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; // Already set by SetCapacity
  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(AList.FList);
  463. end;
  464. {****************************************************************************}
  465. {* TList *}
  466. {****************************************************************************}
  467. { TList = class(TObject)
  468. private
  469. FList: TFPList;
  470. }
  471. function TList.Get(Index: Integer): Pointer;
  472. begin
  473. Result := FList.Get(Index);
  474. end;
  475. procedure TList.Grow;
  476. begin
  477. // Only for compatibility with Delphi. Not needed.
  478. end;
  479. procedure TList.Put(Index: Integer; Item: Pointer);
  480. var p : pointer;
  481. begin
  482. p := get(Index);
  483. FList.Put(Index, Item);
  484. if assigned (p) then
  485. Notify (p, lnDeleted);
  486. if assigned (Item) then
  487. Notify (Item, lnAdded);
  488. end;
  489. function TList.Extract(item: Pointer): Pointer;
  490. var c : integer;
  491. begin
  492. c := FList.Count;
  493. Result := FList.Extract(item);
  494. if c <> FList.Count then
  495. Notify (Result, lnExtracted);
  496. end;
  497. procedure TList.Notify(Ptr: Pointer; Action: TListNotification);
  498. begin
  499. if Assigned(FObservers) then
  500. Case ACtion of
  501. lnAdded : FPONotifyObservers(Self,ooAddItem,Ptr);
  502. lnExtracted : FPONotifyObservers(Self,ooDeleteItem,Ptr);
  503. lnDeleted : FPONotifyObservers(Self,ooDeleteItem,Ptr);
  504. end;
  505. end;
  506. function TList.GetCapacity: integer;
  507. begin
  508. Result := FList.Capacity;
  509. end;
  510. procedure TList.SetCapacity(NewCapacity: Integer);
  511. begin
  512. FList.SetCapacity(NewCapacity);
  513. end;
  514. function TList.GetCount: Integer;
  515. begin
  516. Result := FList.Count;
  517. end;
  518. procedure TList.SetCount(NewCount: Integer);
  519. begin
  520. if NewCount < FList.Count then
  521. while FList.Count > NewCount do
  522. Delete(FList.Count - 1)
  523. else
  524. FList.SetCount(NewCount);
  525. end;
  526. constructor TList.Create;
  527. begin
  528. inherited Create;
  529. FList := TFPList.Create;
  530. end;
  531. destructor TList.Destroy;
  532. begin
  533. if Assigned(Flist) then
  534. Clear;
  535. If Assigned(FObservers) then
  536. begin
  537. FPONotifyObservers(Self,ooFree,Nil);
  538. FreeAndNil(FObservers);
  539. end;
  540. FreeAndNil(FList);
  541. inherited Destroy;
  542. end;
  543. procedure TList.FPOAttachObserver(AObserver: TObject);
  544. Var
  545. I : IFPObserver;
  546. begin
  547. If Not AObserver.GetInterface(SGUIDObserver,I) then
  548. Raise EObserver.CreateFmt(SErrNotObserver,[AObserver.ClassName]);
  549. If not Assigned(FObservers) then
  550. FObservers:=TFPList.Create;
  551. FObservers.Add(I);
  552. end;
  553. procedure TList.FPODetachObserver(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 Assigned(FObservers) then
  560. begin
  561. FObservers.Remove(I);
  562. If (FObservers.Count=0) then
  563. FreeAndNil(FObservers);
  564. end;
  565. end;
  566. procedure TList.FPONotifyObservers(ASender: TObject;
  567. AOperation: TFPObservedOperation; Data : Pointer);
  568. Var
  569. I : Integer;
  570. Obs : IFPObserver;
  571. begin
  572. If Assigned(FObservers) then
  573. For I:=FObservers.Count-1 downto 0 do
  574. begin
  575. Obs:=IFPObserver(FObservers[i]);
  576. Obs.FPOObservedChanged(ASender,AOperation,Data);
  577. end;
  578. end;
  579. function TList.Add(Item: Pointer): Integer;
  580. begin
  581. Result := FList.Add(Item);
  582. if Item <> nil then
  583. Notify(Item, lnAdded);
  584. end;
  585. Procedure TList.AddList(AList : TList);
  586. var
  587. I: Integer;
  588. begin
  589. { this only does FList.AddList(AList.FList), avoiding notifications }
  590. FList.AddList(AList.FList);
  591. { make lnAdded notifications }
  592. for I := 0 to AList.Count - 1 do
  593. if AList[I] <> nil then
  594. Notify(AList[I], lnAdded);
  595. end;
  596. procedure TList.Clear;
  597. begin
  598. While (FList.Count>0) do
  599. Delete(Count-1);
  600. end;
  601. procedure TList.Delete(Index: Integer);
  602. var P : pointer;
  603. begin
  604. P:=FList.Get(Index);
  605. FList.Delete(Index);
  606. if assigned(p) then
  607. Notify(p, lnDeleted);
  608. end;
  609. class procedure TList.Error(const Msg: string; Data: PtrInt);
  610. begin
  611. Raise EListError.CreateFmt(Msg,[Data]) at get_caller_addr(get_frame), get_caller_frame(get_frame);
  612. end;
  613. procedure TList.Exchange(Index1, Index2: Integer);
  614. begin
  615. FList.Exchange(Index1, Index2);
  616. FPONotifyObservers(Self,ooChange,Nil);
  617. end;
  618. function TList.Expand: TList;
  619. begin
  620. FList.Expand;
  621. Result:=Self;
  622. end;
  623. function TList.First: Pointer;
  624. begin
  625. Result := FList.First;
  626. end;
  627. function TList.GetEnumerator: TListEnumerator;
  628. begin
  629. Result := TListEnumerator.Create(Self);
  630. end;
  631. function TList.IndexOf(Item: Pointer): Integer;
  632. begin
  633. Result := FList.IndexOf(Item);
  634. end;
  635. procedure TList.Insert(Index: Integer; Item: Pointer);
  636. begin
  637. FList.Insert(Index, Item);
  638. if Item <> nil then
  639. Notify(Item,lnAdded);
  640. end;
  641. function TList.Last: Pointer;
  642. begin
  643. Result := FList.Last;
  644. end;
  645. procedure TList.Move(CurIndex, NewIndex: Integer);
  646. begin
  647. FList.Move(CurIndex, NewIndex);
  648. end;
  649. function TList.Remove(Item: Pointer): Integer;
  650. begin
  651. Result := IndexOf(Item);
  652. if Result <> -1 then
  653. Self.Delete(Result);
  654. end;
  655. procedure TList.Pack;
  656. begin
  657. FList.Pack;
  658. end;
  659. procedure TList.Sort(Compare: TListSortCompare);
  660. begin
  661. FList.Sort(Compare);
  662. end;
  663. procedure TList.Sort(Compare: TListSortCompare; SortingAlgorithm: PSortingAlgorithm);
  664. begin
  665. FList.Sort(Compare, SortingAlgorithm);
  666. end;
  667. procedure TList.Sort(Compare: TListSortComparer_Context; Context: Pointer);
  668. begin
  669. FList.Sort(Compare, Context);
  670. end;
  671. procedure TList.Sort(Compare: TListSortComparer_Context; Context: Pointer; SortingAlgorithm: PSortingAlgorithm);
  672. begin
  673. FList.Sort(Compare, Context, SortingAlgorithm);
  674. end;
  675. procedure TList.CopyMove (aList : TList);
  676. var r : integer;
  677. begin
  678. Clear;
  679. for r := 0 to aList.count-1 do
  680. Add (aList[r]);
  681. end;
  682. procedure TList.MergeMove (aList : TList);
  683. var r : integer;
  684. begin
  685. For r := 0 to aList.count-1 do
  686. if self.indexof(aList[r]) < 0 then
  687. self.Add (aList[r]);
  688. end;
  689. procedure TList.DoCopy(ListA, ListB : TList);
  690. begin
  691. if assigned (ListB) then
  692. CopyMove (ListB)
  693. else
  694. CopyMove (ListA);
  695. end;
  696. procedure TList.DoDestUnique(ListA, ListB : TList);
  697. procedure MoveElements (src, dest : TList);
  698. var r : integer;
  699. begin
  700. self.clear;
  701. for r := 0 to src.count-1 do
  702. if dest.indexof(src[r]) < 0 then
  703. self.Add (src[r]);
  704. end;
  705. var dest : TList;
  706. begin
  707. if assigned (ListB) then
  708. MoveElements (ListB, ListA)
  709. else
  710. try
  711. dest := TList.Create;
  712. dest.CopyMove (self);
  713. MoveElements (ListA, dest)
  714. finally
  715. dest.Free;
  716. end;
  717. end;
  718. procedure TList.DoAnd(ListA, ListB : TList);
  719. var r : integer;
  720. begin
  721. if assigned (ListB) then
  722. begin
  723. self.clear;
  724. for r := 0 to ListA.count-1 do
  725. if ListB.indexOf (ListA[r]) >= 0 then
  726. self.Add (ListA[r]);
  727. end
  728. else
  729. begin
  730. for r := self.Count-1 downto 0 do
  731. if ListA.indexof (Self[r]) < 0 then
  732. self.delete (r);
  733. end;
  734. end;
  735. procedure TList.DoSrcUnique(ListA, ListB : TList);
  736. var r : integer;
  737. begin
  738. if assigned (ListB) then
  739. begin
  740. self.Clear;
  741. for r := 0 to ListA.Count-1 do
  742. if ListB.indexof (ListA[r]) < 0 then
  743. self.Add (ListA[r]);
  744. end
  745. else
  746. begin
  747. for r := self.count-1 downto 0 do
  748. if ListA.indexof (self[r]) >= 0 then
  749. self.delete (r);
  750. end;
  751. end;
  752. procedure TList.DoOr(ListA, ListB : TList);
  753. begin
  754. if assigned (ListB) then
  755. begin
  756. CopyMove (ListA);
  757. MergeMove (ListB);
  758. end
  759. else
  760. MergeMove (ListA);
  761. end;
  762. procedure TList.DoXOr(ListA, ListB : TList);
  763. var r : integer;
  764. l : TList;
  765. begin
  766. if assigned (ListB) then
  767. begin
  768. self.Clear;
  769. for r := 0 to ListA.count-1 do
  770. if ListB.indexof (ListA[r]) < 0 then
  771. self.Add (ListA[r]);
  772. for r := 0 to ListB.count-1 do
  773. if ListA.indexof (ListB[r]) < 0 then
  774. self.Add (ListB[r]);
  775. end
  776. else
  777. try
  778. l := TList.Create;
  779. l.CopyMove (Self);
  780. for r := self.count-1 downto 0 do
  781. if listA.indexof (self[r]) >= 0 then
  782. self.delete (r);
  783. for r := 0 to ListA.count-1 do
  784. if l.indexof (ListA[r]) < 0 then
  785. self.add (ListA[r]);
  786. finally
  787. l.Free;
  788. end;
  789. end;
  790. procedure TList.Assign (ListA: TList; AOperator: TListAssignOp=laCopy; ListB: TList=nil);
  791. begin
  792. case AOperator of
  793. laCopy : DoCopy (ListA, ListB); // replace dest with src
  794. laSrcUnique : DoSrcUnique (ListA, ListB); // replace dest with src that are not in dest
  795. laAnd : DoAnd (ListA, ListB); // remove from dest that are not in src
  796. laDestUnique : DoDestUnique (ListA, ListB); // remove from dest that are in src
  797. laOr : DoOr (ListA, ListB); // add to dest from src and not in dest
  798. laXOr : DoXOr (ListA, ListB); // add to dest from src and not in dest, remove from dest that are in src
  799. end;
  800. end;
  801. function TList.GetList: PPointerList;
  802. begin
  803. Result := PPointerList(FList.List);
  804. end;
  805. {****************************************************************************}
  806. {* TThreadList *}
  807. {****************************************************************************}
  808. constructor TThreadList.Create;
  809. begin
  810. inherited Create;
  811. FDuplicates:=dupIgnore;
  812. {$ifdef FPC_HAS_FEATURE_THREADING}
  813. InitCriticalSection(FLock);
  814. {$endif}
  815. FList:=TList.Create;
  816. end;
  817. destructor TThreadList.Destroy;
  818. begin
  819. LockList;
  820. try
  821. FList.Free;
  822. inherited Destroy;
  823. finally
  824. UnlockList;
  825. {$ifdef FPC_HAS_FEATURE_THREADING}
  826. DoneCriticalSection(FLock);
  827. {$endif}
  828. end;
  829. end;
  830. procedure TThreadList.Add(Item: Pointer);
  831. begin
  832. LockList;
  833. try
  834. if (Duplicates=dupAccept) or
  835. // make sure it's not already in the list
  836. (FList.IndexOf(Item)=-1) then
  837. FList.Add(Item)
  838. else if (Duplicates=dupError) then
  839. FList.Error(SDuplicateItem,PtrUInt(Item));
  840. finally
  841. UnlockList;
  842. end;
  843. end;
  844. procedure TThreadList.Clear;
  845. begin
  846. Locklist;
  847. try
  848. FList.Clear;
  849. finally
  850. UnLockList;
  851. end;
  852. end;
  853. function TThreadList.LockList: TList;
  854. begin
  855. Result:=FList;
  856. {$ifdef FPC_HAS_FEATURE_THREADING}
  857. System.EnterCriticalSection(FLock);
  858. {$endif}
  859. end;
  860. procedure TThreadList.Remove(Item: Pointer);
  861. begin
  862. LockList;
  863. try
  864. FList.Remove(Item);
  865. finally
  866. UnlockList;
  867. end;
  868. end;
  869. procedure TThreadList.UnlockList;
  870. begin
  871. {$ifdef FPC_HAS_FEATURE_THREADING}
  872. System.LeaveCriticalSection(FLock);
  873. {$endif}
  874. end;