fgl.pp 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 2006 by Micha Nelissen
  4. member of the Free Pascal development team
  5. It contains the Free Pascal generics library
  6. See the file COPYING.FPC, included in this distribution,
  7. for details about the copyright.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11. **********************************************************************}
  12. {$mode objfpc}
  13. { be aware, this unit is a prototype and subject to be changed heavily }
  14. unit fgl;
  15. interface
  16. uses
  17. types, sysutils;
  18. const
  19. MaxListSize = Maxint div 16;
  20. type
  21. EListError = class(Exception);
  22. TFPSList = class;
  23. TFPSListCompareFunc = function(Key1, Key2: Pointer): Integer of object;
  24. TFPSList = class(TObject)
  25. protected
  26. FList: PByte;
  27. FCount: Integer;
  28. FCapacity: Integer; { list is one longer than capacity, for temp }
  29. FItemSize: Integer;
  30. procedure CopyItem(Src, Dest: Pointer); virtual;
  31. procedure Deref(Item: Pointer); virtual; overload;
  32. procedure Deref(FromIndex, ToIndex: Integer); overload;
  33. function Get(Index: Integer): Pointer;
  34. procedure InternalExchange(Index1, Index2: Integer);
  35. function InternalGet(Index: Integer): Pointer; {$ifdef CLASSESINLINE} inline; {$endif}
  36. procedure InternalPut(Index: Integer; NewItem: Pointer);
  37. procedure Put(Index: Integer; Item: Pointer);
  38. procedure QuickSort(L, R: Integer; Compare: TFPSListCompareFunc);
  39. procedure SetCapacity(NewCapacity: Integer);
  40. procedure SetCount(NewCount: Integer);
  41. procedure RaiseIndexError(Index : Integer);
  42. property InternalItems[Index: Integer]: Pointer read InternalGet write InternalPut;
  43. public
  44. constructor Create(AItemSize: Integer = sizeof(Pointer));
  45. destructor Destroy; override;
  46. function Add(Item: Pointer): Integer;
  47. procedure Clear;
  48. procedure Delete(Index: Integer);
  49. class procedure Error(const Msg: string; Data: PtrInt);
  50. procedure Exchange(Index1, Index2: Integer);
  51. function Expand: TFPSList;
  52. function Extract(Item: Pointer): Pointer;
  53. function First: Pointer;
  54. function IndexOf(Item: Pointer): Integer;
  55. procedure Insert(Index: Integer; Item: Pointer);
  56. function Insert(Index: Integer): Pointer;
  57. function Last: Pointer;
  58. procedure Move(CurIndex, NewIndex: Integer);
  59. procedure Assign(Obj: TFPSList);
  60. function Remove(Item: Pointer): Integer;
  61. procedure Pack;
  62. procedure Sort(Compare: TFPSListCompareFunc);
  63. property Capacity: Integer read FCapacity write SetCapacity;
  64. property Count: Integer read FCount write SetCount;
  65. property Items[Index: Integer]: Pointer read Get write Put; default;
  66. property ItemSize: Integer read FItemSize;
  67. property List: PByte read FList;
  68. end;
  69. {$ifndef VER2_0}
  70. generic TFPGList<T> = class(TFPSList)
  71. type public
  72. TCompareFunc = function(const Item1, Item2: T): Integer;
  73. PT = ^T;
  74. var protected
  75. FOnCompare: TCompareFunc;
  76. procedure CopyItem(Src, Dest: Pointer); override;
  77. procedure Deref(Item: Pointer); override;
  78. function Get(Index: Integer): T; {$ifdef CLASSESINLINE} inline; {$endif}
  79. function ItemPtrCompare(Item1, Item2: Pointer): Integer;
  80. procedure Put(Index: Integer; const Item: T); {$ifdef CLASSESINLINE} inline; {$endif}
  81. public
  82. constructor Create;
  83. function Add(const Item: T): Integer; {$ifdef CLASSESINLINE} inline; {$endif}
  84. function Extract(const Item: T): T; {$ifdef CLASSESINLINE} inline; {$endif}
  85. function First: T; {$ifdef CLASSESINLINE} inline; {$endif}
  86. function IndexOf(const Item: T): Integer;
  87. procedure Insert(Index: Integer; const Item: T); {$ifdef CLASSESINLINE} inline; {$endif}
  88. function Last: T; {$ifdef CLASSESINLINE} inline; {$endif}
  89. {$warning TODO: fix TFPGList<T>.Assign(TFPGList) to work somehow}
  90. {procedure Assign(Source: TFPGList);}
  91. function Remove(const Item: T): Integer; {$ifdef CLASSESINLINE} inline; {$endif}
  92. procedure Sort(Compare: TCompareFunc);
  93. property Items[Index: Integer]: T read Get write Put; default;
  94. end;
  95. {$endif}
  96. TFPSMap = class(TFPSList)
  97. private
  98. FKeySize: Integer;
  99. FDataSize: Integer;
  100. FDuplicates: TDuplicates;
  101. FSorted: Boolean;
  102. FOnPtrCompare: TFPSListCompareFunc;
  103. procedure SetSorted(Value: Boolean);
  104. protected
  105. function BinaryCompare(Key1, Key2: Pointer): Integer;
  106. procedure CopyKey(Src, Dest: Pointer); virtual;
  107. procedure CopyData(Src, Dest: Pointer); virtual;
  108. function GetKey(Index: Integer): Pointer;
  109. function GetKeyData(AKey: Pointer): Pointer;
  110. function GetData(Index: Integer): Pointer;
  111. procedure InitOnPtrCompare;
  112. function LinearIndexOf(AKey: Pointer): Integer;
  113. procedure PutKey(Index: Integer; AKey: Pointer);
  114. procedure PutKeyData(AKey: Pointer; NewData: Pointer);
  115. procedure PutData(Index: Integer; AData: Pointer);
  116. public
  117. constructor Create(AKeySize: Integer = sizeof(Pointer);
  118. ADataSize: integer = sizeof(Pointer));
  119. function Add(AKey, AData: Pointer): Integer;
  120. function Add(AKey: Pointer): Integer;
  121. function Find(AKey: Pointer; var Index: Integer): Boolean;
  122. function IndexOf(AKey: Pointer): Integer;
  123. function IndexOfData(AData: Pointer): Integer;
  124. function Insert(Index: Integer): Pointer;
  125. procedure Insert(Index: Integer; var AKey, AData: Pointer);
  126. procedure InsertKey(Index: Integer; AKey: Pointer);
  127. procedure InsertKeyData(Index: Integer; AKey, AData: Pointer);
  128. function Remove(AKey: Pointer): Integer;
  129. procedure Sort;
  130. property Duplicates: TDuplicates read FDuplicates write FDuplicates;
  131. property KeySize: Integer read FKeySize;
  132. property DataSize: Integer read FDataSize;
  133. property Keys[Index: Integer]: Pointer read GetKey write PutKey;
  134. property Data[Index: Integer]: Pointer read GetData write PutData;
  135. property KeyData[Key: Pointer]: Pointer read GetKeyData write PutKeyData; default;
  136. property Sorted: Boolean read FSorted write SetSorted;
  137. property OnPtrCompare: TFPSListCompareFunc read FOnPtrCompare write FOnPtrCompare;
  138. end;
  139. {$ifndef VER2_0}
  140. generic TFPGMap<TKey, TData> = class(TFPSMap)
  141. type public
  142. TCompareFunc = function(const Key1, Key2: TKey): Integer;
  143. var protected
  144. FOnCompare: TCompareFunc;
  145. procedure CopyItem(Src, Dest: Pointer); override;
  146. procedure CopyKey(Src, Dest: Pointer); override;
  147. procedure CopyData(Src, Dest: Pointer); override;
  148. procedure Deref(Item: Pointer); override;
  149. function GetKey(Index: Integer): TKey; {$ifdef CLASSESINLINE} inline; {$endif}
  150. function GetKeyData(const AKey: TKey): TData; {$ifdef CLASSESINLINE} inline; {$endif}
  151. function GetData(Index: Integer): TData; {$ifdef CLASSESINLINE} inline; {$endif}
  152. function KeyPtrCompare(Key1, Key2: Pointer): Integer;
  153. procedure PutKey(Index: Integer; const NewKey: TKey); {$ifdef CLASSESINLINE} inline; {$endif}
  154. procedure PutKeyData(const AKey: TKey; const NewData: TData); {$ifdef CLASSESINLINE} inline; {$endif}
  155. procedure PutData(Index: Integer; const NewData: TData); {$ifdef CLASSESINLINE} inline; {$endif}
  156. procedure SetOnCompare(NewCompare: TCompareFunc);
  157. public
  158. constructor Create;
  159. function Add(const AKey: TKey; const AData: TData): Integer; {$ifdef CLASSESINLINE} inline; {$endif}
  160. function Add(const AKey: TKey): Integer; {$ifdef CLASSESINLINE} inline; {$endif}
  161. function Find(const AKey: TKey; var Index: Integer): Boolean; {$ifdef CLASSESINLINE} inline; {$endif}
  162. function IndexOf(const AKey: TKey): Integer; {$ifdef CLASSESINLINE} inline; {$endif}
  163. function IndexOfData(const AData: TData): Integer;
  164. procedure InsertKey(Index: Integer; const AKey: TKey);
  165. procedure InsertKeyData(Index: Integer; const AKey: TKey; const AData: TData);
  166. function Remove(const AKey: TKey): Integer;
  167. property Keys[Index: Integer]: TKey read GetKey write PutKey;
  168. property Data[Index: Integer]: TData read GetData write PutData;
  169. property KeyData[const AKey: TKey]: TData read GetKeyData write PutKeyData; default;
  170. property OnCompare: TCompareFunc read FOnCompare write SetOnCompare;
  171. end;
  172. {$endif}
  173. implementation
  174. uses
  175. rtlconsts;
  176. {****************************************************************************
  177. TFPSList
  178. ****************************************************************************}
  179. constructor TFPSList.Create(AItemSize: integer);
  180. begin
  181. inherited Create;
  182. FItemSize := AItemSize;
  183. end;
  184. destructor TFPSList.Destroy;
  185. begin
  186. Clear;
  187. inherited Destroy;
  188. end;
  189. procedure TFPSList.CopyItem(Src, Dest: Pointer);
  190. begin
  191. System.Move(Src^, Dest^, FItemSize);
  192. end;
  193. procedure TFPSList.RaiseIndexError(Index : Integer);
  194. begin
  195. Error(SListIndexError, Index);
  196. end;
  197. function TFPSList.InternalGet(Index: Integer): Pointer;
  198. begin
  199. Result:=FList+Index*ItemSize;
  200. end;
  201. procedure TFPSList.InternalPut(Index: Integer; NewItem: Pointer);
  202. var
  203. ListItem: Pointer;
  204. begin
  205. ListItem := InternalItems[Index];
  206. CopyItem(NewItem, ListItem);
  207. end;
  208. function TFPSList.Get(Index: Integer): Pointer;
  209. begin
  210. if (Index < 0) or (Index >= FCount) then
  211. RaiseIndexError(Index);
  212. Result := InternalItems[Index];
  213. end;
  214. procedure TFPSList.Put(Index: Integer; Item: Pointer);
  215. begin
  216. if (Index < 0) or (Index >= FCount) then
  217. RaiseIndexError(Index);
  218. InternalItems[Index] := Item;
  219. end;
  220. procedure TFPSList.SetCapacity(NewCapacity: Integer);
  221. begin
  222. if (NewCapacity < FCount) or (NewCapacity > MaxListSize) then
  223. Error(SListCapacityError, NewCapacity);
  224. if NewCapacity = FCapacity then
  225. exit;
  226. ReallocMem(FList, (NewCapacity+1) * FItemSize);
  227. FillChar(InternalItems[FCapacity]^, (NewCapacity+1-FCapacity) * FItemSize, #0);
  228. FCapacity := NewCapacity;
  229. end;
  230. procedure TFPSList.Deref(Item: Pointer);
  231. begin
  232. end;
  233. procedure TFPSList.Deref(FromIndex, ToIndex: Integer);
  234. var
  235. ListItem, ListItemLast: Pointer;
  236. begin
  237. ListItem := InternalItems[FromIndex];
  238. ListItemLast := InternalItems[ToIndex];
  239. repeat
  240. Deref(ListItem);
  241. if ListItem = ListItemLast then
  242. break;
  243. ListItem := PByte(ListItem) + ItemSize;
  244. until false;
  245. end;
  246. procedure TFPSList.SetCount(NewCount: Integer);
  247. begin
  248. if (NewCount < 0) or (NewCount > MaxListSize) then
  249. Error(SListCountError, NewCount);
  250. if NewCount > FCount then
  251. begin
  252. if NewCount > FCapacity then
  253. SetCapacity(NewCount);
  254. if NewCount > FCount then
  255. FillByte(InternalItems[FCount]^, (NewCount-FCount) * FItemSize, 0)
  256. else if NewCount < FCount then
  257. Deref(NewCount, FCount-1);
  258. end;
  259. FCount := NewCount;
  260. end;
  261. function TFPSList.Add(Item: Pointer): Integer;
  262. begin
  263. if FCount = FCapacity then
  264. Self.Expand;
  265. CopyItem(Item, InternalItems[FCount]);
  266. Result := FCount;
  267. Inc(FCount);
  268. end;
  269. procedure TFPSList.Clear;
  270. begin
  271. if Assigned(FList) then
  272. begin
  273. SetCount(0);
  274. SetCapacity(0);
  275. FList := nil;
  276. end;
  277. end;
  278. procedure TFPSList.Delete(Index: Integer);
  279. var
  280. ListItem: Pointer;
  281. begin
  282. if (Index < 0) or (Index >= FCount) then
  283. Error(SListIndexError, Index);
  284. Dec(FCount);
  285. ListItem := InternalItems[Index];
  286. Deref(ListItem);
  287. System.Move(InternalItems[Index+1]^, ListItem^, (FCount - Index) * FItemSize);
  288. // Shrink the list if appropriate
  289. if (FCapacity > 256) and (FCount < FCapacity shr 2) then
  290. begin
  291. FCapacity := FCapacity shr 1;
  292. ReallocMem(FList, (FCapacity+1) * FItemSize);
  293. end;
  294. end;
  295. function TFPSList.Extract(Item: Pointer): Pointer;
  296. var
  297. i : Integer;
  298. begin
  299. Result := nil;
  300. i := IndexOf(Item);
  301. if i >= 0 then
  302. begin
  303. Result := InternalItems[i];
  304. System.Move(Result^, InternalItems[FCapacity]^, FItemSize);
  305. Delete(i);
  306. end;
  307. end;
  308. class procedure TFPSList.Error(const Msg: string; Data: PtrInt);
  309. begin
  310. raise EListError.CreateFmt(Msg,[Data]) at get_caller_addr(get_frame);
  311. end;
  312. procedure TFPSList.Exchange(Index1, Index2: Integer);
  313. begin
  314. if ((Index1 >= FCount) or (Index1 < 0)) then
  315. Error(SListIndexError, Index1);
  316. if ((Index2 >= FCount) or (Index2 < 0)) then
  317. Error(SListIndexError, Index2);
  318. InternalExchange(Index1, Index2);
  319. end;
  320. procedure TFPSList.InternalExchange(Index1, Index2: Integer);
  321. begin
  322. System.Move(InternalItems[Index1]^, InternalItems[FCapacity]^, FItemSize);
  323. System.Move(InternalItems[Index2]^, InternalItems[Index1]^, FItemSize);
  324. System.Move(InternalItems[FCapacity]^, InternalItems[Index2]^, FItemSize);
  325. end;
  326. function TFPSList.Expand: TFPSList;
  327. var
  328. IncSize : Longint;
  329. begin
  330. if FCount < FCapacity then exit;
  331. IncSize := 4;
  332. if FCapacity > 3 then IncSize := IncSize + 4;
  333. if FCapacity > 8 then IncSize := IncSize + 8;
  334. if FCapacity > 127 then Inc(IncSize, FCapacity shr 2);
  335. SetCapacity(FCapacity + IncSize);
  336. Result := Self;
  337. end;
  338. function TFPSList.First: Pointer;
  339. begin
  340. If FCount = 0 then
  341. Result := Nil
  342. else
  343. Result := InternalItems[0];
  344. end;
  345. function TFPSList.IndexOf(Item: Pointer): Integer;
  346. var
  347. ListItem: Pointer;
  348. begin
  349. Result := 0;
  350. ListItem := First;
  351. while (Result < FCount) and (CompareByte(ListItem^, Item^, FItemSize) <> 0) do
  352. begin
  353. Inc(Result);
  354. ListItem := PByte(ListItem)+FItemSize;
  355. end;
  356. if Result = FCount then Result := -1;
  357. end;
  358. function TFPSList.Insert(Index: Integer): Pointer;
  359. begin
  360. if (Index < 0) or (Index > FCount) then
  361. Error(SListIndexError, Index);
  362. if FCount = FCapacity then Self.Expand;
  363. if Index<FCount then
  364. System.Move(InternalItems[Index]^, InternalItems[Index+1]^, (FCount - Index) * FItemSize);
  365. Result := InternalItems[Index];
  366. Inc(FCount);
  367. end;
  368. procedure TFPSList.Insert(Index: Integer; Item: Pointer);
  369. begin
  370. CopyItem(Item, Insert(Index));
  371. end;
  372. function TFPSList.Last: Pointer;
  373. begin
  374. if FCount = 0 then
  375. Result := nil
  376. else
  377. Result := InternalItems[FCount - 1];
  378. end;
  379. procedure TFPSList.Move(CurIndex, NewIndex: Integer);
  380. var
  381. CurItem, NewItem, TmpItem, Src, Dest: Pointer;
  382. MoveCount: Integer;
  383. begin
  384. if (CurIndex < 0) or (CurIndex >= Count) then
  385. Error(SListIndexError, CurIndex);
  386. if (NewIndex < 0) or (NewIndex >= Count) then
  387. Error(SListIndexError, NewIndex);
  388. if CurIndex = NewIndex then
  389. exit;
  390. CurItem := InternalItems[CurIndex];
  391. NewItem := InternalItems[NewIndex];
  392. TmpItem := InternalItems[FCapacity];
  393. System.Move(CurItem^, TmpItem^, FItemSize);
  394. if NewIndex > CurIndex then
  395. begin
  396. Src := InternalItems[CurIndex+1];
  397. Dest := CurItem;
  398. MoveCount := NewIndex - CurIndex;
  399. end else begin
  400. Src := NewItem;
  401. Dest := InternalItems[NewIndex+1];
  402. MoveCount := CurIndex - NewIndex;
  403. end;
  404. System.Move(Src^, Dest^, MoveCount * FItemSize);
  405. System.Move(TmpItem^, NewItem^, FItemSize);
  406. end;
  407. function TFPSList.Remove(Item: Pointer): Integer;
  408. begin
  409. Result := IndexOf(Item);
  410. if Result <> -1 then
  411. Delete(Result);
  412. end;
  413. procedure TFPSList.Pack;
  414. var
  415. NewCount,
  416. i : integer;
  417. pdest,
  418. psrc : Pointer;
  419. begin
  420. NewCount:=0;
  421. psrc:=First;
  422. pdest:=psrc;
  423. For I:=0 To FCount-1 Do
  424. begin
  425. if assigned(pointer(psrc^)) then
  426. begin
  427. System.Move(psrc^, pdest^, FItemSize);
  428. inc(pdest);
  429. inc(NewCount);
  430. end;
  431. inc(psrc);
  432. end;
  433. FCount:=NewCount;
  434. end;
  435. // Needed by Sort method.
  436. procedure TFPSList.QuickSort(L, R: Integer; Compare: TFPSListCompareFunc);
  437. var
  438. I, J, P: Integer;
  439. PivotItem: Pointer;
  440. begin
  441. repeat
  442. I := L;
  443. J := R;
  444. P := (L + R) div 2;
  445. repeat
  446. PivotItem := InternalItems[P];
  447. while Compare(PivotItem, InternalItems[I]) > 0 do
  448. Inc(I);
  449. while Compare(PivotItem, InternalItems[J]) < 0 do
  450. Dec(J);
  451. if I <= J then
  452. begin
  453. InternalExchange(I, J);
  454. if P = I then
  455. P := J
  456. else if P = J then
  457. P := I;
  458. Inc(I);
  459. Dec(J);
  460. end;
  461. until I > J;
  462. if L < J then
  463. QuickSort(L, J, Compare);
  464. L := I;
  465. until I >= R;
  466. end;
  467. procedure TFPSList.Sort(Compare: TFPSListCompareFunc);
  468. begin
  469. if not Assigned(FList) or (FCount < 2) then exit;
  470. QuickSort(0, FCount-1, Compare);
  471. end;
  472. procedure TFPSList.Assign(Obj: TFPSList);
  473. var
  474. i: Integer;
  475. begin
  476. if Obj.ItemSize <> FItemSize then
  477. Error(SListItemSizeError, 0);
  478. Clear;
  479. for I := 0 to Obj.Count - 1 do
  480. Add(Obj[i]);
  481. end;
  482. {****************************************************************************}
  483. {* TFPGList *}
  484. {****************************************************************************}
  485. {$ifndef VER2_0}
  486. constructor TFPGList.Create;
  487. begin
  488. inherited Create(sizeof(T));
  489. end;
  490. procedure TFPGList.CopyItem(Src, Dest: Pointer);
  491. begin
  492. T(Dest^) := T(Src^);
  493. end;
  494. procedure TFPGList.Deref(Item: Pointer);
  495. begin
  496. Finalize(T(Item^));
  497. end;
  498. function TFPGList.Get(Index: Integer): T;
  499. begin
  500. Result := T(inherited Get(Index)^);
  501. end;
  502. function TFPGList.ItemPtrCompare(Item1, Item2: Pointer): Integer;
  503. begin
  504. Result := FOnCompare(T(Item1^), T(Item2^));
  505. end;
  506. procedure TFPGList.Put(Index: Integer; const Item: T);
  507. begin
  508. inherited Put(Index, @Item);
  509. end;
  510. function TFPGList.Add(const Item: T): Integer;
  511. begin
  512. Result := inherited Add(@Item);
  513. end;
  514. function TFPGList.Extract(const Item: T): T;
  515. var
  516. ResPtr: Pointer;
  517. begin
  518. ResPtr := inherited Extract(@Item);
  519. if ResPtr <> nil then
  520. Result := T(ResPtr^)
  521. else
  522. FillByte(Result, 0, sizeof(T));
  523. end;
  524. function TFPGList.First: T;
  525. begin
  526. Result := T(inherited First^);
  527. end;
  528. function TFPGList.IndexOf(const Item: T): Integer;
  529. begin
  530. Result := 0;
  531. {$warning TODO: fix inlining to work! InternalItems[Result]^}
  532. while (Result < FCount) and (PT(FList)[Result] <> Item) do
  533. Inc(Result);
  534. {$warning TODO: Result := -1; does not compile }
  535. if Result = FCount then
  536. begin
  537. Result := 0;
  538. dec(Result);
  539. end;
  540. end;
  541. procedure TFPGList.Insert(Index: Integer; const Item: T);
  542. begin
  543. T(inherited Insert(Index)^) := Item;
  544. end;
  545. function TFPGList.Last: T;
  546. begin
  547. Result := T(inherited Last^);
  548. end;
  549. function TFPGList.Remove(const Item: T): Integer;
  550. begin
  551. Result := IndexOf(Item);
  552. if Result >= 0 then
  553. Delete(Result);
  554. end;
  555. procedure TFPGList.Sort(Compare: TCompareFunc);
  556. begin
  557. FOnCompare := Compare;
  558. inherited Sort(@ItemPtrCompare);
  559. end;
  560. {$endif}
  561. {****************************************************************************
  562. TFPSMap
  563. ****************************************************************************}
  564. constructor TFPSMap.Create(AKeySize: Integer; ADataSize: integer);
  565. begin
  566. inherited Create(AKeySize+ADataSize);
  567. FKeySize := AKeySize;
  568. FDataSize := ADataSize;
  569. InitOnPtrCompare;
  570. end;
  571. procedure TFPSMap.CopyKey(Src, Dest: Pointer);
  572. begin
  573. System.Move(Src^, Dest^, FKeySize);
  574. end;
  575. procedure TFPSMap.CopyData(Src, Dest: Pointer);
  576. begin
  577. System.Move(Src^, Dest^, FDataSize);
  578. end;
  579. function TFPSMap.BinaryCompare(Key1, Key2: Pointer): Integer;
  580. begin
  581. Result := CompareByte(Key1^, Key2^, FKeySize);
  582. end;
  583. function TFPSMap.GetKey(Index: Integer): Pointer;
  584. begin
  585. Result := Items[Index];
  586. end;
  587. function TFPSMap.GetData(Index: Integer): Pointer;
  588. begin
  589. Result := PByte(Items[Index])+FKeySize;
  590. end;
  591. function TFPSMap.GetKeyData(AKey: Pointer): Pointer;
  592. var
  593. I: Integer;
  594. begin
  595. if Find(AKey, I) then
  596. Result := InternalItems[I]
  597. else
  598. Result := nil;
  599. end;
  600. procedure TFPSMap.InitOnPtrCompare;
  601. begin
  602. FOnPtrCompare := @BinaryCompare;
  603. end;
  604. procedure TFPSMap.PutKey(Index: Integer; AKey: Pointer);
  605. begin
  606. if FSorted then
  607. Error(SSortedListError, 0);
  608. CopyKey(AKey, Items[Index]);
  609. end;
  610. procedure TFPSMap.PutData(Index: Integer; AData: Pointer);
  611. begin
  612. CopyData(AData, PByte(Items[Index])+FKeySize);
  613. end;
  614. procedure TFPSMap.PutKeyData(AKey: Pointer; NewData: Pointer);
  615. var
  616. I: Integer;
  617. begin
  618. if Find(AKey, I) then
  619. Data[I] := NewData
  620. else
  621. Add(AKey, NewData);
  622. end;
  623. procedure TFPSMap.SetSorted(Value: Boolean);
  624. begin
  625. if Value = FSorted then exit;
  626. FSorted := Value;
  627. if Value then Sort;
  628. end;
  629. function TFPSMap.Add(AKey: Pointer): Integer;
  630. begin
  631. if Sorted then
  632. begin
  633. if Find(AKey, Result) then
  634. case Duplicates of
  635. dupIgnore: exit;
  636. dupError: Error(SDuplicateItem, 0)
  637. end;
  638. end else
  639. Result := Count;
  640. CopyKey(AKey, Insert(Result));
  641. end;
  642. function TFPSMap.Add(AKey, AData: Pointer): Integer;
  643. begin
  644. Result := Add(AKey);
  645. Data[Result] := AData;
  646. end;
  647. function TFPSMap.Find(AKey: Pointer; var Index: Integer): Boolean;
  648. { Searches for the first item <= Key, returns True if exact match,
  649. sets index to the index f the found string. }
  650. var
  651. I,L,R,Dir: Integer;
  652. begin
  653. Result := false;
  654. // Use binary search.
  655. L := 0;
  656. R := FCount-1;
  657. while L<=R do
  658. begin
  659. I := (L+R) div 2;
  660. Dir := FOnPtrCompare(Items[I], AKey);
  661. if Dir < 0 then
  662. L := I+1
  663. else begin
  664. R := I-1;
  665. if Dir = 0 then
  666. begin
  667. Result := true;
  668. if Duplicates <> dupAccept then
  669. L := I;
  670. end;
  671. end;
  672. end;
  673. Index := L;
  674. end;
  675. function TFPSMap.LinearIndexOf(AKey: Pointer): Integer;
  676. var
  677. ListItem: Pointer;
  678. begin
  679. Result := 0;
  680. ListItem := First;
  681. while (Result < FCount) and (FOnPtrCompare(ListItem, AKey) <> 0) do
  682. begin
  683. Inc(Result);
  684. ListItem := PByte(ListItem)+FItemSize;
  685. end;
  686. if Result = FCount then Result := -1;
  687. end;
  688. function TFPSMap.IndexOf(AKey: Pointer): Integer;
  689. begin
  690. if Sorted then
  691. begin
  692. if not Find(AKey, Result) then
  693. Result := -1;
  694. end else
  695. Result := LinearIndexOf(AKey);
  696. end;
  697. function TFPSMap.IndexOfData(AData: Pointer): Integer;
  698. var
  699. ListItem: Pointer;
  700. begin
  701. Result := 0;
  702. ListItem := First+FKeySize;
  703. while (Result < FCount) and (CompareByte(ListItem^, AData^, FDataSize) <> 0) do
  704. begin
  705. Inc(Result);
  706. ListItem := PByte(ListItem)+FItemSize;
  707. end;
  708. if Result = FCount then Result := -1;
  709. end;
  710. function TFPSMap.Insert(Index: Integer): Pointer;
  711. begin
  712. if FSorted then
  713. Error(SSortedListError, 0);
  714. Result := inherited Insert(Index);
  715. end;
  716. procedure TFPSMap.Insert(Index: Integer; var AKey, AData: Pointer);
  717. begin
  718. AKey := Insert(Index);
  719. AData := PByte(AKey) + FKeySize;
  720. end;
  721. procedure TFPSMap.InsertKey(Index: Integer; AKey: Pointer);
  722. begin
  723. CopyKey(AKey, Insert(Index));
  724. end;
  725. procedure TFPSMap.InsertKeyData(Index: Integer; AKey, AData: Pointer);
  726. var
  727. ListItem: Pointer;
  728. begin
  729. ListItem := Insert(Index);
  730. CopyKey(AKey, ListItem);
  731. CopyData(AData, PByte(ListItem)+FKeySize);
  732. end;
  733. function TFPSMap.Remove(AKey: Pointer): Integer;
  734. begin
  735. if Find(AKey, Result) then
  736. Delete(Result)
  737. else
  738. Result := -1;
  739. end;
  740. procedure TFPSMap.Sort;
  741. begin
  742. inherited Sort(FOnPtrCompare);
  743. end;
  744. {****************************************************************************
  745. TFPGMap
  746. ****************************************************************************}
  747. {$ifndef VER2_0}
  748. constructor TFPGMap.Create;
  749. begin
  750. inherited Create(SizeOf(TKey), SizeOf(TData));
  751. end;
  752. procedure TFPGMap.CopyItem(Src, Dest: Pointer);
  753. begin
  754. CopyKey(Src, Dest);
  755. CopyData(PByte(Src)+KeySize, PByte(Dest)+KeySize);
  756. end;
  757. procedure TFPGMap.CopyKey(Src, Dest: Pointer);
  758. begin
  759. TKey(Dest^) := TKey(Src^);
  760. end;
  761. procedure TFPGMap.CopyData(Src, Dest: Pointer);
  762. begin
  763. TData(Dest^) := TData(Src^);
  764. end;
  765. procedure TFPGMap.Deref(Item: Pointer);
  766. begin
  767. Finalize(TKey(Item^));
  768. Finalize(TData(Pointer(PByte(Item)+KeySize)^));
  769. end;
  770. function TFPGMap.GetKey(Index: Integer): TKey;
  771. begin
  772. Result := TKey(inherited GetKey(Index)^);
  773. end;
  774. function TFPGMap.GetData(Index: Integer): TData;
  775. begin
  776. Result := TData(inherited GetData(Index)^);
  777. end;
  778. function TFPGMap.GetKeyData(const AKey: TKey): TData;
  779. begin
  780. Result := TData(inherited GetKeyData(@AKey)^);
  781. end;
  782. function TFPGMap.KeyPtrCompare(Key1, Key2: Pointer): Integer;
  783. begin
  784. Result := FOnCompare(TKey(Key1^), TKey(Key2^));
  785. end;
  786. procedure TFPGMap.PutKey(Index: Integer; const NewKey: TKey);
  787. begin
  788. inherited PutKey(Index, @NewKey);
  789. end;
  790. procedure TFPGMap.PutData(Index: Integer; const NewData: TData);
  791. begin
  792. inherited PutData(Index, @NewData);
  793. end;
  794. procedure TFPGMap.PutKeyData(const AKey: TKey; const NewData: TData);
  795. begin
  796. inherited PutKeyData(@AKey, @NewData);
  797. end;
  798. procedure TFPGMap.SetOnCompare(NewCompare: TCompareFunc);
  799. begin
  800. FOnCompare := NewCompare;
  801. if NewCompare <> nil then
  802. OnPtrCompare := @KeyPtrCompare
  803. else
  804. InitOnPtrCompare;
  805. end;
  806. function TFPGMap.Add(const AKey: TKey): Integer;
  807. begin
  808. Result := inherited Add(@AKey);
  809. end;
  810. function TFPGMap.Add(const AKey: TKey; const AData: TData): Integer;
  811. begin
  812. Result := inherited Add(@AKey, @AData);
  813. end;
  814. function TFPGMap.Find(const AKey: TKey; var Index: Integer): Boolean;
  815. begin
  816. Result := inherited Find(@AKey, Index);
  817. end;
  818. function TFPGMap.IndexOf(const AKey: TKey): Integer;
  819. begin
  820. Result := inherited IndexOf(@AKey);
  821. end;
  822. function TFPGMap.IndexOfData(const AData: TData): Integer;
  823. begin
  824. { TODO: loop ? }
  825. Result := inherited IndexOfData(@AData);
  826. end;
  827. procedure TFPGMap.InsertKey(Index: Integer; const AKey: TKey);
  828. begin
  829. inherited InsertKey(Index, @AKey);
  830. end;
  831. procedure TFPGMap.InsertKeyData(Index: Integer; const AKey: TKey; const AData: TData);
  832. begin
  833. inherited InsertKeyData(Index, @AKey, @AData);
  834. end;
  835. function TFPGMap.Remove(const AKey: TKey): Integer;
  836. begin
  837. Result := inherited Remove(@AKey);
  838. end;
  839. {$endif}
  840. end.