lists.inc 22 KB

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