fgl.pp 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248
  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. generic TFPGObjectList<T> = class(TFPSList)
  103. type public
  104. TCompareFunc = function(const Item1, Item2: T): Integer;
  105. TTypeList = array[0..MaxGListSize] of T;
  106. PTypeList = ^TTypeList;
  107. PT = ^T;
  108. var protected
  109. FOnCompare: TCompareFunc;
  110. FFreeObjects: Boolean;
  111. procedure CopyItem(Src, Dest: Pointer); override;
  112. procedure Deref(Item: Pointer); override;
  113. function Get(Index: Integer): T; {$ifdef CLASSESINLINE} inline; {$endif}
  114. function GetList: PTypeList; {$ifdef CLASSESINLINE} inline; {$endif}
  115. function ItemPtrCompare(Item1, Item2: Pointer): Integer;
  116. procedure Put(Index: Integer; const Item: T); {$ifdef CLASSESINLINE} inline; {$endif}
  117. public
  118. constructor Create(FreeObjects: Boolean = True);
  119. function Add(const Item: T): Integer; {$ifdef CLASSESINLINE} inline; {$endif}
  120. function Extract(const Item: T): T; {$ifdef CLASSESINLINE} inline; {$endif}
  121. function First: T; {$ifdef CLASSESINLINE} inline; {$endif}
  122. function IndexOf(const Item: T): Integer;
  123. procedure Insert(Index: Integer; const Item: T); {$ifdef CLASSESINLINE} inline; {$endif}
  124. function Last: T; {$ifdef CLASSESINLINE} inline; {$endif}
  125. {$info FIXME: bug #10479: implement TFPGObjectList<T>.Assign(TFPGList) to work somehow}
  126. {procedure Assign(Source: TFPGList);}
  127. function Remove(const Item: T): Integer; {$ifdef CLASSESINLINE} inline; {$endif}
  128. procedure Sort(Compare: TCompareFunc);
  129. property Items[Index: Integer]: T read Get write Put; default;
  130. property List: PTypeList read GetList;
  131. property FreeObjects: Boolean read FFreeObjects write FFreeObjects;
  132. end;
  133. generic TFPGInterfacedObjectList<T> = class(TFPSList)
  134. type public
  135. TCompareFunc = function(const Item1, Item2: T): Integer;
  136. TTypeList = array[0..MaxGListSize] of T;
  137. PTypeList = ^TTypeList;
  138. PT = ^T;
  139. var protected
  140. FOnCompare: TCompareFunc;
  141. procedure CopyItem(Src, Dest: Pointer); override;
  142. procedure Deref(Item: Pointer); override;
  143. function Get(Index: Integer): T; {$ifdef CLASSESINLINE} inline; {$endif}
  144. function GetList: PTypeList; {$ifdef CLASSESINLINE} inline; {$endif}
  145. function ItemPtrCompare(Item1, Item2: Pointer): Integer;
  146. procedure Put(Index: Integer; const Item: T); {$ifdef CLASSESINLINE} inline; {$endif}
  147. public
  148. constructor Create;
  149. function Add(const Item: T): Integer; {$ifdef CLASSESINLINE} inline; {$endif}
  150. function Extract(const Item: T): T; {$ifdef CLASSESINLINE} inline; {$endif}
  151. function First: T; {$ifdef CLASSESINLINE} inline; {$endif}
  152. function IndexOf(const Item: T): Integer;
  153. procedure Insert(Index: Integer; const Item: T); {$ifdef CLASSESINLINE} inline; {$endif}
  154. function Last: T; {$ifdef CLASSESINLINE} inline; {$endif}
  155. {$info FIXME: bug #10479: implement TFPGInterfacedObjectList<T>.Assign(TFPGList) to work somehow}
  156. {procedure Assign(Source: TFPGList);}
  157. function Remove(const Item: T): Integer; {$ifdef CLASSESINLINE} inline; {$endif}
  158. procedure Sort(Compare: TCompareFunc);
  159. property Items[Index: Integer]: T read Get write Put; default;
  160. property List: PTypeList read GetList;
  161. end;
  162. {$endif}
  163. TFPSMap = class(TFPSList)
  164. private
  165. FKeySize: Integer;
  166. FDataSize: Integer;
  167. FDuplicates: TDuplicates;
  168. FSorted: Boolean;
  169. FOnPtrCompare: TFPSListCompareFunc;
  170. procedure SetSorted(Value: Boolean);
  171. protected
  172. function BinaryCompare(Key1, Key2: Pointer): Integer;
  173. procedure CopyKey(Src, Dest: Pointer); virtual;
  174. procedure CopyData(Src, Dest: Pointer); virtual;
  175. function GetKey(Index: Integer): Pointer;
  176. function GetKeyData(AKey: Pointer): Pointer;
  177. function GetData(Index: Integer): Pointer;
  178. procedure InitOnPtrCompare; virtual;
  179. function LinearIndexOf(AKey: Pointer): Integer;
  180. procedure PutKey(Index: Integer; AKey: Pointer);
  181. procedure PutKeyData(AKey: Pointer; NewData: Pointer);
  182. procedure PutData(Index: Integer; AData: Pointer);
  183. public
  184. constructor Create(AKeySize: Integer = sizeof(Pointer);
  185. ADataSize: integer = sizeof(Pointer));
  186. function Add(AKey, AData: Pointer): Integer;
  187. function Add(AKey: Pointer): Integer;
  188. function Find(AKey: Pointer; var Index: Integer): Boolean;
  189. function IndexOf(AKey: Pointer): Integer;
  190. function IndexOfData(AData: Pointer): Integer;
  191. function Insert(Index: Integer): Pointer;
  192. procedure Insert(Index: Integer; var AKey, AData: Pointer);
  193. procedure InsertKey(Index: Integer; AKey: Pointer);
  194. procedure InsertKeyData(Index: Integer; AKey, AData: Pointer);
  195. function Remove(AKey: Pointer): Integer;
  196. procedure Sort;
  197. property Duplicates: TDuplicates read FDuplicates write FDuplicates;
  198. property KeySize: Integer read FKeySize;
  199. property DataSize: Integer read FDataSize;
  200. property Keys[Index: Integer]: Pointer read GetKey write PutKey;
  201. property Data[Index: Integer]: Pointer read GetData write PutData;
  202. property KeyData[Key: Pointer]: Pointer read GetKeyData write PutKeyData; default;
  203. property Sorted: Boolean read FSorted write SetSorted;
  204. property OnPtrCompare: TFPSListCompareFunc read FOnPtrCompare write FOnPtrCompare;
  205. end;
  206. {$ifndef VER2_0}
  207. generic TFPGMap<TKey, TData> = class(TFPSMap)
  208. type public
  209. TCompareFunc = function(const Key1, Key2: TKey): Integer;
  210. PKey = ^TKey;
  211. PData = ^TData;
  212. var protected
  213. FOnCompare: TCompareFunc;
  214. procedure CopyItem(Src, Dest: Pointer); override;
  215. procedure CopyKey(Src, Dest: Pointer); override;
  216. procedure CopyData(Src, Dest: Pointer); override;
  217. procedure Deref(Item: Pointer); override;
  218. procedure InitOnPtrCompare; override;
  219. function GetKey(Index: Integer): TKey; {$ifdef CLASSESINLINE} inline; {$endif}
  220. function GetKeyData(const AKey: TKey): TData; {$ifdef CLASSESINLINE} inline; {$endif}
  221. function GetData(Index: Integer): TData; {$ifdef CLASSESINLINE} inline; {$endif}
  222. function KeyCompare(Key1, Key2: Pointer): Integer;
  223. function KeyCustomCompare(Key1, Key2: Pointer): Integer;
  224. procedure PutKey(Index: Integer; const NewKey: TKey); {$ifdef CLASSESINLINE} inline; {$endif}
  225. procedure PutKeyData(const AKey: TKey; const NewData: TData); {$ifdef CLASSESINLINE} inline; {$endif}
  226. procedure PutData(Index: Integer; const NewData: TData); {$ifdef CLASSESINLINE} inline; {$endif}
  227. procedure SetOnCompare(NewCompare: TCompareFunc);
  228. public
  229. constructor Create;
  230. function Add(const AKey: TKey; const AData: TData): Integer; {$ifdef CLASSESINLINE} inline; {$endif}
  231. function Add(const AKey: TKey): Integer; {$ifdef CLASSESINLINE} inline; {$endif}
  232. function Find(const AKey: TKey; var Index: Integer): Boolean; {$ifdef CLASSESINLINE} inline; {$endif}
  233. function IndexOf(const AKey: TKey): Integer; {$ifdef CLASSESINLINE} inline; {$endif}
  234. function IndexOfData(const AData: TData): Integer;
  235. procedure InsertKey(Index: Integer; const AKey: TKey);
  236. procedure InsertKeyData(Index: Integer; const AKey: TKey; const AData: TData);
  237. function Remove(const AKey: TKey): Integer;
  238. property Keys[Index: Integer]: TKey read GetKey write PutKey;
  239. property Data[Index: Integer]: TData read GetData write PutData;
  240. property KeyData[const AKey: TKey]: TData read GetKeyData write PutKeyData; default;
  241. property OnCompare: TCompareFunc read FOnCompare write SetOnCompare;
  242. end;
  243. {$endif}
  244. implementation
  245. uses
  246. rtlconsts;
  247. {****************************************************************************
  248. TFPSList
  249. ****************************************************************************}
  250. constructor TFPSList.Create(AItemSize: integer);
  251. begin
  252. inherited Create;
  253. FItemSize := AItemSize;
  254. end;
  255. destructor TFPSList.Destroy;
  256. begin
  257. Clear;
  258. // Clear() does not clear the whole list; there is always a single temp entry
  259. // at the end which is never freed. Take care of that one here.
  260. FreeMem(FList);
  261. inherited Destroy;
  262. end;
  263. procedure TFPSList.CopyItem(Src, Dest: Pointer);
  264. begin
  265. System.Move(Src^, Dest^, FItemSize);
  266. end;
  267. procedure TFPSList.RaiseIndexError(Index : Integer);
  268. begin
  269. Error(SListIndexError, Index);
  270. end;
  271. function TFPSList.InternalGet(Index: Integer): Pointer;
  272. begin
  273. Result:=FList+Index*ItemSize;
  274. end;
  275. procedure TFPSList.InternalPut(Index: Integer; NewItem: Pointer);
  276. var
  277. ListItem: Pointer;
  278. begin
  279. ListItem := InternalItems[Index];
  280. CopyItem(NewItem, ListItem);
  281. end;
  282. function TFPSList.Get(Index: Integer): Pointer;
  283. begin
  284. if (Index < 0) or (Index >= FCount) then
  285. RaiseIndexError(Index);
  286. Result := InternalItems[Index];
  287. end;
  288. procedure TFPSList.Put(Index: Integer; Item: Pointer);
  289. begin
  290. if (Index < 0) or (Index >= FCount) then
  291. RaiseIndexError(Index);
  292. InternalItems[Index] := Item;
  293. end;
  294. procedure TFPSList.SetCapacity(NewCapacity: Integer);
  295. begin
  296. if (NewCapacity < FCount) or (NewCapacity > MaxListSize) then
  297. Error(SListCapacityError, NewCapacity);
  298. if NewCapacity = FCapacity then
  299. exit;
  300. ReallocMem(FList, (NewCapacity+1) * FItemSize);
  301. FillChar(InternalItems[FCapacity]^, (NewCapacity+1-FCapacity) * FItemSize, #0);
  302. FCapacity := NewCapacity;
  303. end;
  304. procedure TFPSList.Deref(Item: Pointer);
  305. begin
  306. end;
  307. procedure TFPSList.Deref(FromIndex, ToIndex: Integer);
  308. var
  309. ListItem, ListItemLast: Pointer;
  310. begin
  311. ListItem := InternalItems[FromIndex];
  312. ListItemLast := InternalItems[ToIndex];
  313. repeat
  314. Deref(ListItem);
  315. if ListItem = ListItemLast then
  316. break;
  317. ListItem := PByte(ListItem) + ItemSize;
  318. until false;
  319. end;
  320. procedure TFPSList.SetCount(NewCount: Integer);
  321. begin
  322. if (NewCount < 0) or (NewCount > MaxListSize) then
  323. Error(SListCountError, NewCount);
  324. if NewCount > FCapacity then
  325. SetCapacity(NewCount);
  326. if NewCount > FCount then
  327. FillByte(InternalItems[FCount]^, (NewCount-FCount) * FItemSize, 0)
  328. else if NewCount < FCount then
  329. Deref(NewCount, FCount-1);
  330. FCount := NewCount;
  331. end;
  332. function TFPSList.Add(Item: Pointer): Integer;
  333. begin
  334. if FCount = FCapacity then
  335. Self.Expand;
  336. CopyItem(Item, InternalItems[FCount]);
  337. Result := FCount;
  338. Inc(FCount);
  339. end;
  340. procedure TFPSList.Clear;
  341. begin
  342. if Assigned(FList) then
  343. begin
  344. SetCount(0);
  345. SetCapacity(0);
  346. end;
  347. end;
  348. procedure TFPSList.Delete(Index: Integer);
  349. var
  350. ListItem: Pointer;
  351. begin
  352. if (Index < 0) or (Index >= FCount) then
  353. Error(SListIndexError, Index);
  354. Dec(FCount);
  355. ListItem := InternalItems[Index];
  356. Deref(ListItem);
  357. System.Move(InternalItems[Index+1]^, ListItem^, (FCount - Index) * FItemSize);
  358. // Shrink the list if appropriate
  359. if (FCapacity > 256) and (FCount < FCapacity shr 2) then
  360. begin
  361. FCapacity := FCapacity shr 1;
  362. ReallocMem(FList, (FCapacity+1) * FItemSize);
  363. end;
  364. end;
  365. function TFPSList.Extract(Item: Pointer): Pointer;
  366. var
  367. i : Integer;
  368. begin
  369. Result := nil;
  370. i := IndexOf(Item);
  371. if i >= 0 then
  372. begin
  373. Result := InternalItems[i];
  374. System.Move(Result^, InternalItems[FCapacity]^, FItemSize);
  375. Delete(i);
  376. end;
  377. end;
  378. class procedure TFPSList.Error(const Msg: string; Data: PtrInt);
  379. begin
  380. raise EListError.CreateFmt(Msg,[Data]) at get_caller_addr(get_frame);
  381. end;
  382. procedure TFPSList.Exchange(Index1, Index2: Integer);
  383. begin
  384. if ((Index1 >= FCount) or (Index1 < 0)) then
  385. Error(SListIndexError, Index1);
  386. if ((Index2 >= FCount) or (Index2 < 0)) then
  387. Error(SListIndexError, Index2);
  388. InternalExchange(Index1, Index2);
  389. end;
  390. procedure TFPSList.InternalExchange(Index1, Index2: Integer);
  391. begin
  392. System.Move(InternalItems[Index1]^, InternalItems[FCapacity]^, FItemSize);
  393. System.Move(InternalItems[Index2]^, InternalItems[Index1]^, FItemSize);
  394. System.Move(InternalItems[FCapacity]^, InternalItems[Index2]^, FItemSize);
  395. end;
  396. function TFPSList.Expand: TFPSList;
  397. var
  398. IncSize : Longint;
  399. begin
  400. if FCount < FCapacity then exit;
  401. IncSize := 4;
  402. if FCapacity > 3 then IncSize := IncSize + 4;
  403. if FCapacity > 8 then IncSize := IncSize + 8;
  404. if FCapacity > 127 then Inc(IncSize, FCapacity shr 2);
  405. SetCapacity(FCapacity + IncSize);
  406. Result := Self;
  407. end;
  408. function TFPSList.First: Pointer;
  409. begin
  410. If FCount = 0 then
  411. Result := Nil
  412. else
  413. Result := InternalItems[0];
  414. end;
  415. function TFPSList.IndexOf(Item: Pointer): Integer;
  416. var
  417. ListItem: Pointer;
  418. begin
  419. Result := 0;
  420. ListItem := First;
  421. while (Result < FCount) and (CompareByte(ListItem^, Item^, FItemSize) <> 0) do
  422. begin
  423. Inc(Result);
  424. ListItem := PByte(ListItem)+FItemSize;
  425. end;
  426. if Result = FCount then Result := -1;
  427. end;
  428. function TFPSList.Insert(Index: Integer): Pointer;
  429. begin
  430. if (Index < 0) or (Index > FCount) then
  431. Error(SListIndexError, Index);
  432. if FCount = FCapacity then Self.Expand;
  433. if Index<FCount then
  434. System.Move(InternalItems[Index]^, InternalItems[Index+1]^, (FCount - Index) * FItemSize);
  435. Result := InternalItems[Index];
  436. Inc(FCount);
  437. end;
  438. procedure TFPSList.Insert(Index: Integer; Item: Pointer);
  439. begin
  440. CopyItem(Item, Insert(Index));
  441. end;
  442. function TFPSList.Last: Pointer;
  443. begin
  444. if FCount = 0 then
  445. Result := nil
  446. else
  447. Result := InternalItems[FCount - 1];
  448. end;
  449. procedure TFPSList.Move(CurIndex, NewIndex: Integer);
  450. var
  451. CurItem, NewItem, TmpItem, Src, Dest: Pointer;
  452. MoveCount: Integer;
  453. begin
  454. if (CurIndex < 0) or (CurIndex >= Count) then
  455. Error(SListIndexError, CurIndex);
  456. if (NewIndex < 0) or (NewIndex >= Count) then
  457. Error(SListIndexError, NewIndex);
  458. if CurIndex = NewIndex then
  459. exit;
  460. CurItem := InternalItems[CurIndex];
  461. NewItem := InternalItems[NewIndex];
  462. TmpItem := InternalItems[FCapacity];
  463. System.Move(CurItem^, TmpItem^, FItemSize);
  464. if NewIndex > CurIndex then
  465. begin
  466. Src := InternalItems[CurIndex+1];
  467. Dest := CurItem;
  468. MoveCount := NewIndex - CurIndex;
  469. end else begin
  470. Src := NewItem;
  471. Dest := InternalItems[NewIndex+1];
  472. MoveCount := CurIndex - NewIndex;
  473. end;
  474. System.Move(Src^, Dest^, MoveCount * FItemSize);
  475. System.Move(TmpItem^, NewItem^, FItemSize);
  476. end;
  477. function TFPSList.Remove(Item: Pointer): Integer;
  478. begin
  479. Result := IndexOf(Item);
  480. if Result <> -1 then
  481. Delete(Result);
  482. end;
  483. procedure TFPSList.Pack;
  484. var
  485. NewCount,
  486. i : integer;
  487. pdest,
  488. psrc : Pointer;
  489. begin
  490. NewCount:=0;
  491. psrc:=First;
  492. pdest:=psrc;
  493. For I:=0 To FCount-1 Do
  494. begin
  495. if assigned(pointer(psrc^)) then
  496. begin
  497. System.Move(psrc^, pdest^, FItemSize);
  498. inc(pdest);
  499. inc(NewCount);
  500. end;
  501. inc(psrc);
  502. end;
  503. FCount:=NewCount;
  504. end;
  505. // Needed by Sort method.
  506. procedure TFPSList.QuickSort(L, R: Integer; Compare: TFPSListCompareFunc);
  507. var
  508. I, J, P: Integer;
  509. PivotItem: Pointer;
  510. begin
  511. repeat
  512. I := L;
  513. J := R;
  514. P := (L + R) div 2;
  515. repeat
  516. PivotItem := InternalItems[P];
  517. while Compare(PivotItem, InternalItems[I]) > 0 do
  518. Inc(I);
  519. while Compare(PivotItem, InternalItems[J]) < 0 do
  520. Dec(J);
  521. if I <= J then
  522. begin
  523. InternalExchange(I, J);
  524. if P = I then
  525. P := J
  526. else if P = J then
  527. P := I;
  528. Inc(I);
  529. Dec(J);
  530. end;
  531. until I > J;
  532. if L < J then
  533. QuickSort(L, J, Compare);
  534. L := I;
  535. until I >= R;
  536. end;
  537. procedure TFPSList.Sort(Compare: TFPSListCompareFunc);
  538. begin
  539. if not Assigned(FList) or (FCount < 2) then exit;
  540. QuickSort(0, FCount-1, Compare);
  541. end;
  542. procedure TFPSList.Assign(Obj: TFPSList);
  543. var
  544. i: Integer;
  545. begin
  546. if Obj.ItemSize <> FItemSize then
  547. Error(SListItemSizeError, 0);
  548. Clear;
  549. for I := 0 to Obj.Count - 1 do
  550. Add(Obj[i]);
  551. end;
  552. {$ifndef VER2_0}
  553. {****************************************************************************}
  554. {* TFPGList *}
  555. {****************************************************************************}
  556. constructor TFPGList.Create;
  557. begin
  558. inherited Create(sizeof(T));
  559. end;
  560. procedure TFPGList.CopyItem(Src, Dest: Pointer);
  561. begin
  562. T(Dest^) := T(Src^);
  563. end;
  564. procedure TFPGList.Deref(Item: Pointer);
  565. begin
  566. Finalize(T(Item^));
  567. end;
  568. function TFPGList.Get(Index: Integer): T;
  569. begin
  570. Result := T(inherited Get(Index)^);
  571. end;
  572. function TFPGList.GetList: PTypeList;
  573. begin
  574. Result := PTypeList(FList);
  575. end;
  576. function TFPGList.ItemPtrCompare(Item1, Item2: Pointer): Integer;
  577. begin
  578. Result := FOnCompare(T(Item1^), T(Item2^));
  579. end;
  580. procedure TFPGList.Put(Index: Integer; const Item: T);
  581. begin
  582. inherited Put(Index, @Item);
  583. end;
  584. function TFPGList.Add(const Item: T): Integer;
  585. begin
  586. Result := inherited Add(@Item);
  587. end;
  588. function TFPGList.Extract(const Item: T): T;
  589. var
  590. ResPtr: Pointer;
  591. begin
  592. ResPtr := inherited Extract(@Item);
  593. if ResPtr <> nil then
  594. Result := T(ResPtr^)
  595. else
  596. FillByte(Result, 0, sizeof(T));
  597. end;
  598. function TFPGList.First: T;
  599. begin
  600. Result := T(inherited First^);
  601. end;
  602. function TFPGList.IndexOf(const Item: T): Integer;
  603. begin
  604. Result := 0;
  605. {$info TODO: fix inlining to work! InternalItems[Result]^}
  606. while (Result < FCount) and (PT(FList)[Result] <> Item) do
  607. Inc(Result);
  608. if Result = FCount then
  609. Result := -1;
  610. end;
  611. procedure TFPGList.Insert(Index: Integer; const Item: T);
  612. begin
  613. T(inherited Insert(Index)^) := Item;
  614. end;
  615. function TFPGList.Last: T;
  616. begin
  617. Result := T(inherited Last^);
  618. end;
  619. function TFPGList.Remove(const Item: T): Integer;
  620. begin
  621. Result := IndexOf(Item);
  622. if Result >= 0 then
  623. Delete(Result);
  624. end;
  625. procedure TFPGList.Sort(Compare: TCompareFunc);
  626. begin
  627. FOnCompare := Compare;
  628. inherited Sort(@ItemPtrCompare);
  629. end;
  630. {****************************************************************************}
  631. {* TFPGObjectList *}
  632. {****************************************************************************}
  633. constructor TFPGObjectList.Create(FreeObjects: Boolean);
  634. begin
  635. inherited Create;
  636. FFreeObjects := FreeObjects;
  637. end;
  638. procedure TFPGObjectList.CopyItem(Src, Dest: Pointer);
  639. begin
  640. T(Dest^) := T(Src^);
  641. {if TObject(Dest^) is TInterfacedObject then
  642. T(Dest^)._AddRef;}
  643. end;
  644. procedure TFPGObjectList.Deref(Item: Pointer);
  645. begin
  646. {if TObject(Item^) is TInterfacedObject then
  647. T(Item^)._Release
  648. else}
  649. if FFreeObjects then
  650. T(Item^).Free;
  651. end;
  652. function TFPGObjectList.Get(Index: Integer): T;
  653. begin
  654. Result := T(inherited Get(Index)^);
  655. end;
  656. function TFPGObjectList.GetList: PTypeList;
  657. begin
  658. Result := PTypeList(FList);
  659. end;
  660. function TFPGObjectList.ItemPtrCompare(Item1, Item2: Pointer): Integer;
  661. begin
  662. Result := FOnCompare(T(Item1^), T(Item2^));
  663. end;
  664. procedure TFPGObjectList.Put(Index: Integer; const Item: T);
  665. begin
  666. inherited Put(Index, @Item);
  667. end;
  668. function TFPGObjectList.Add(const Item: T): Integer;
  669. begin
  670. Result := inherited Add(@Item);
  671. end;
  672. function TFPGObjectList.Extract(const Item: T): T;
  673. var
  674. ResPtr: Pointer;
  675. begin
  676. ResPtr := inherited Extract(@Item);
  677. if ResPtr <> nil then
  678. Result := T(ResPtr^)
  679. else
  680. FillByte(Result, 0, sizeof(T));
  681. end;
  682. function TFPGObjectList.First: T;
  683. begin
  684. Result := T(inherited First^);
  685. end;
  686. function TFPGObjectList.IndexOf(const Item: T): Integer;
  687. begin
  688. Result := 0;
  689. {$info TODO: fix inlining to work! InternalItems[Result]^}
  690. while (Result < FCount) and (PT(FList)[Result] <> Item) do
  691. Inc(Result);
  692. if Result = FCount then
  693. Result := -1;
  694. end;
  695. procedure TFPGObjectList.Insert(Index: Integer; const Item: T);
  696. begin
  697. T(inherited Insert(Index)^) := Item;
  698. end;
  699. function TFPGObjectList.Last: T;
  700. begin
  701. Result := T(inherited Last^);
  702. end;
  703. function TFPGObjectList.Remove(const Item: T): Integer;
  704. begin
  705. Result := IndexOf(Item);
  706. if Result >= 0 then
  707. Delete(Result);
  708. end;
  709. procedure TFPGObjectList.Sort(Compare: TCompareFunc);
  710. begin
  711. FOnCompare := Compare;
  712. inherited Sort(@ItemPtrCompare);
  713. end;
  714. {****************************************************************************}
  715. {* TFPGInterfacedObjectList *}
  716. {****************************************************************************}
  717. constructor TFPGInterfacedObjectList.Create;
  718. begin
  719. inherited Create;
  720. end;
  721. procedure TFPGInterfacedObjectList.CopyItem(Src, Dest: Pointer);
  722. begin
  723. T(Dest^) := T(Src^);
  724. if Assigned(Pointer(Dest^)) then
  725. T(Dest^)._AddRef;
  726. end;
  727. procedure TFPGInterfacedObjectList.Deref(Item: Pointer);
  728. begin
  729. if Assigned(Pointer(Item^)) then
  730. T(Item^)._Release;
  731. end;
  732. function TFPGInterfacedObjectList.Get(Index: Integer): T;
  733. begin
  734. Result := T(inherited Get(Index)^);
  735. end;
  736. function TFPGInterfacedObjectList.GetList: PTypeList;
  737. begin
  738. Result := PTypeList(FList);
  739. end;
  740. function TFPGInterfacedObjectList.ItemPtrCompare(Item1, Item2: Pointer): Integer;
  741. begin
  742. Result := FOnCompare(T(Item1^), T(Item2^));
  743. end;
  744. procedure TFPGInterfacedObjectList.Put(Index: Integer; const Item: T);
  745. begin
  746. inherited Put(Index, @Item);
  747. end;
  748. function TFPGInterfacedObjectList.Add(const Item: T): Integer;
  749. begin
  750. Result := inherited Add(@Item);
  751. end;
  752. function TFPGInterfacedObjectList.Extract(const Item: T): T;
  753. var
  754. ResPtr: Pointer;
  755. begin
  756. ResPtr := inherited Extract(@Item);
  757. if ResPtr <> nil then
  758. Result := T(ResPtr^)
  759. else
  760. FillByte(Result, 0, sizeof(T));
  761. end;
  762. function TFPGInterfacedObjectList.First: T;
  763. begin
  764. Result := T(inherited First^);
  765. end;
  766. function TFPGInterfacedObjectList.IndexOf(const Item: T): Integer;
  767. begin
  768. Result := 0;
  769. {$info TODO: fix inlining to work! InternalItems[Result]^}
  770. while (Result < FCount) and (PT(FList)[Result] <> Item) do
  771. Inc(Result);
  772. if Result = FCount then
  773. Result := -1;
  774. end;
  775. procedure TFPGInterfacedObjectList.Insert(Index: Integer; const Item: T);
  776. begin
  777. T(inherited Insert(Index)^) := Item;
  778. end;
  779. function TFPGInterfacedObjectList.Last: T;
  780. begin
  781. Result := T(inherited Last^);
  782. end;
  783. function TFPGInterfacedObjectList.Remove(const Item: T): Integer;
  784. begin
  785. Result := IndexOf(Item);
  786. if Result >= 0 then
  787. Delete(Result);
  788. end;
  789. procedure TFPGInterfacedObjectList.Sort(Compare: TCompareFunc);
  790. begin
  791. FOnCompare := Compare;
  792. inherited Sort(@ItemPtrCompare);
  793. end;
  794. {$endif}
  795. {****************************************************************************
  796. TFPSMap
  797. ****************************************************************************}
  798. constructor TFPSMap.Create(AKeySize: Integer; ADataSize: integer);
  799. begin
  800. inherited Create(AKeySize+ADataSize);
  801. FKeySize := AKeySize;
  802. FDataSize := ADataSize;
  803. InitOnPtrCompare;
  804. end;
  805. procedure TFPSMap.CopyKey(Src, Dest: Pointer);
  806. begin
  807. System.Move(Src^, Dest^, FKeySize);
  808. end;
  809. procedure TFPSMap.CopyData(Src, Dest: Pointer);
  810. begin
  811. System.Move(Src^, Dest^, FDataSize);
  812. end;
  813. function TFPSMap.BinaryCompare(Key1, Key2: Pointer): Integer;
  814. begin
  815. Result := CompareByte(Key1^, Key2^, FKeySize);
  816. end;
  817. function TFPSMap.GetKey(Index: Integer): Pointer;
  818. begin
  819. Result := Items[Index];
  820. end;
  821. function TFPSMap.GetData(Index: Integer): Pointer;
  822. begin
  823. Result := PByte(Items[Index])+FKeySize;
  824. end;
  825. function TFPSMap.GetKeyData(AKey: Pointer): Pointer;
  826. var
  827. I: Integer;
  828. begin
  829. I := IndexOf(AKey);
  830. if I >= 0 then
  831. Result := InternalItems[I]+FKeySize
  832. else
  833. Error(SMapKeyError, PtrUInt(AKey));
  834. end;
  835. procedure TFPSMap.InitOnPtrCompare;
  836. begin
  837. FOnPtrCompare := @BinaryCompare;
  838. end;
  839. procedure TFPSMap.PutKey(Index: Integer; AKey: Pointer);
  840. begin
  841. if FSorted then
  842. Error(SSortedListError, 0);
  843. CopyKey(AKey, Items[Index]);
  844. end;
  845. procedure TFPSMap.PutData(Index: Integer; AData: Pointer);
  846. begin
  847. CopyData(AData, PByte(Items[Index])+FKeySize);
  848. end;
  849. procedure TFPSMap.PutKeyData(AKey: Pointer; NewData: Pointer);
  850. var
  851. I: Integer;
  852. begin
  853. I := IndexOf(AKey);
  854. if I >= 0 then
  855. Data[I] := NewData
  856. else
  857. Add(AKey, NewData);
  858. end;
  859. procedure TFPSMap.SetSorted(Value: Boolean);
  860. begin
  861. if Value = FSorted then exit;
  862. FSorted := Value;
  863. if Value then Sort;
  864. end;
  865. function TFPSMap.Add(AKey: Pointer): Integer;
  866. begin
  867. if Sorted then
  868. begin
  869. if Find(AKey, Result) then
  870. case Duplicates of
  871. dupIgnore: exit;
  872. dupError: Error(SDuplicateItem, 0)
  873. end;
  874. end else
  875. Result := Count;
  876. CopyKey(AKey, inherited Insert(Result));
  877. end;
  878. function TFPSMap.Add(AKey, AData: Pointer): Integer;
  879. begin
  880. Result := Add(AKey);
  881. Data[Result] := AData;
  882. end;
  883. function TFPSMap.Find(AKey: Pointer; var Index: Integer): Boolean;
  884. { Searches for the first item <= Key, returns True if exact match,
  885. sets index to the index f the found string. }
  886. var
  887. I,L,R,Dir: Integer;
  888. begin
  889. Result := false;
  890. // Use binary search.
  891. L := 0;
  892. R := FCount-1;
  893. while L<=R do
  894. begin
  895. I := (L+R) div 2;
  896. Dir := FOnPtrCompare(Items[I], AKey);
  897. if Dir < 0 then
  898. L := I+1
  899. else begin
  900. R := I-1;
  901. if Dir = 0 then
  902. begin
  903. Result := true;
  904. if Duplicates <> dupAccept then
  905. L := I;
  906. end;
  907. end;
  908. end;
  909. Index := L;
  910. end;
  911. function TFPSMap.LinearIndexOf(AKey: Pointer): Integer;
  912. var
  913. ListItem: Pointer;
  914. begin
  915. Result := 0;
  916. ListItem := First;
  917. while (Result < FCount) and (FOnPtrCompare(ListItem, AKey) <> 0) do
  918. begin
  919. Inc(Result);
  920. ListItem := PByte(ListItem)+FItemSize;
  921. end;
  922. if Result = FCount then Result := -1;
  923. end;
  924. function TFPSMap.IndexOf(AKey: Pointer): Integer;
  925. begin
  926. if Sorted then
  927. begin
  928. if not Find(AKey, Result) then
  929. Result := -1;
  930. end else
  931. Result := LinearIndexOf(AKey);
  932. end;
  933. function TFPSMap.IndexOfData(AData: Pointer): Integer;
  934. var
  935. ListItem: Pointer;
  936. begin
  937. Result := 0;
  938. ListItem := First+FKeySize;
  939. while (Result < FCount) and (CompareByte(ListItem^, AData^, FDataSize) <> 0) do
  940. begin
  941. Inc(Result);
  942. ListItem := PByte(ListItem)+FItemSize;
  943. end;
  944. if Result = FCount then Result := -1;
  945. end;
  946. function TFPSMap.Insert(Index: Integer): Pointer;
  947. begin
  948. if FSorted then
  949. Error(SSortedListError, 0);
  950. Result := inherited Insert(Index);
  951. end;
  952. procedure TFPSMap.Insert(Index: Integer; var AKey, AData: Pointer);
  953. begin
  954. AKey := Insert(Index);
  955. AData := PByte(AKey) + FKeySize;
  956. end;
  957. procedure TFPSMap.InsertKey(Index: Integer; AKey: Pointer);
  958. begin
  959. CopyKey(AKey, Insert(Index));
  960. end;
  961. procedure TFPSMap.InsertKeyData(Index: Integer; AKey, AData: Pointer);
  962. var
  963. ListItem: Pointer;
  964. begin
  965. ListItem := Insert(Index);
  966. CopyKey(AKey, ListItem);
  967. CopyData(AData, PByte(ListItem)+FKeySize);
  968. end;
  969. function TFPSMap.Remove(AKey: Pointer): Integer;
  970. begin
  971. Result := IndexOf(AKey);
  972. if Result >= 0 then
  973. Delete(Result);
  974. end;
  975. procedure TFPSMap.Sort;
  976. begin
  977. inherited Sort(FOnPtrCompare);
  978. end;
  979. {****************************************************************************
  980. TFPGMap
  981. ****************************************************************************}
  982. {$ifndef VER2_0}
  983. constructor TFPGMap.Create;
  984. begin
  985. inherited Create(SizeOf(TKey), SizeOf(TData));
  986. end;
  987. procedure TFPGMap.CopyItem(Src, Dest: Pointer);
  988. begin
  989. CopyKey(Src, Dest);
  990. CopyData(PByte(Src)+KeySize, PByte(Dest)+KeySize);
  991. end;
  992. procedure TFPGMap.CopyKey(Src, Dest: Pointer);
  993. begin
  994. TKey(Dest^) := TKey(Src^);
  995. end;
  996. procedure TFPGMap.CopyData(Src, Dest: Pointer);
  997. begin
  998. TData(Dest^) := TData(Src^);
  999. end;
  1000. procedure TFPGMap.Deref(Item: Pointer);
  1001. begin
  1002. Finalize(TKey(Item^));
  1003. Finalize(TData(Pointer(PByte(Item)+KeySize)^));
  1004. end;
  1005. function TFPGMap.GetKey(Index: Integer): TKey;
  1006. begin
  1007. Result := TKey(inherited GetKey(Index)^);
  1008. end;
  1009. function TFPGMap.GetData(Index: Integer): TData;
  1010. begin
  1011. Result := TData(inherited GetData(Index)^);
  1012. end;
  1013. function TFPGMap.GetKeyData(const AKey: TKey): TData;
  1014. begin
  1015. Result := TData(inherited GetKeyData(@AKey)^);
  1016. end;
  1017. procedure TFPGMap.InitOnPtrCompare;
  1018. begin
  1019. OnPtrCompare := @KeyCompare;
  1020. end;
  1021. function TFPGMap.KeyCompare(Key1, Key2: Pointer): Integer;
  1022. begin
  1023. if PKey(Key1)^ < PKey(Key2)^ then
  1024. Result := -1
  1025. else if PKey(Key1)^ > PKey(Key2)^ then
  1026. Result := 1
  1027. else
  1028. Result := 0;
  1029. end;
  1030. function TFPGMap.KeyCustomCompare(Key1, Key2: Pointer): Integer;
  1031. begin
  1032. Result := FOnCompare(TKey(Key1^), TKey(Key2^));
  1033. end;
  1034. procedure TFPGMap.PutKey(Index: Integer; const NewKey: TKey);
  1035. begin
  1036. inherited PutKey(Index, @NewKey);
  1037. end;
  1038. procedure TFPGMap.PutData(Index: Integer; const NewData: TData);
  1039. begin
  1040. inherited PutData(Index, @NewData);
  1041. end;
  1042. procedure TFPGMap.PutKeyData(const AKey: TKey; const NewData: TData);
  1043. begin
  1044. inherited PutKeyData(@AKey, @NewData);
  1045. end;
  1046. procedure TFPGMap.SetOnCompare(NewCompare: TCompareFunc);
  1047. begin
  1048. FOnCompare := NewCompare;
  1049. if NewCompare <> nil then
  1050. OnPtrCompare := @KeyCustomCompare
  1051. else
  1052. InitOnPtrCompare;
  1053. end;
  1054. function TFPGMap.Add(const AKey: TKey): Integer;
  1055. begin
  1056. Result := inherited Add(@AKey);
  1057. end;
  1058. function TFPGMap.Add(const AKey: TKey; const AData: TData): Integer;
  1059. begin
  1060. Result := inherited Add(@AKey, @AData);
  1061. end;
  1062. function TFPGMap.Find(const AKey: TKey; var Index: Integer): Boolean;
  1063. begin
  1064. Result := inherited Find(@AKey, Index);
  1065. end;
  1066. function TFPGMap.IndexOf(const AKey: TKey): Integer;
  1067. begin
  1068. Result := inherited IndexOf(@AKey);
  1069. end;
  1070. function TFPGMap.IndexOfData(const AData: TData): Integer;
  1071. begin
  1072. { TODO: loop ? }
  1073. Result := inherited IndexOfData(@AData);
  1074. end;
  1075. procedure TFPGMap.InsertKey(Index: Integer; const AKey: TKey);
  1076. begin
  1077. inherited InsertKey(Index, @AKey);
  1078. end;
  1079. procedure TFPGMap.InsertKeyData(Index: Integer; const AKey: TKey; const AData: TData);
  1080. begin
  1081. inherited InsertKeyData(Index, @AKey, @AData);
  1082. end;
  1083. function TFPGMap.Remove(const AKey: TKey): Integer;
  1084. begin
  1085. Result := inherited Remove(@AKey);
  1086. end;
  1087. {$endif}
  1088. end.