fgl.pp 25 KB

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