fgl.pp 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976
  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. I := IndexOf(AKey);
  609. if I >= 0 then
  610. Result := InternalItems[I]
  611. else
  612. Error(SMapKeyError, PtrInt(AKey));
  613. end;
  614. procedure TFPSMap.InitOnPtrCompare;
  615. begin
  616. FOnPtrCompare := @BinaryCompare;
  617. end;
  618. procedure TFPSMap.PutKey(Index: Integer; AKey: Pointer);
  619. begin
  620. if FSorted then
  621. Error(SSortedListError, 0);
  622. CopyKey(AKey, Items[Index]);
  623. end;
  624. procedure TFPSMap.PutData(Index: Integer; AData: Pointer);
  625. begin
  626. CopyData(AData, PByte(Items[Index])+FKeySize);
  627. end;
  628. procedure TFPSMap.PutKeyData(AKey: Pointer; NewData: Pointer);
  629. var
  630. I: Integer;
  631. begin
  632. I := IndexOf(AKey);
  633. if I >= 0 then
  634. Data[I] := NewData
  635. else
  636. Add(AKey, NewData);
  637. end;
  638. procedure TFPSMap.SetSorted(Value: Boolean);
  639. begin
  640. if Value = FSorted then exit;
  641. FSorted := Value;
  642. if Value then Sort;
  643. end;
  644. function TFPSMap.Add(AKey: Pointer): Integer;
  645. begin
  646. if Sorted then
  647. begin
  648. if Find(AKey, Result) then
  649. case Duplicates of
  650. dupIgnore: exit;
  651. dupError: Error(SDuplicateItem, 0)
  652. end;
  653. end else
  654. Result := Count;
  655. CopyKey(AKey, inherited Insert(Result));
  656. end;
  657. function TFPSMap.Add(AKey, AData: Pointer): Integer;
  658. begin
  659. Result := Add(AKey);
  660. Data[Result] := AData;
  661. end;
  662. function TFPSMap.Find(AKey: Pointer; var Index: Integer): Boolean;
  663. { Searches for the first item <= Key, returns True if exact match,
  664. sets index to the index f the found string. }
  665. var
  666. I,L,R,Dir: Integer;
  667. begin
  668. Result := false;
  669. // Use binary search.
  670. L := 0;
  671. R := FCount-1;
  672. while L<=R do
  673. begin
  674. I := (L+R) div 2;
  675. Dir := FOnPtrCompare(Items[I], AKey);
  676. if Dir < 0 then
  677. L := I+1
  678. else begin
  679. R := I-1;
  680. if Dir = 0 then
  681. begin
  682. Result := true;
  683. if Duplicates <> dupAccept then
  684. L := I;
  685. end;
  686. end;
  687. end;
  688. Index := L;
  689. end;
  690. function TFPSMap.LinearIndexOf(AKey: Pointer): Integer;
  691. var
  692. ListItem: Pointer;
  693. begin
  694. Result := 0;
  695. ListItem := First;
  696. while (Result < FCount) and (FOnPtrCompare(ListItem, AKey) <> 0) do
  697. begin
  698. Inc(Result);
  699. ListItem := PByte(ListItem)+FItemSize;
  700. end;
  701. if Result = FCount then Result := -1;
  702. end;
  703. function TFPSMap.IndexOf(AKey: Pointer): Integer;
  704. begin
  705. if Sorted then
  706. begin
  707. if not Find(AKey, Result) then
  708. Result := -1;
  709. end else
  710. Result := LinearIndexOf(AKey);
  711. end;
  712. function TFPSMap.IndexOfData(AData: Pointer): Integer;
  713. var
  714. ListItem: Pointer;
  715. begin
  716. Result := 0;
  717. ListItem := First+FKeySize;
  718. while (Result < FCount) and (CompareByte(ListItem^, AData^, FDataSize) <> 0) do
  719. begin
  720. Inc(Result);
  721. ListItem := PByte(ListItem)+FItemSize;
  722. end;
  723. if Result = FCount then Result := -1;
  724. end;
  725. function TFPSMap.Insert(Index: Integer): Pointer;
  726. begin
  727. if FSorted then
  728. Error(SSortedListError, 0);
  729. Result := inherited Insert(Index);
  730. end;
  731. procedure TFPSMap.Insert(Index: Integer; var AKey, AData: Pointer);
  732. begin
  733. AKey := Insert(Index);
  734. AData := PByte(AKey) + FKeySize;
  735. end;
  736. procedure TFPSMap.InsertKey(Index: Integer; AKey: Pointer);
  737. begin
  738. CopyKey(AKey, Insert(Index));
  739. end;
  740. procedure TFPSMap.InsertKeyData(Index: Integer; AKey, AData: Pointer);
  741. var
  742. ListItem: Pointer;
  743. begin
  744. ListItem := Insert(Index);
  745. CopyKey(AKey, ListItem);
  746. CopyData(AData, PByte(ListItem)+FKeySize);
  747. end;
  748. function TFPSMap.Remove(AKey: Pointer): Integer;
  749. begin
  750. Result := IndexOf(AKey);
  751. if Result >= 0 then
  752. Delete(Result);
  753. end;
  754. procedure TFPSMap.Sort;
  755. begin
  756. inherited Sort(FOnPtrCompare);
  757. end;
  758. {****************************************************************************
  759. TFPGMap
  760. ****************************************************************************}
  761. {$ifndef VER2_0}
  762. constructor TFPGMap.Create;
  763. begin
  764. inherited Create(SizeOf(TKey), SizeOf(TData));
  765. end;
  766. procedure TFPGMap.CopyItem(Src, Dest: Pointer);
  767. begin
  768. CopyKey(Src, Dest);
  769. CopyData(PByte(Src)+KeySize, PByte(Dest)+KeySize);
  770. end;
  771. procedure TFPGMap.CopyKey(Src, Dest: Pointer);
  772. begin
  773. TKey(Dest^) := TKey(Src^);
  774. end;
  775. procedure TFPGMap.CopyData(Src, Dest: Pointer);
  776. begin
  777. TData(Dest^) := TData(Src^);
  778. end;
  779. procedure TFPGMap.Deref(Item: Pointer);
  780. begin
  781. Finalize(TKey(Item^));
  782. Finalize(TData(Pointer(PByte(Item)+KeySize)^));
  783. end;
  784. function TFPGMap.GetKey(Index: Integer): TKey;
  785. begin
  786. Result := TKey(inherited GetKey(Index)^);
  787. end;
  788. function TFPGMap.GetData(Index: Integer): TData;
  789. begin
  790. Result := TData(inherited GetData(Index)^);
  791. end;
  792. function TFPGMap.GetKeyData(const AKey: TKey): TData;
  793. begin
  794. Result := TData(inherited GetKeyData(@AKey)^);
  795. end;
  796. function TFPGMap.KeyPtrCompare(Key1, Key2: Pointer): Integer;
  797. begin
  798. Result := FOnCompare(TKey(Key1^), TKey(Key2^));
  799. end;
  800. procedure TFPGMap.PutKey(Index: Integer; const NewKey: TKey);
  801. begin
  802. inherited PutKey(Index, @NewKey);
  803. end;
  804. procedure TFPGMap.PutData(Index: Integer; const NewData: TData);
  805. begin
  806. inherited PutData(Index, @NewData);
  807. end;
  808. procedure TFPGMap.PutKeyData(const AKey: TKey; const NewData: TData);
  809. begin
  810. inherited PutKeyData(@AKey, @NewData);
  811. end;
  812. procedure TFPGMap.SetOnCompare(NewCompare: TCompareFunc);
  813. begin
  814. FOnCompare := NewCompare;
  815. if NewCompare <> nil then
  816. OnPtrCompare := @KeyPtrCompare
  817. else
  818. InitOnPtrCompare;
  819. end;
  820. function TFPGMap.Add(const AKey: TKey): Integer;
  821. begin
  822. Result := inherited Add(@AKey);
  823. end;
  824. function TFPGMap.Add(const AKey: TKey; const AData: TData): Integer;
  825. begin
  826. Result := inherited Add(@AKey, @AData);
  827. end;
  828. function TFPGMap.Find(const AKey: TKey; var Index: Integer): Boolean;
  829. begin
  830. Result := inherited Find(@AKey, Index);
  831. end;
  832. function TFPGMap.IndexOf(const AKey: TKey): Integer;
  833. begin
  834. Result := inherited IndexOf(@AKey);
  835. end;
  836. function TFPGMap.IndexOfData(const AData: TData): Integer;
  837. begin
  838. { TODO: loop ? }
  839. Result := inherited IndexOfData(@AData);
  840. end;
  841. procedure TFPGMap.InsertKey(Index: Integer; const AKey: TKey);
  842. begin
  843. inherited InsertKey(Index, @AKey);
  844. end;
  845. procedure TFPGMap.InsertKeyData(Index: Integer; const AKey: TKey; const AData: TData);
  846. begin
  847. inherited InsertKeyData(Index, @AKey, @AData);
  848. end;
  849. function TFPGMap.Remove(const AKey: TKey): Integer;
  850. begin
  851. Result := inherited Remove(@AKey);
  852. end;
  853. {$endif}
  854. end.