lists.inc 23 KB

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