fgl.pp 25 KB

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