fgl.pp 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251
  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 > FCount then
  325. begin
  326. if NewCount > FCapacity then
  327. SetCapacity(NewCount);
  328. if NewCount > FCount then
  329. FillByte(InternalItems[FCount]^, (NewCount-FCount) * FItemSize, 0)
  330. else if NewCount < FCount then
  331. Deref(NewCount, FCount-1);
  332. end;
  333. FCount := NewCount;
  334. end;
  335. function TFPSList.Add(Item: Pointer): Integer;
  336. begin
  337. if FCount = FCapacity then
  338. Self.Expand;
  339. CopyItem(Item, InternalItems[FCount]);
  340. Result := FCount;
  341. Inc(FCount);
  342. end;
  343. procedure TFPSList.Clear;
  344. begin
  345. if Assigned(FList) then
  346. begin
  347. SetCount(0);
  348. SetCapacity(0);
  349. end;
  350. end;
  351. procedure TFPSList.Delete(Index: Integer);
  352. var
  353. ListItem: Pointer;
  354. begin
  355. if (Index < 0) or (Index >= FCount) then
  356. Error(SListIndexError, Index);
  357. Dec(FCount);
  358. ListItem := InternalItems[Index];
  359. Deref(ListItem);
  360. System.Move(InternalItems[Index+1]^, ListItem^, (FCount - Index) * FItemSize);
  361. // Shrink the list if appropriate
  362. if (FCapacity > 256) and (FCount < FCapacity shr 2) then
  363. begin
  364. FCapacity := FCapacity shr 1;
  365. ReallocMem(FList, (FCapacity+1) * FItemSize);
  366. end;
  367. end;
  368. function TFPSList.Extract(Item: Pointer): Pointer;
  369. var
  370. i : Integer;
  371. begin
  372. Result := nil;
  373. i := IndexOf(Item);
  374. if i >= 0 then
  375. begin
  376. Result := InternalItems[i];
  377. System.Move(Result^, InternalItems[FCapacity]^, FItemSize);
  378. Delete(i);
  379. end;
  380. end;
  381. class procedure TFPSList.Error(const Msg: string; Data: PtrInt);
  382. begin
  383. raise EListError.CreateFmt(Msg,[Data]) at get_caller_addr(get_frame);
  384. end;
  385. procedure TFPSList.Exchange(Index1, Index2: Integer);
  386. begin
  387. if ((Index1 >= FCount) or (Index1 < 0)) then
  388. Error(SListIndexError, Index1);
  389. if ((Index2 >= FCount) or (Index2 < 0)) then
  390. Error(SListIndexError, Index2);
  391. InternalExchange(Index1, Index2);
  392. end;
  393. procedure TFPSList.InternalExchange(Index1, Index2: Integer);
  394. begin
  395. System.Move(InternalItems[Index1]^, InternalItems[FCapacity]^, FItemSize);
  396. System.Move(InternalItems[Index2]^, InternalItems[Index1]^, FItemSize);
  397. System.Move(InternalItems[FCapacity]^, InternalItems[Index2]^, FItemSize);
  398. end;
  399. function TFPSList.Expand: TFPSList;
  400. var
  401. IncSize : Longint;
  402. begin
  403. if FCount < FCapacity then exit;
  404. IncSize := 4;
  405. if FCapacity > 3 then IncSize := IncSize + 4;
  406. if FCapacity > 8 then IncSize := IncSize + 8;
  407. if FCapacity > 127 then Inc(IncSize, FCapacity shr 2);
  408. SetCapacity(FCapacity + IncSize);
  409. Result := Self;
  410. end;
  411. function TFPSList.First: Pointer;
  412. begin
  413. If FCount = 0 then
  414. Result := Nil
  415. else
  416. Result := InternalItems[0];
  417. end;
  418. function TFPSList.IndexOf(Item: Pointer): Integer;
  419. var
  420. ListItem: Pointer;
  421. begin
  422. Result := 0;
  423. ListItem := First;
  424. while (Result < FCount) and (CompareByte(ListItem^, Item^, FItemSize) <> 0) do
  425. begin
  426. Inc(Result);
  427. ListItem := PByte(ListItem)+FItemSize;
  428. end;
  429. if Result = FCount then Result := -1;
  430. end;
  431. function TFPSList.Insert(Index: Integer): Pointer;
  432. begin
  433. if (Index < 0) or (Index > FCount) then
  434. Error(SListIndexError, Index);
  435. if FCount = FCapacity then Self.Expand;
  436. if Index<FCount then
  437. System.Move(InternalItems[Index]^, InternalItems[Index+1]^, (FCount - Index) * FItemSize);
  438. Result := InternalItems[Index];
  439. Inc(FCount);
  440. end;
  441. procedure TFPSList.Insert(Index: Integer; Item: Pointer);
  442. begin
  443. CopyItem(Item, Insert(Index));
  444. end;
  445. function TFPSList.Last: Pointer;
  446. begin
  447. if FCount = 0 then
  448. Result := nil
  449. else
  450. Result := InternalItems[FCount - 1];
  451. end;
  452. procedure TFPSList.Move(CurIndex, NewIndex: Integer);
  453. var
  454. CurItem, NewItem, TmpItem, Src, Dest: Pointer;
  455. MoveCount: Integer;
  456. begin
  457. if (CurIndex < 0) or (CurIndex >= Count) then
  458. Error(SListIndexError, CurIndex);
  459. if (NewIndex < 0) or (NewIndex >= Count) then
  460. Error(SListIndexError, NewIndex);
  461. if CurIndex = NewIndex then
  462. exit;
  463. CurItem := InternalItems[CurIndex];
  464. NewItem := InternalItems[NewIndex];
  465. TmpItem := InternalItems[FCapacity];
  466. System.Move(CurItem^, TmpItem^, FItemSize);
  467. if NewIndex > CurIndex then
  468. begin
  469. Src := InternalItems[CurIndex+1];
  470. Dest := CurItem;
  471. MoveCount := NewIndex - CurIndex;
  472. end else begin
  473. Src := NewItem;
  474. Dest := InternalItems[NewIndex+1];
  475. MoveCount := CurIndex - NewIndex;
  476. end;
  477. System.Move(Src^, Dest^, MoveCount * FItemSize);
  478. System.Move(TmpItem^, NewItem^, FItemSize);
  479. end;
  480. function TFPSList.Remove(Item: Pointer): Integer;
  481. begin
  482. Result := IndexOf(Item);
  483. if Result <> -1 then
  484. Delete(Result);
  485. end;
  486. procedure TFPSList.Pack;
  487. var
  488. NewCount,
  489. i : integer;
  490. pdest,
  491. psrc : Pointer;
  492. begin
  493. NewCount:=0;
  494. psrc:=First;
  495. pdest:=psrc;
  496. For I:=0 To FCount-1 Do
  497. begin
  498. if assigned(pointer(psrc^)) then
  499. begin
  500. System.Move(psrc^, pdest^, FItemSize);
  501. inc(pdest);
  502. inc(NewCount);
  503. end;
  504. inc(psrc);
  505. end;
  506. FCount:=NewCount;
  507. end;
  508. // Needed by Sort method.
  509. procedure TFPSList.QuickSort(L, R: Integer; Compare: TFPSListCompareFunc);
  510. var
  511. I, J, P: Integer;
  512. PivotItem: Pointer;
  513. begin
  514. repeat
  515. I := L;
  516. J := R;
  517. P := (L + R) div 2;
  518. repeat
  519. PivotItem := InternalItems[P];
  520. while Compare(PivotItem, InternalItems[I]) > 0 do
  521. Inc(I);
  522. while Compare(PivotItem, InternalItems[J]) < 0 do
  523. Dec(J);
  524. if I <= J then
  525. begin
  526. InternalExchange(I, J);
  527. if P = I then
  528. P := J
  529. else if P = J then
  530. P := I;
  531. Inc(I);
  532. Dec(J);
  533. end;
  534. until I > J;
  535. if L < J then
  536. QuickSort(L, J, Compare);
  537. L := I;
  538. until I >= R;
  539. end;
  540. procedure TFPSList.Sort(Compare: TFPSListCompareFunc);
  541. begin
  542. if not Assigned(FList) or (FCount < 2) then exit;
  543. QuickSort(0, FCount-1, Compare);
  544. end;
  545. procedure TFPSList.Assign(Obj: TFPSList);
  546. var
  547. i: Integer;
  548. begin
  549. if Obj.ItemSize <> FItemSize then
  550. Error(SListItemSizeError, 0);
  551. Clear;
  552. for I := 0 to Obj.Count - 1 do
  553. Add(Obj[i]);
  554. end;
  555. {$ifndef VER2_0}
  556. {****************************************************************************}
  557. {* TFPGList *}
  558. {****************************************************************************}
  559. constructor TFPGList.Create;
  560. begin
  561. inherited Create(sizeof(T));
  562. end;
  563. procedure TFPGList.CopyItem(Src, Dest: Pointer);
  564. begin
  565. T(Dest^) := T(Src^);
  566. end;
  567. procedure TFPGList.Deref(Item: Pointer);
  568. begin
  569. Finalize(T(Item^));
  570. end;
  571. function TFPGList.Get(Index: Integer): T;
  572. begin
  573. Result := T(inherited Get(Index)^);
  574. end;
  575. function TFPGList.GetList: PTypeList;
  576. begin
  577. Result := PTypeList(FList);
  578. end;
  579. function TFPGList.ItemPtrCompare(Item1, Item2: Pointer): Integer;
  580. begin
  581. Result := FOnCompare(T(Item1^), T(Item2^));
  582. end;
  583. procedure TFPGList.Put(Index: Integer; const Item: T);
  584. begin
  585. inherited Put(Index, @Item);
  586. end;
  587. function TFPGList.Add(const Item: T): Integer;
  588. begin
  589. Result := inherited Add(@Item);
  590. end;
  591. function TFPGList.Extract(const Item: T): T;
  592. var
  593. ResPtr: Pointer;
  594. begin
  595. ResPtr := inherited Extract(@Item);
  596. if ResPtr <> nil then
  597. Result := T(ResPtr^)
  598. else
  599. FillByte(Result, 0, sizeof(T));
  600. end;
  601. function TFPGList.First: T;
  602. begin
  603. Result := T(inherited First^);
  604. end;
  605. function TFPGList.IndexOf(const Item: T): Integer;
  606. begin
  607. Result := 0;
  608. {$info TODO: fix inlining to work! InternalItems[Result]^}
  609. while (Result < FCount) and (PT(FList)[Result] <> Item) do
  610. Inc(Result);
  611. if Result = FCount then
  612. Result := -1;
  613. end;
  614. procedure TFPGList.Insert(Index: Integer; const Item: T);
  615. begin
  616. T(inherited Insert(Index)^) := Item;
  617. end;
  618. function TFPGList.Last: T;
  619. begin
  620. Result := T(inherited Last^);
  621. end;
  622. function TFPGList.Remove(const Item: T): Integer;
  623. begin
  624. Result := IndexOf(Item);
  625. if Result >= 0 then
  626. Delete(Result);
  627. end;
  628. procedure TFPGList.Sort(Compare: TCompareFunc);
  629. begin
  630. FOnCompare := Compare;
  631. inherited Sort(@ItemPtrCompare);
  632. end;
  633. {****************************************************************************}
  634. {* TFPGObjectList *}
  635. {****************************************************************************}
  636. constructor TFPGObjectList.Create(FreeObjects: Boolean);
  637. begin
  638. inherited Create;
  639. FFreeObjects := FreeObjects;
  640. end;
  641. procedure TFPGObjectList.CopyItem(Src, Dest: Pointer);
  642. begin
  643. T(Dest^) := T(Src^);
  644. {if TObject(Dest^) is TInterfacedObject then
  645. T(Dest^)._AddRef;}
  646. end;
  647. procedure TFPGObjectList.Deref(Item: Pointer);
  648. begin
  649. {if TObject(Item^) is TInterfacedObject then
  650. T(Item^)._Release
  651. else}
  652. if FFreeObjects then
  653. T(Item^).Free;
  654. end;
  655. function TFPGObjectList.Get(Index: Integer): T;
  656. begin
  657. Result := T(inherited Get(Index)^);
  658. end;
  659. function TFPGObjectList.GetList: PTypeList;
  660. begin
  661. Result := PTypeList(FList);
  662. end;
  663. function TFPGObjectList.ItemPtrCompare(Item1, Item2: Pointer): Integer;
  664. begin
  665. Result := FOnCompare(T(Item1^), T(Item2^));
  666. end;
  667. procedure TFPGObjectList.Put(Index: Integer; const Item: T);
  668. begin
  669. inherited Put(Index, @Item);
  670. end;
  671. function TFPGObjectList.Add(const Item: T): Integer;
  672. begin
  673. Result := inherited Add(@Item);
  674. end;
  675. function TFPGObjectList.Extract(const Item: T): T;
  676. var
  677. ResPtr: Pointer;
  678. begin
  679. ResPtr := inherited Extract(@Item);
  680. if ResPtr <> nil then
  681. Result := T(ResPtr^)
  682. else
  683. FillByte(Result, 0, sizeof(T));
  684. end;
  685. function TFPGObjectList.First: T;
  686. begin
  687. Result := T(inherited First^);
  688. end;
  689. function TFPGObjectList.IndexOf(const Item: T): Integer;
  690. begin
  691. Result := 0;
  692. {$info TODO: fix inlining to work! InternalItems[Result]^}
  693. while (Result < FCount) and (PT(FList)[Result] <> Item) do
  694. Inc(Result);
  695. if Result = FCount then
  696. Result := -1;
  697. end;
  698. procedure TFPGObjectList.Insert(Index: Integer; const Item: T);
  699. begin
  700. T(inherited Insert(Index)^) := Item;
  701. end;
  702. function TFPGObjectList.Last: T;
  703. begin
  704. Result := T(inherited Last^);
  705. end;
  706. function TFPGObjectList.Remove(const Item: T): Integer;
  707. begin
  708. Result := IndexOf(Item);
  709. if Result >= 0 then
  710. Delete(Result);
  711. end;
  712. procedure TFPGObjectList.Sort(Compare: TCompareFunc);
  713. begin
  714. FOnCompare := Compare;
  715. inherited Sort(@ItemPtrCompare);
  716. end;
  717. {****************************************************************************}
  718. {* TFPGInterfacedObjectList *}
  719. {****************************************************************************}
  720. constructor TFPGInterfacedObjectList.Create;
  721. begin
  722. inherited Create;
  723. end;
  724. procedure TFPGInterfacedObjectList.CopyItem(Src, Dest: Pointer);
  725. begin
  726. T(Dest^) := T(Src^);
  727. if Assigned(Pointer(Dest^)) then
  728. T(Dest^)._AddRef;
  729. end;
  730. procedure TFPGInterfacedObjectList.Deref(Item: Pointer);
  731. begin
  732. if Assigned(Pointer(Item^)) then
  733. T(Item^)._Release;
  734. end;
  735. function TFPGInterfacedObjectList.Get(Index: Integer): T;
  736. begin
  737. Result := T(inherited Get(Index)^);
  738. end;
  739. function TFPGInterfacedObjectList.GetList: PTypeList;
  740. begin
  741. Result := PTypeList(FList);
  742. end;
  743. function TFPGInterfacedObjectList.ItemPtrCompare(Item1, Item2: Pointer): Integer;
  744. begin
  745. Result := FOnCompare(T(Item1^), T(Item2^));
  746. end;
  747. procedure TFPGInterfacedObjectList.Put(Index: Integer; const Item: T);
  748. begin
  749. inherited Put(Index, @Item);
  750. end;
  751. function TFPGInterfacedObjectList.Add(const Item: T): Integer;
  752. begin
  753. Result := inherited Add(@Item);
  754. end;
  755. function TFPGInterfacedObjectList.Extract(const Item: T): T;
  756. var
  757. ResPtr: Pointer;
  758. begin
  759. ResPtr := inherited Extract(@Item);
  760. if ResPtr <> nil then
  761. Result := T(ResPtr^)
  762. else
  763. FillByte(Result, 0, sizeof(T));
  764. end;
  765. function TFPGInterfacedObjectList.First: T;
  766. begin
  767. Result := T(inherited First^);
  768. end;
  769. function TFPGInterfacedObjectList.IndexOf(const Item: T): Integer;
  770. begin
  771. Result := 0;
  772. {$info TODO: fix inlining to work! InternalItems[Result]^}
  773. while (Result < FCount) and (PT(FList)[Result] <> Item) do
  774. Inc(Result);
  775. if Result = FCount then
  776. Result := -1;
  777. end;
  778. procedure TFPGInterfacedObjectList.Insert(Index: Integer; const Item: T);
  779. begin
  780. T(inherited Insert(Index)^) := Item;
  781. end;
  782. function TFPGInterfacedObjectList.Last: T;
  783. begin
  784. Result := T(inherited Last^);
  785. end;
  786. function TFPGInterfacedObjectList.Remove(const Item: T): Integer;
  787. begin
  788. Result := IndexOf(Item);
  789. if Result >= 0 then
  790. Delete(Result);
  791. end;
  792. procedure TFPGInterfacedObjectList.Sort(Compare: TCompareFunc);
  793. begin
  794. FOnCompare := Compare;
  795. inherited Sort(@ItemPtrCompare);
  796. end;
  797. {$endif}
  798. {****************************************************************************
  799. TFPSMap
  800. ****************************************************************************}
  801. constructor TFPSMap.Create(AKeySize: Integer; ADataSize: integer);
  802. begin
  803. inherited Create(AKeySize+ADataSize);
  804. FKeySize := AKeySize;
  805. FDataSize := ADataSize;
  806. InitOnPtrCompare;
  807. end;
  808. procedure TFPSMap.CopyKey(Src, Dest: Pointer);
  809. begin
  810. System.Move(Src^, Dest^, FKeySize);
  811. end;
  812. procedure TFPSMap.CopyData(Src, Dest: Pointer);
  813. begin
  814. System.Move(Src^, Dest^, FDataSize);
  815. end;
  816. function TFPSMap.BinaryCompare(Key1, Key2: Pointer): Integer;
  817. begin
  818. Result := CompareByte(Key1^, Key2^, FKeySize);
  819. end;
  820. function TFPSMap.GetKey(Index: Integer): Pointer;
  821. begin
  822. Result := Items[Index];
  823. end;
  824. function TFPSMap.GetData(Index: Integer): Pointer;
  825. begin
  826. Result := PByte(Items[Index])+FKeySize;
  827. end;
  828. function TFPSMap.GetKeyData(AKey: Pointer): Pointer;
  829. var
  830. I: Integer;
  831. begin
  832. I := IndexOf(AKey);
  833. if I >= 0 then
  834. Result := InternalItems[I]+FKeySize
  835. else
  836. Error(SMapKeyError, PtrUInt(AKey));
  837. end;
  838. procedure TFPSMap.InitOnPtrCompare;
  839. begin
  840. FOnPtrCompare := @BinaryCompare;
  841. end;
  842. procedure TFPSMap.PutKey(Index: Integer; AKey: Pointer);
  843. begin
  844. if FSorted then
  845. Error(SSortedListError, 0);
  846. CopyKey(AKey, Items[Index]);
  847. end;
  848. procedure TFPSMap.PutData(Index: Integer; AData: Pointer);
  849. begin
  850. CopyData(AData, PByte(Items[Index])+FKeySize);
  851. end;
  852. procedure TFPSMap.PutKeyData(AKey: Pointer; NewData: Pointer);
  853. var
  854. I: Integer;
  855. begin
  856. I := IndexOf(AKey);
  857. if I >= 0 then
  858. Data[I] := NewData
  859. else
  860. Add(AKey, NewData);
  861. end;
  862. procedure TFPSMap.SetSorted(Value: Boolean);
  863. begin
  864. if Value = FSorted then exit;
  865. FSorted := Value;
  866. if Value then Sort;
  867. end;
  868. function TFPSMap.Add(AKey: Pointer): Integer;
  869. begin
  870. if Sorted then
  871. begin
  872. if Find(AKey, Result) then
  873. case Duplicates of
  874. dupIgnore: exit;
  875. dupError: Error(SDuplicateItem, 0)
  876. end;
  877. end else
  878. Result := Count;
  879. CopyKey(AKey, inherited Insert(Result));
  880. end;
  881. function TFPSMap.Add(AKey, AData: Pointer): Integer;
  882. begin
  883. Result := Add(AKey);
  884. Data[Result] := AData;
  885. end;
  886. function TFPSMap.Find(AKey: Pointer; var Index: Integer): Boolean;
  887. { Searches for the first item <= Key, returns True if exact match,
  888. sets index to the index f the found string. }
  889. var
  890. I,L,R,Dir: Integer;
  891. begin
  892. Result := false;
  893. // Use binary search.
  894. L := 0;
  895. R := FCount-1;
  896. while L<=R do
  897. begin
  898. I := (L+R) div 2;
  899. Dir := FOnPtrCompare(Items[I], AKey);
  900. if Dir < 0 then
  901. L := I+1
  902. else begin
  903. R := I-1;
  904. if Dir = 0 then
  905. begin
  906. Result := true;
  907. if Duplicates <> dupAccept then
  908. L := I;
  909. end;
  910. end;
  911. end;
  912. Index := L;
  913. end;
  914. function TFPSMap.LinearIndexOf(AKey: Pointer): Integer;
  915. var
  916. ListItem: Pointer;
  917. begin
  918. Result := 0;
  919. ListItem := First;
  920. while (Result < FCount) and (FOnPtrCompare(ListItem, AKey) <> 0) do
  921. begin
  922. Inc(Result);
  923. ListItem := PByte(ListItem)+FItemSize;
  924. end;
  925. if Result = FCount then Result := -1;
  926. end;
  927. function TFPSMap.IndexOf(AKey: Pointer): Integer;
  928. begin
  929. if Sorted then
  930. begin
  931. if not Find(AKey, Result) then
  932. Result := -1;
  933. end else
  934. Result := LinearIndexOf(AKey);
  935. end;
  936. function TFPSMap.IndexOfData(AData: Pointer): Integer;
  937. var
  938. ListItem: Pointer;
  939. begin
  940. Result := 0;
  941. ListItem := First+FKeySize;
  942. while (Result < FCount) and (CompareByte(ListItem^, AData^, FDataSize) <> 0) do
  943. begin
  944. Inc(Result);
  945. ListItem := PByte(ListItem)+FItemSize;
  946. end;
  947. if Result = FCount then Result := -1;
  948. end;
  949. function TFPSMap.Insert(Index: Integer): Pointer;
  950. begin
  951. if FSorted then
  952. Error(SSortedListError, 0);
  953. Result := inherited Insert(Index);
  954. end;
  955. procedure TFPSMap.Insert(Index: Integer; var AKey, AData: Pointer);
  956. begin
  957. AKey := Insert(Index);
  958. AData := PByte(AKey) + FKeySize;
  959. end;
  960. procedure TFPSMap.InsertKey(Index: Integer; AKey: Pointer);
  961. begin
  962. CopyKey(AKey, Insert(Index));
  963. end;
  964. procedure TFPSMap.InsertKeyData(Index: Integer; AKey, AData: Pointer);
  965. var
  966. ListItem: Pointer;
  967. begin
  968. ListItem := Insert(Index);
  969. CopyKey(AKey, ListItem);
  970. CopyData(AData, PByte(ListItem)+FKeySize);
  971. end;
  972. function TFPSMap.Remove(AKey: Pointer): Integer;
  973. begin
  974. Result := IndexOf(AKey);
  975. if Result >= 0 then
  976. Delete(Result);
  977. end;
  978. procedure TFPSMap.Sort;
  979. begin
  980. inherited Sort(FOnPtrCompare);
  981. end;
  982. {****************************************************************************
  983. TFPGMap
  984. ****************************************************************************}
  985. {$ifndef VER2_0}
  986. constructor TFPGMap.Create;
  987. begin
  988. inherited Create(SizeOf(TKey), SizeOf(TData));
  989. end;
  990. procedure TFPGMap.CopyItem(Src, Dest: Pointer);
  991. begin
  992. CopyKey(Src, Dest);
  993. CopyData(PByte(Src)+KeySize, PByte(Dest)+KeySize);
  994. end;
  995. procedure TFPGMap.CopyKey(Src, Dest: Pointer);
  996. begin
  997. TKey(Dest^) := TKey(Src^);
  998. end;
  999. procedure TFPGMap.CopyData(Src, Dest: Pointer);
  1000. begin
  1001. TData(Dest^) := TData(Src^);
  1002. end;
  1003. procedure TFPGMap.Deref(Item: Pointer);
  1004. begin
  1005. Finalize(TKey(Item^));
  1006. Finalize(TData(Pointer(PByte(Item)+KeySize)^));
  1007. end;
  1008. function TFPGMap.GetKey(Index: Integer): TKey;
  1009. begin
  1010. Result := TKey(inherited GetKey(Index)^);
  1011. end;
  1012. function TFPGMap.GetData(Index: Integer): TData;
  1013. begin
  1014. Result := TData(inherited GetData(Index)^);
  1015. end;
  1016. function TFPGMap.GetKeyData(const AKey: TKey): TData;
  1017. begin
  1018. Result := TData(inherited GetKeyData(@AKey)^);
  1019. end;
  1020. procedure TFPGMap.InitOnPtrCompare;
  1021. begin
  1022. OnPtrCompare := @KeyCompare;
  1023. end;
  1024. function TFPGMap.KeyCompare(Key1, Key2: Pointer): Integer;
  1025. begin
  1026. if PKey(Key1)^ < PKey(Key2)^ then
  1027. Result := -1
  1028. else if PKey(Key1)^ > PKey(Key2)^ then
  1029. Result := 1
  1030. else
  1031. Result := 0;
  1032. end;
  1033. function TFPGMap.KeyCustomCompare(Key1, Key2: Pointer): Integer;
  1034. begin
  1035. Result := FOnCompare(TKey(Key1^), TKey(Key2^));
  1036. end;
  1037. procedure TFPGMap.PutKey(Index: Integer; const NewKey: TKey);
  1038. begin
  1039. inherited PutKey(Index, @NewKey);
  1040. end;
  1041. procedure TFPGMap.PutData(Index: Integer; const NewData: TData);
  1042. begin
  1043. inherited PutData(Index, @NewData);
  1044. end;
  1045. procedure TFPGMap.PutKeyData(const AKey: TKey; const NewData: TData);
  1046. begin
  1047. inherited PutKeyData(@AKey, @NewData);
  1048. end;
  1049. procedure TFPGMap.SetOnCompare(NewCompare: TCompareFunc);
  1050. begin
  1051. FOnCompare := NewCompare;
  1052. if NewCompare <> nil then
  1053. OnPtrCompare := @KeyCustomCompare
  1054. else
  1055. InitOnPtrCompare;
  1056. end;
  1057. function TFPGMap.Add(const AKey: TKey): Integer;
  1058. begin
  1059. Result := inherited Add(@AKey);
  1060. end;
  1061. function TFPGMap.Add(const AKey: TKey; const AData: TData): Integer;
  1062. begin
  1063. Result := inherited Add(@AKey, @AData);
  1064. end;
  1065. function TFPGMap.Find(const AKey: TKey; var Index: Integer): Boolean;
  1066. begin
  1067. Result := inherited Find(@AKey, Index);
  1068. end;
  1069. function TFPGMap.IndexOf(const AKey: TKey): Integer;
  1070. begin
  1071. Result := inherited IndexOf(@AKey);
  1072. end;
  1073. function TFPGMap.IndexOfData(const AData: TData): Integer;
  1074. begin
  1075. { TODO: loop ? }
  1076. Result := inherited IndexOfData(@AData);
  1077. end;
  1078. procedure TFPGMap.InsertKey(Index: Integer; const AKey: TKey);
  1079. begin
  1080. inherited InsertKey(Index, @AKey);
  1081. end;
  1082. procedure TFPGMap.InsertKeyData(Index: Integer; const AKey: TKey; const AData: TData);
  1083. begin
  1084. inherited InsertKeyData(Index, @AKey, @AData);
  1085. end;
  1086. function TFPGMap.Remove(const AKey: TKey): Integer;
  1087. begin
  1088. Result := inherited Remove(@AKey);
  1089. end;
  1090. {$endif}
  1091. end.