fgl.pp 25 KB

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