fgl.pp 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991
  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. {$info FIXME: bug #10479: implement 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; virtual;
  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. PKey = ^TKey;
  151. PData = ^TData;
  152. var protected
  153. FOnCompare: TCompareFunc;
  154. procedure CopyItem(Src, Dest: Pointer); override;
  155. procedure CopyKey(Src, Dest: Pointer); override;
  156. procedure CopyData(Src, Dest: Pointer); override;
  157. procedure Deref(Item: Pointer); override;
  158. procedure InitOnPtrCompare; override;
  159. function GetKey(Index: Integer): TKey; {$ifdef CLASSESINLINE} inline; {$endif}
  160. function GetKeyData(const AKey: TKey): TData; {$ifdef CLASSESINLINE} inline; {$endif}
  161. function GetData(Index: Integer): TData; {$ifdef CLASSESINLINE} inline; {$endif}
  162. function KeyCompare(Key1, Key2: Pointer): Integer;
  163. function KeyCustomCompare(Key1, Key2: Pointer): Integer;
  164. procedure PutKey(Index: Integer; const NewKey: TKey); {$ifdef CLASSESINLINE} inline; {$endif}
  165. procedure PutKeyData(const AKey: TKey; const NewData: TData); {$ifdef CLASSESINLINE} inline; {$endif}
  166. procedure PutData(Index: Integer; const NewData: TData); {$ifdef CLASSESINLINE} inline; {$endif}
  167. procedure SetOnCompare(NewCompare: TCompareFunc);
  168. public
  169. constructor Create;
  170. function Add(const AKey: TKey; const AData: TData): Integer; {$ifdef CLASSESINLINE} inline; {$endif}
  171. function Add(const AKey: TKey): Integer; {$ifdef CLASSESINLINE} inline; {$endif}
  172. function Find(const AKey: TKey; var Index: Integer): Boolean; {$ifdef CLASSESINLINE} inline; {$endif}
  173. function IndexOf(const AKey: TKey): Integer; {$ifdef CLASSESINLINE} inline; {$endif}
  174. function IndexOfData(const AData: TData): Integer;
  175. procedure InsertKey(Index: Integer; const AKey: TKey);
  176. procedure InsertKeyData(Index: Integer; const AKey: TKey; const AData: TData);
  177. function Remove(const AKey: TKey): Integer;
  178. property Keys[Index: Integer]: TKey read GetKey write PutKey;
  179. property Data[Index: Integer]: TData read GetData write PutData;
  180. property KeyData[const AKey: TKey]: TData read GetKeyData write PutKeyData; default;
  181. property OnCompare: TCompareFunc read FOnCompare write SetOnCompare;
  182. end;
  183. {$endif}
  184. implementation
  185. uses
  186. rtlconsts;
  187. {****************************************************************************
  188. TFPSList
  189. ****************************************************************************}
  190. constructor TFPSList.Create(AItemSize: integer);
  191. begin
  192. inherited Create;
  193. FItemSize := AItemSize;
  194. end;
  195. destructor TFPSList.Destroy;
  196. begin
  197. Clear;
  198. // Clear() does not clear the whole list; there is always a single temp entry
  199. // at the end which is never freed. Take care of that one here.
  200. FreeMem(FList);
  201. inherited Destroy;
  202. end;
  203. procedure TFPSList.CopyItem(Src, Dest: Pointer);
  204. begin
  205. System.Move(Src^, Dest^, FItemSize);
  206. end;
  207. procedure TFPSList.RaiseIndexError(Index : Integer);
  208. begin
  209. Error(SListIndexError, Index);
  210. end;
  211. function TFPSList.InternalGet(Index: Integer): Pointer;
  212. begin
  213. Result:=FList+Index*ItemSize;
  214. end;
  215. procedure TFPSList.InternalPut(Index: Integer; NewItem: Pointer);
  216. var
  217. ListItem: Pointer;
  218. begin
  219. ListItem := InternalItems[Index];
  220. CopyItem(NewItem, ListItem);
  221. end;
  222. function TFPSList.Get(Index: Integer): Pointer;
  223. begin
  224. if (Index < 0) or (Index >= FCount) then
  225. RaiseIndexError(Index);
  226. Result := InternalItems[Index];
  227. end;
  228. procedure TFPSList.Put(Index: Integer; Item: Pointer);
  229. begin
  230. if (Index < 0) or (Index >= FCount) then
  231. RaiseIndexError(Index);
  232. InternalItems[Index] := Item;
  233. end;
  234. procedure TFPSList.SetCapacity(NewCapacity: Integer);
  235. begin
  236. if (NewCapacity < FCount) or (NewCapacity > MaxListSize) then
  237. Error(SListCapacityError, NewCapacity);
  238. if NewCapacity = FCapacity then
  239. exit;
  240. ReallocMem(FList, (NewCapacity+1) * FItemSize);
  241. FillChar(InternalItems[FCapacity]^, (NewCapacity+1-FCapacity) * FItemSize, #0);
  242. FCapacity := NewCapacity;
  243. end;
  244. procedure TFPSList.Deref(Item: Pointer);
  245. begin
  246. end;
  247. procedure TFPSList.Deref(FromIndex, ToIndex: Integer);
  248. var
  249. ListItem, ListItemLast: Pointer;
  250. begin
  251. ListItem := InternalItems[FromIndex];
  252. ListItemLast := InternalItems[ToIndex];
  253. repeat
  254. Deref(ListItem);
  255. if ListItem = ListItemLast then
  256. break;
  257. ListItem := PByte(ListItem) + ItemSize;
  258. until false;
  259. end;
  260. procedure TFPSList.SetCount(NewCount: Integer);
  261. begin
  262. if (NewCount < 0) or (NewCount > MaxListSize) then
  263. Error(SListCountError, NewCount);
  264. if NewCount > FCount then
  265. begin
  266. if NewCount > FCapacity then
  267. SetCapacity(NewCount);
  268. if NewCount > FCount then
  269. FillByte(InternalItems[FCount]^, (NewCount-FCount) * FItemSize, 0)
  270. else if NewCount < FCount then
  271. Deref(NewCount, FCount-1);
  272. end;
  273. FCount := NewCount;
  274. end;
  275. function TFPSList.Add(Item: Pointer): Integer;
  276. begin
  277. if FCount = FCapacity then
  278. Self.Expand;
  279. CopyItem(Item, InternalItems[FCount]);
  280. Result := FCount;
  281. Inc(FCount);
  282. end;
  283. procedure TFPSList.Clear;
  284. begin
  285. if Assigned(FList) then
  286. begin
  287. SetCount(0);
  288. SetCapacity(0);
  289. end;
  290. end;
  291. procedure TFPSList.Delete(Index: Integer);
  292. var
  293. ListItem: Pointer;
  294. begin
  295. if (Index < 0) or (Index >= FCount) then
  296. Error(SListIndexError, Index);
  297. Dec(FCount);
  298. ListItem := InternalItems[Index];
  299. Deref(ListItem);
  300. System.Move(InternalItems[Index+1]^, ListItem^, (FCount - Index) * FItemSize);
  301. // Shrink the list if appropriate
  302. if (FCapacity > 256) and (FCount < FCapacity shr 2) then
  303. begin
  304. FCapacity := FCapacity shr 1;
  305. ReallocMem(FList, (FCapacity+1) * FItemSize);
  306. end;
  307. end;
  308. function TFPSList.Extract(Item: Pointer): Pointer;
  309. var
  310. i : Integer;
  311. begin
  312. Result := nil;
  313. i := IndexOf(Item);
  314. if i >= 0 then
  315. begin
  316. Result := InternalItems[i];
  317. System.Move(Result^, InternalItems[FCapacity]^, FItemSize);
  318. Delete(i);
  319. end;
  320. end;
  321. class procedure TFPSList.Error(const Msg: string; Data: PtrInt);
  322. begin
  323. raise EListError.CreateFmt(Msg,[Data]) at get_caller_addr(get_frame);
  324. end;
  325. procedure TFPSList.Exchange(Index1, Index2: Integer);
  326. begin
  327. if ((Index1 >= FCount) or (Index1 < 0)) then
  328. Error(SListIndexError, Index1);
  329. if ((Index2 >= FCount) or (Index2 < 0)) then
  330. Error(SListIndexError, Index2);
  331. InternalExchange(Index1, Index2);
  332. end;
  333. procedure TFPSList.InternalExchange(Index1, Index2: Integer);
  334. begin
  335. System.Move(InternalItems[Index1]^, InternalItems[FCapacity]^, FItemSize);
  336. System.Move(InternalItems[Index2]^, InternalItems[Index1]^, FItemSize);
  337. System.Move(InternalItems[FCapacity]^, InternalItems[Index2]^, FItemSize);
  338. end;
  339. function TFPSList.Expand: TFPSList;
  340. var
  341. IncSize : Longint;
  342. begin
  343. if FCount < FCapacity then exit;
  344. IncSize := 4;
  345. if FCapacity > 3 then IncSize := IncSize + 4;
  346. if FCapacity > 8 then IncSize := IncSize + 8;
  347. if FCapacity > 127 then Inc(IncSize, FCapacity shr 2);
  348. SetCapacity(FCapacity + IncSize);
  349. Result := Self;
  350. end;
  351. function TFPSList.First: Pointer;
  352. begin
  353. If FCount = 0 then
  354. Result := Nil
  355. else
  356. Result := InternalItems[0];
  357. end;
  358. function TFPSList.IndexOf(Item: Pointer): Integer;
  359. var
  360. ListItem: Pointer;
  361. begin
  362. Result := 0;
  363. ListItem := First;
  364. while (Result < FCount) and (CompareByte(ListItem^, Item^, FItemSize) <> 0) do
  365. begin
  366. Inc(Result);
  367. ListItem := PByte(ListItem)+FItemSize;
  368. end;
  369. if Result = FCount then Result := -1;
  370. end;
  371. function TFPSList.Insert(Index: Integer): Pointer;
  372. begin
  373. if (Index < 0) or (Index > FCount) then
  374. Error(SListIndexError, Index);
  375. if FCount = FCapacity then Self.Expand;
  376. if Index<FCount then
  377. System.Move(InternalItems[Index]^, InternalItems[Index+1]^, (FCount - Index) * FItemSize);
  378. Result := InternalItems[Index];
  379. Inc(FCount);
  380. end;
  381. procedure TFPSList.Insert(Index: Integer; Item: Pointer);
  382. begin
  383. CopyItem(Item, Insert(Index));
  384. end;
  385. function TFPSList.Last: Pointer;
  386. begin
  387. if FCount = 0 then
  388. Result := nil
  389. else
  390. Result := InternalItems[FCount - 1];
  391. end;
  392. procedure TFPSList.Move(CurIndex, NewIndex: Integer);
  393. var
  394. CurItem, NewItem, TmpItem, Src, Dest: Pointer;
  395. MoveCount: Integer;
  396. begin
  397. if (CurIndex < 0) or (CurIndex >= Count) then
  398. Error(SListIndexError, CurIndex);
  399. if (NewIndex < 0) or (NewIndex >= Count) then
  400. Error(SListIndexError, NewIndex);
  401. if CurIndex = NewIndex then
  402. exit;
  403. CurItem := InternalItems[CurIndex];
  404. NewItem := InternalItems[NewIndex];
  405. TmpItem := InternalItems[FCapacity];
  406. System.Move(CurItem^, TmpItem^, FItemSize);
  407. if NewIndex > CurIndex then
  408. begin
  409. Src := InternalItems[CurIndex+1];
  410. Dest := CurItem;
  411. MoveCount := NewIndex - CurIndex;
  412. end else begin
  413. Src := NewItem;
  414. Dest := InternalItems[NewIndex+1];
  415. MoveCount := CurIndex - NewIndex;
  416. end;
  417. System.Move(Src^, Dest^, MoveCount * FItemSize);
  418. System.Move(TmpItem^, NewItem^, FItemSize);
  419. end;
  420. function TFPSList.Remove(Item: Pointer): Integer;
  421. begin
  422. Result := IndexOf(Item);
  423. if Result <> -1 then
  424. Delete(Result);
  425. end;
  426. procedure TFPSList.Pack;
  427. var
  428. NewCount,
  429. i : integer;
  430. pdest,
  431. psrc : Pointer;
  432. begin
  433. NewCount:=0;
  434. psrc:=First;
  435. pdest:=psrc;
  436. For I:=0 To FCount-1 Do
  437. begin
  438. if assigned(pointer(psrc^)) then
  439. begin
  440. System.Move(psrc^, pdest^, FItemSize);
  441. inc(pdest);
  442. inc(NewCount);
  443. end;
  444. inc(psrc);
  445. end;
  446. FCount:=NewCount;
  447. end;
  448. // Needed by Sort method.
  449. procedure TFPSList.QuickSort(L, R: Integer; Compare: TFPSListCompareFunc);
  450. var
  451. I, J, P: Integer;
  452. PivotItem: Pointer;
  453. begin
  454. repeat
  455. I := L;
  456. J := R;
  457. P := (L + R) div 2;
  458. repeat
  459. PivotItem := InternalItems[P];
  460. while Compare(PivotItem, InternalItems[I]) > 0 do
  461. Inc(I);
  462. while Compare(PivotItem, InternalItems[J]) < 0 do
  463. Dec(J);
  464. if I <= J then
  465. begin
  466. InternalExchange(I, J);
  467. if P = I then
  468. P := J
  469. else if P = J then
  470. P := I;
  471. Inc(I);
  472. Dec(J);
  473. end;
  474. until I > J;
  475. if L < J then
  476. QuickSort(L, J, Compare);
  477. L := I;
  478. until I >= R;
  479. end;
  480. procedure TFPSList.Sort(Compare: TFPSListCompareFunc);
  481. begin
  482. if not Assigned(FList) or (FCount < 2) then exit;
  483. QuickSort(0, FCount-1, Compare);
  484. end;
  485. procedure TFPSList.Assign(Obj: TFPSList);
  486. var
  487. i: Integer;
  488. begin
  489. if Obj.ItemSize <> FItemSize then
  490. Error(SListItemSizeError, 0);
  491. Clear;
  492. for I := 0 to Obj.Count - 1 do
  493. Add(Obj[i]);
  494. end;
  495. {****************************************************************************}
  496. {* TFPGList *}
  497. {****************************************************************************}
  498. {$ifndef VER2_0}
  499. constructor TFPGList.Create;
  500. begin
  501. inherited Create(sizeof(T));
  502. end;
  503. procedure TFPGList.CopyItem(Src, Dest: Pointer);
  504. begin
  505. T(Dest^) := T(Src^);
  506. end;
  507. procedure TFPGList.Deref(Item: Pointer);
  508. begin
  509. Finalize(T(Item^));
  510. end;
  511. function TFPGList.Get(Index: Integer): T;
  512. begin
  513. Result := T(inherited Get(Index)^);
  514. end;
  515. function TFPGList.GetList: PTypeList;
  516. begin
  517. Result := PTypeList(FList);
  518. end;
  519. function TFPGList.ItemPtrCompare(Item1, Item2: Pointer): Integer;
  520. begin
  521. Result := FOnCompare(T(Item1^), T(Item2^));
  522. end;
  523. procedure TFPGList.Put(Index: Integer; const Item: T);
  524. begin
  525. inherited Put(Index, @Item);
  526. end;
  527. function TFPGList.Add(const Item: T): Integer;
  528. begin
  529. Result := inherited Add(@Item);
  530. end;
  531. function TFPGList.Extract(const Item: T): T;
  532. var
  533. ResPtr: Pointer;
  534. begin
  535. ResPtr := inherited Extract(@Item);
  536. if ResPtr <> nil then
  537. Result := T(ResPtr^)
  538. else
  539. FillByte(Result, 0, sizeof(T));
  540. end;
  541. function TFPGList.First: T;
  542. begin
  543. Result := T(inherited First^);
  544. end;
  545. function TFPGList.IndexOf(const Item: T): Integer;
  546. begin
  547. Result := 0;
  548. {$info TODO: fix inlining to work! InternalItems[Result]^}
  549. while (Result < FCount) and (PT(FList)[Result] <> Item) do
  550. Inc(Result);
  551. if Result = FCount then
  552. Result := -1;
  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]+FKeySize
  611. else
  612. Error(SMapKeyError, PtrUInt(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. procedure TFPGMap.InitOnPtrCompare;
  797. begin
  798. OnPtrCompare := @KeyCompare;
  799. end;
  800. function TFPGMap.KeyCompare(Key1, Key2: Pointer): Integer;
  801. begin
  802. if PKey(Key1)^ < PKey(Key2)^ then
  803. Result := -1
  804. else if PKey(Key1)^ > PKey(Key2)^ then
  805. Result := 1
  806. else
  807. Result := 0;
  808. end;
  809. function TFPGMap.KeyCustomCompare(Key1, Key2: Pointer): Integer;
  810. begin
  811. Result := FOnCompare(TKey(Key1^), TKey(Key2^));
  812. end;
  813. procedure TFPGMap.PutKey(Index: Integer; const NewKey: TKey);
  814. begin
  815. inherited PutKey(Index, @NewKey);
  816. end;
  817. procedure TFPGMap.PutData(Index: Integer; const NewData: TData);
  818. begin
  819. inherited PutData(Index, @NewData);
  820. end;
  821. procedure TFPGMap.PutKeyData(const AKey: TKey; const NewData: TData);
  822. begin
  823. inherited PutKeyData(@AKey, @NewData);
  824. end;
  825. procedure TFPGMap.SetOnCompare(NewCompare: TCompareFunc);
  826. begin
  827. FOnCompare := NewCompare;
  828. if NewCompare <> nil then
  829. OnPtrCompare := @KeyCustomCompare
  830. else
  831. InitOnPtrCompare;
  832. end;
  833. function TFPGMap.Add(const AKey: TKey): Integer;
  834. begin
  835. Result := inherited Add(@AKey);
  836. end;
  837. function TFPGMap.Add(const AKey: TKey; const AData: TData): Integer;
  838. begin
  839. Result := inherited Add(@AKey, @AData);
  840. end;
  841. function TFPGMap.Find(const AKey: TKey; var Index: Integer): Boolean;
  842. begin
  843. Result := inherited Find(@AKey, Index);
  844. end;
  845. function TFPGMap.IndexOf(const AKey: TKey): Integer;
  846. begin
  847. Result := inherited IndexOf(@AKey);
  848. end;
  849. function TFPGMap.IndexOfData(const AData: TData): Integer;
  850. begin
  851. { TODO: loop ? }
  852. Result := inherited IndexOfData(@AData);
  853. end;
  854. procedure TFPGMap.InsertKey(Index: Integer; const AKey: TKey);
  855. begin
  856. inherited InsertKey(Index, @AKey);
  857. end;
  858. procedure TFPGMap.InsertKeyData(Index: Integer; const AKey: TKey; const AData: TData);
  859. begin
  860. inherited InsertKeyData(Index, @AKey, @AData);
  861. end;
  862. function TFPGMap.Remove(const AKey: TKey): Integer;
  863. begin
  864. Result := inherited Remove(@AKey);
  865. end;
  866. {$endif}
  867. end.