fgl.pp 44 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599
  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. {.$define CLASSESINLINE}
  14. { be aware, this unit is a prototype and subject to be changed heavily }
  15. unit fgl;
  16. interface
  17. uses
  18. types, sysutils;
  19. {$IF defined(VER2_4)}
  20. {$DEFINE OldSyntax}
  21. {$IFEND}
  22. const
  23. MaxListSize = Maxint div 16;
  24. type
  25. EListError = class(Exception);
  26. TFPSList = class;
  27. TFPSListCompareFunc = function(Key1, Key2: Pointer): Integer of object;
  28. TFPSList = class(TObject)
  29. protected
  30. FList: PByte;
  31. FCount: Integer;
  32. FCapacity: Integer; { list is one longer sgthan capacity, for temp }
  33. FItemSize: Integer;
  34. procedure CopyItem(Src, Dest: Pointer); virtual;
  35. procedure Deref(Item: Pointer); virtual; overload;
  36. procedure Deref(FromIndex, ToIndex: Integer); overload;
  37. function Get(Index: Integer): Pointer;
  38. procedure InternalExchange(Index1, Index2: Integer);
  39. function InternalGet(Index: Integer): Pointer; {$ifdef CLASSESINLINE} inline; {$endif}
  40. procedure InternalPut(Index: Integer; NewItem: Pointer);
  41. procedure Put(Index: Integer; Item: Pointer);
  42. procedure QuickSort(L, R: Integer; Compare: TFPSListCompareFunc);
  43. procedure SetCapacity(NewCapacity: Integer);
  44. procedure SetCount(NewCount: Integer);
  45. procedure RaiseIndexError(Index : Integer);
  46. property InternalItems[Index: Integer]: Pointer read InternalGet write InternalPut;
  47. public
  48. constructor Create(AItemSize: Integer = sizeof(Pointer));
  49. destructor Destroy; override;
  50. function Add(Item: Pointer): Integer;
  51. procedure Clear;
  52. procedure Delete(Index: Integer);
  53. class procedure Error(const Msg: string; Data: PtrInt);
  54. procedure Exchange(Index1, Index2: Integer);
  55. function Expand: TFPSList;
  56. function Extract(Item: Pointer): Pointer;
  57. function First: Pointer;
  58. function IndexOf(Item: Pointer): Integer;
  59. procedure Insert(Index: Integer; Item: Pointer);
  60. function Insert(Index: Integer): Pointer;
  61. function Last: Pointer;
  62. procedure Move(CurIndex, NewIndex: Integer);
  63. procedure Assign(Obj: TFPSList);
  64. function Remove(Item: Pointer): Integer;
  65. procedure Pack;
  66. procedure Sort(Compare: TFPSListCompareFunc);
  67. property Capacity: Integer read FCapacity write SetCapacity;
  68. property Count: Integer read FCount write SetCount;
  69. property Items[Index: Integer]: Pointer read Get write Put; default;
  70. property ItemSize: Integer read FItemSize;
  71. property List: PByte read FList;
  72. end;
  73. const
  74. MaxGListSize = MaxInt div 1024;
  75. type
  76. generic TFPGListEnumerator<T> = class(TObject)
  77. protected
  78. FList: TFPSList;
  79. FPosition: Integer;
  80. function GetCurrent: T;
  81. public
  82. constructor Create(AList: TFPSList);
  83. function MoveNext: Boolean;
  84. property Current: T read GetCurrent;
  85. end;
  86. generic TFPGList<T> = class(TFPSList)
  87. public
  88. type
  89. TCompareFunc = function(const Item1, Item2: T): Integer;
  90. TTypeList = array[0..MaxGListSize] of T;
  91. PTypeList = ^TTypeList;
  92. PT = ^T;
  93. TFPGListEnumeratorSpec = specialize TFPGListEnumerator<T>;
  94. {$ifndef OldSyntax}protected var{$else}var protected{$endif}
  95. FOnCompare: TCompareFunc;
  96. procedure CopyItem(Src, Dest: Pointer); override;
  97. procedure Deref(Item: Pointer); override;
  98. function Get(Index: Integer): T; {$ifdef CLASSESINLINE} inline; {$endif}
  99. function GetList: PTypeList; {$ifdef CLASSESINLINE} inline; {$endif}
  100. function ItemPtrCompare(Item1, Item2: Pointer): Integer;
  101. procedure Put(Index: Integer; const Item: T); {$ifdef CLASSESINLINE} inline; {$endif}
  102. public
  103. constructor Create;
  104. function Add(const Item: T): Integer; {$ifdef CLASSESINLINE} inline; {$endif}
  105. function Extract(const Item: T): T; {$ifdef CLASSESINLINE} inline; {$endif}
  106. function First: T; {$ifdef CLASSESINLINE} inline; {$endif}
  107. function GetEnumerator: TFPGListEnumeratorSpec; {$ifdef CLASSESINLINE} inline; {$endif}
  108. function IndexOf(const Item: T): Integer;
  109. procedure Insert(Index: Integer; const Item: T); {$ifdef CLASSESINLINE} inline; {$endif}
  110. function Last: T; {$ifdef CLASSESINLINE} inline; {$endif}
  111. {$ifndef VER2_4}
  112. procedure Assign(Source: TFPGList);
  113. {$endif VER2_4}
  114. function Remove(const Item: T): Integer; {$ifdef CLASSESINLINE} inline; {$endif}
  115. procedure Sort(Compare: TCompareFunc);
  116. property Items[Index: Integer]: T read Get write Put; default;
  117. property List: PTypeList read GetList;
  118. end;
  119. generic TFPGObjectList<T> = class(TFPSList)
  120. public
  121. type
  122. TCompareFunc = function(const Item1, Item2: T): Integer;
  123. TTypeList = array[0..MaxGListSize] of T;
  124. PTypeList = ^TTypeList;
  125. PT = ^T;
  126. TFPGListEnumeratorSpec = specialize TFPGListEnumerator<T>;
  127. {$ifndef OldSyntax}protected var{$else}var protected{$endif}
  128. FOnCompare: TCompareFunc;
  129. FFreeObjects: Boolean;
  130. procedure CopyItem(Src, Dest: Pointer); override;
  131. procedure Deref(Item: Pointer); override;
  132. function Get(Index: Integer): T; {$ifdef CLASSESINLINE} inline; {$endif}
  133. function GetList: PTypeList; {$ifdef CLASSESINLINE} inline; {$endif}
  134. function ItemPtrCompare(Item1, Item2: Pointer): Integer;
  135. procedure Put(Index: Integer; const Item: T); {$ifdef CLASSESINLINE} inline; {$endif}
  136. public
  137. constructor Create(FreeObjects: Boolean = True);
  138. function Add(const Item: T): Integer; {$ifdef CLASSESINLINE} inline; {$endif}
  139. function Extract(const Item: T): T; {$ifdef CLASSESINLINE} inline; {$endif}
  140. function First: T; {$ifdef CLASSESINLINE} inline; {$endif}
  141. function GetEnumerator: TFPGListEnumeratorSpec; {$ifdef CLASSESINLINE} inline; {$endif}
  142. function IndexOf(const Item: T): Integer;
  143. procedure Insert(Index: Integer; const Item: T); {$ifdef CLASSESINLINE} inline; {$endif}
  144. function Last: T; {$ifdef CLASSESINLINE} inline; {$endif}
  145. {$ifndef VER2_4}
  146. procedure Assign(Source: TFPGObjectList);
  147. {$endif VER2_4}
  148. function Remove(const Item: T): Integer; {$ifdef CLASSESINLINE} inline; {$endif}
  149. procedure Sort(Compare: TCompareFunc);
  150. property Items[Index: Integer]: T read Get write Put; default;
  151. property List: PTypeList read GetList;
  152. property FreeObjects: Boolean read FFreeObjects write FFreeObjects;
  153. end;
  154. generic TFPGInterfacedObjectList<T> = class(TFPSList)
  155. public
  156. type
  157. TCompareFunc = function(const Item1, Item2: T): Integer;
  158. TTypeList = array[0..MaxGListSize] of T;
  159. PTypeList = ^TTypeList;
  160. PT = ^T;
  161. TFPGListEnumeratorSpec = specialize TFPGListEnumerator<T>;
  162. {$ifndef OldSyntax}protected var{$else}var protected{$endif}
  163. FOnCompare: TCompareFunc;
  164. procedure CopyItem(Src, Dest: Pointer); override;
  165. procedure Deref(Item: Pointer); override;
  166. function Get(Index: Integer): T; {$ifdef CLASSESINLINE} inline; {$endif}
  167. function GetList: PTypeList; {$ifdef CLASSESINLINE} inline; {$endif}
  168. function ItemPtrCompare(Item1, Item2: Pointer): Integer;
  169. procedure Put(Index: Integer; const Item: T); {$ifdef CLASSESINLINE} inline; {$endif}
  170. public
  171. constructor Create;
  172. function Add(const Item: T): Integer; {$ifdef CLASSESINLINE} inline; {$endif}
  173. function Extract(const Item: T): T; {$ifdef CLASSESINLINE} inline; {$endif}
  174. function First: T; {$ifdef CLASSESINLINE} inline; {$endif}
  175. function GetEnumerator: TFPGListEnumeratorSpec; {$ifdef CLASSESINLINE} inline; {$endif}
  176. function IndexOf(const Item: T): Integer;
  177. procedure Insert(Index: Integer; const Item: T); {$ifdef CLASSESINLINE} inline; {$endif}
  178. function Last: T; {$ifdef CLASSESINLINE} inline; {$endif}
  179. {$ifndef VER2_4}
  180. procedure Assign(Source: TFPGInterfacedObjectList);
  181. {$endif VER2_4}
  182. function Remove(const Item: T): Integer; {$ifdef CLASSESINLINE} inline; {$endif}
  183. procedure Sort(Compare: TCompareFunc);
  184. property Items[Index: Integer]: T read Get write Put; default;
  185. property List: PTypeList read GetList;
  186. end;
  187. TFPSMap = class(TFPSList)
  188. private
  189. FKeySize: Integer;
  190. FDataSize: Integer;
  191. FDuplicates: TDuplicates;
  192. FSorted: Boolean;
  193. FOnKeyPtrCompare: TFPSListCompareFunc;
  194. FOnDataPtrCompare: TFPSListCompareFunc;
  195. procedure SetSorted(Value: Boolean);
  196. protected
  197. function BinaryCompareKey(Key1, Key2: Pointer): Integer;
  198. function BinaryCompareData(Data1, Data2: Pointer): Integer;
  199. procedure SetOnKeyPtrCompare(Proc: TFPSListCompareFunc);
  200. procedure SetOnDataPtrCompare(Proc: TFPSListCompareFunc);
  201. procedure InitOnPtrCompare; virtual;
  202. procedure CopyKey(Src, Dest: Pointer); virtual;
  203. procedure CopyData(Src, Dest: Pointer); virtual;
  204. function GetKey(Index: Integer): Pointer;
  205. function GetKeyData(AKey: Pointer): Pointer;
  206. function GetData(Index: Integer): Pointer;
  207. function LinearIndexOf(AKey: Pointer): Integer;
  208. procedure PutKey(Index: Integer; AKey: Pointer);
  209. procedure PutKeyData(AKey: Pointer; NewData: Pointer);
  210. procedure PutData(Index: Integer; AData: Pointer);
  211. public
  212. constructor Create(AKeySize: Integer = sizeof(Pointer);
  213. ADataSize: integer = sizeof(Pointer));
  214. function Add(AKey, AData: Pointer): Integer;
  215. function Add(AKey: Pointer): Integer;
  216. function Find(AKey: Pointer; out Index: Integer): Boolean;
  217. function IndexOf(AKey: Pointer): Integer;
  218. function IndexOfData(AData: Pointer): Integer;
  219. function Insert(Index: Integer): Pointer;
  220. procedure Insert(Index: Integer; out AKey, AData: Pointer);
  221. procedure InsertKey(Index: Integer; AKey: Pointer);
  222. procedure InsertKeyData(Index: Integer; AKey, AData: Pointer);
  223. function Remove(AKey: Pointer): Integer;
  224. procedure Sort;
  225. property Duplicates: TDuplicates read FDuplicates write FDuplicates;
  226. property KeySize: Integer read FKeySize;
  227. property DataSize: Integer read FDataSize;
  228. property Keys[Index: Integer]: Pointer read GetKey write PutKey;
  229. property Data[Index: Integer]: Pointer read GetData write PutData;
  230. property KeyData[Key: Pointer]: Pointer read GetKeyData write PutKeyData; default;
  231. property Sorted: Boolean read FSorted write SetSorted;
  232. property OnPtrCompare: TFPSListCompareFunc read FOnKeyPtrCompare write SetOnKeyPtrCompare; //deprecated;
  233. property OnKeyPtrCompare: TFPSListCompareFunc read FOnKeyPtrCompare write SetOnKeyPtrCompare;
  234. property OnDataPtrCompare: TFPSListCompareFunc read FOnDataPtrCompare write SetOnDataPtrCompare;
  235. end;
  236. generic TFPGMap<TKey, TData> = class(TFPSMap)
  237. public
  238. type
  239. TKeyCompareFunc = function(const Key1, Key2: TKey): Integer;
  240. TDataCompareFunc = function(const Data1, Data2: TData): Integer;
  241. PKey = ^TKey;
  242. PData = ^TData;
  243. {$ifndef OldSyntax}protected var{$else}var protected{$endif}
  244. FOnKeyCompare: TKeyCompareFunc;
  245. FOnDataCompare: TDataCompareFunc;
  246. procedure CopyItem(Src, Dest: Pointer); override;
  247. procedure CopyKey(Src, Dest: Pointer); override;
  248. procedure CopyData(Src, Dest: Pointer); override;
  249. procedure Deref(Item: Pointer); override;
  250. procedure InitOnPtrCompare; override;
  251. function GetKey(Index: Integer): TKey; {$ifdef CLASSESINLINE} inline; {$endif}
  252. function GetKeyData(const AKey: TKey): TData; {$ifdef CLASSESINLINE} inline; {$endif}
  253. function GetData(Index: Integer): TData; {$ifdef CLASSESINLINE} inline; {$endif}
  254. function KeyCompare(Key1, Key2: Pointer): Integer;
  255. function KeyCustomCompare(Key1, Key2: Pointer): Integer;
  256. //function DataCompare(Data1, Data2: Pointer): Integer;
  257. function DataCustomCompare(Data1, Data2: Pointer): Integer;
  258. procedure PutKey(Index: Integer; const NewKey: TKey); {$ifdef CLASSESINLINE} inline; {$endif}
  259. procedure PutKeyData(const AKey: TKey; const NewData: TData); {$ifdef CLASSESINLINE} inline; {$endif}
  260. procedure PutData(Index: Integer; const NewData: TData); {$ifdef CLASSESINLINE} inline; {$endif}
  261. procedure SetOnKeyCompare(NewCompare: TKeyCompareFunc);
  262. procedure SetOnDataCompare(NewCompare: TDataCompareFunc);
  263. public
  264. constructor Create;
  265. function Add(const AKey: TKey; const AData: TData): Integer; {$ifdef CLASSESINLINE} inline; {$endif}
  266. function Add(const AKey: TKey): Integer; {$ifdef CLASSESINLINE} inline; {$endif}
  267. function Find(const AKey: TKey; out Index: Integer): Boolean; {$ifdef CLASSESINLINE} inline; {$endif}
  268. function IndexOf(const AKey: TKey): Integer; {$ifdef CLASSESINLINE} inline; {$endif}
  269. function IndexOfData(const AData: TData): Integer;
  270. procedure InsertKey(Index: Integer; const AKey: TKey);
  271. procedure InsertKeyData(Index: Integer; const AKey: TKey; const AData: TData);
  272. function Remove(const AKey: TKey): Integer;
  273. property Keys[Index: Integer]: TKey read GetKey write PutKey;
  274. property Data[Index: Integer]: TData read GetData write PutData;
  275. property KeyData[const AKey: TKey]: TData read GetKeyData write PutKeyData; default;
  276. property OnCompare: TKeyCompareFunc read FOnKeyCompare write SetOnKeyCompare; //deprecated;
  277. property OnKeyCompare: TKeyCompareFunc read FOnKeyCompare write SetOnKeyCompare;
  278. property OnDataCompare: TDataCompareFunc read FOnDataCompare write SetOnDataCompare;
  279. end;
  280. generic TFPGMapInterfacedObjectData<TKey, TData> = class(TFPSMap)
  281. public
  282. type
  283. TKeyCompareFunc = function(const Key1, Key2: TKey): Integer;
  284. TDataCompareFunc = function(const Data1, Data2: TData): Integer;
  285. PKey = ^TKey;
  286. PData = ^TData;
  287. {$ifndef OldSyntax}protected var{$else}var protected{$endif}
  288. FOnKeyCompare: TKeyCompareFunc;
  289. FOnDataCompare: TDataCompareFunc;
  290. procedure CopyItem(Src, Dest: Pointer); override;
  291. procedure CopyKey(Src, Dest: Pointer); override;
  292. procedure CopyData(Src, Dest: Pointer); override;
  293. procedure Deref(Item: Pointer); override;
  294. procedure InitOnPtrCompare; override;
  295. function GetKey(Index: Integer): TKey; {$ifdef CLASSESINLINE} inline; {$endif}
  296. function GetKeyData(const AKey: TKey): TData; {$ifdef CLASSESINLINE} inline; {$endif}
  297. function GetData(Index: Integer): TData; {$ifdef CLASSESINLINE} inline; {$endif}
  298. function KeyCompare(Key1, Key2: Pointer): Integer;
  299. function KeyCustomCompare(Key1, Key2: Pointer): Integer;
  300. //function DataCompare(Data1, Data2: Pointer): Integer;
  301. function DataCustomCompare(Data1, Data2: Pointer): Integer;
  302. procedure PutKey(Index: Integer; const NewKey: TKey); {$ifdef CLASSESINLINE} inline; {$endif}
  303. procedure PutKeyData(const AKey: TKey; const NewData: TData); {$ifdef CLASSESINLINE} inline; {$endif}
  304. procedure PutData(Index: Integer; const NewData: TData); {$ifdef CLASSESINLINE} inline; {$endif}
  305. procedure SetOnKeyCompare(NewCompare: TKeyCompareFunc);
  306. procedure SetOnDataCompare(NewCompare: TDataCompareFunc);
  307. public
  308. constructor Create;
  309. function Add(const AKey: TKey; const AData: TData): Integer; {$ifdef CLASSESINLINE} inline; {$endif}
  310. function Add(const AKey: TKey): Integer; {$ifdef CLASSESINLINE} inline; {$endif}
  311. function Find(const AKey: TKey; out Index: Integer): Boolean; {$ifdef CLASSESINLINE} inline; {$endif}
  312. function IndexOf(const AKey: TKey): Integer; {$ifdef CLASSESINLINE} inline; {$endif}
  313. function IndexOfData(const AData: TData): Integer;
  314. procedure InsertKey(Index: Integer; const AKey: TKey);
  315. procedure InsertKeyData(Index: Integer; const AKey: TKey; const AData: TData);
  316. function Remove(const AKey: TKey): Integer;
  317. property Keys[Index: Integer]: TKey read GetKey write PutKey;
  318. property Data[Index: Integer]: TData read GetData write PutData;
  319. property KeyData[const AKey: TKey]: TData read GetKeyData write PutKeyData; default;
  320. property OnCompare: TKeyCompareFunc read FOnKeyCompare write SetOnKeyCompare; //deprecated;
  321. property OnKeyCompare: TKeyCompareFunc read FOnKeyCompare write SetOnKeyCompare;
  322. property OnDataCompare: TDataCompareFunc read FOnDataCompare write SetOnDataCompare;
  323. end;
  324. implementation
  325. uses
  326. rtlconsts;
  327. {****************************************************************************
  328. TFPSList
  329. ****************************************************************************}
  330. constructor TFPSList.Create(AItemSize: integer);
  331. begin
  332. inherited Create;
  333. FItemSize := AItemSize;
  334. end;
  335. destructor TFPSList.Destroy;
  336. begin
  337. Clear;
  338. // Clear() does not clear the whole list; there is always a single temp entry
  339. // at the end which is never freed. Take care of that one here.
  340. FreeMem(FList);
  341. inherited Destroy;
  342. end;
  343. procedure TFPSList.CopyItem(Src, Dest: Pointer);
  344. begin
  345. System.Move(Src^, Dest^, FItemSize);
  346. end;
  347. procedure TFPSList.RaiseIndexError(Index : Integer);
  348. begin
  349. Error(SListIndexError, Index);
  350. end;
  351. function TFPSList.InternalGet(Index: Integer): Pointer;
  352. begin
  353. Result:=FList+Index*ItemSize;
  354. end;
  355. procedure TFPSList.InternalPut(Index: Integer; NewItem: Pointer);
  356. var
  357. ListItem: Pointer;
  358. begin
  359. ListItem := InternalItems[Index];
  360. CopyItem(NewItem, ListItem);
  361. end;
  362. function TFPSList.Get(Index: Integer): Pointer;
  363. begin
  364. if (Index < 0) or (Index >= FCount) then
  365. RaiseIndexError(Index);
  366. Result := InternalItems[Index];
  367. end;
  368. procedure TFPSList.Put(Index: Integer; Item: Pointer);
  369. begin
  370. if (Index < 0) or (Index >= FCount) then
  371. RaiseIndexError(Index);
  372. InternalItems[Index] := Item;
  373. end;
  374. procedure TFPSList.SetCapacity(NewCapacity: Integer);
  375. begin
  376. if (NewCapacity < FCount) or (NewCapacity > MaxListSize) then
  377. Error(SListCapacityError, NewCapacity);
  378. if NewCapacity = FCapacity then
  379. exit;
  380. ReallocMem(FList, (NewCapacity+1) * FItemSize);
  381. FillChar(InternalItems[FCapacity]^, (NewCapacity+1-FCapacity) * FItemSize, #0);
  382. FCapacity := NewCapacity;
  383. end;
  384. procedure TFPSList.Deref(Item: Pointer);
  385. begin
  386. end;
  387. procedure TFPSList.Deref(FromIndex, ToIndex: Integer);
  388. var
  389. ListItem, ListItemLast: Pointer;
  390. begin
  391. ListItem := InternalItems[FromIndex];
  392. ListItemLast := InternalItems[ToIndex];
  393. repeat
  394. Deref(ListItem);
  395. if ListItem = ListItemLast then
  396. break;
  397. ListItem := PByte(ListItem) + ItemSize;
  398. until false;
  399. end;
  400. procedure TFPSList.SetCount(NewCount: Integer);
  401. begin
  402. if (NewCount < 0) or (NewCount > MaxListSize) then
  403. Error(SListCountError, NewCount);
  404. if NewCount > FCapacity then
  405. SetCapacity(NewCount);
  406. if NewCount > FCount then
  407. FillByte(InternalItems[FCount]^, (NewCount-FCount) * FItemSize, 0)
  408. else if NewCount < FCount then
  409. Deref(NewCount, FCount-1);
  410. FCount := NewCount;
  411. end;
  412. function TFPSList.Add(Item: Pointer): Integer;
  413. begin
  414. if FCount = FCapacity then
  415. Self.Expand;
  416. CopyItem(Item, InternalItems[FCount]);
  417. Result := FCount;
  418. Inc(FCount);
  419. end;
  420. procedure TFPSList.Clear;
  421. begin
  422. if Assigned(FList) then
  423. begin
  424. SetCount(0);
  425. SetCapacity(0);
  426. end;
  427. end;
  428. procedure TFPSList.Delete(Index: Integer);
  429. var
  430. ListItem: Pointer;
  431. begin
  432. if (Index < 0) or (Index >= FCount) then
  433. Error(SListIndexError, Index);
  434. Dec(FCount);
  435. ListItem := InternalItems[Index];
  436. Deref(ListItem);
  437. System.Move(InternalItems[Index+1]^, ListItem^, (FCount - Index) * FItemSize);
  438. // Shrink the list if appropriate
  439. if (FCapacity > 256) and (FCount < FCapacity shr 2) then
  440. begin
  441. FCapacity := FCapacity shr 1;
  442. ReallocMem(FList, (FCapacity+1) * FItemSize);
  443. end;
  444. end;
  445. function TFPSList.Extract(Item: Pointer): Pointer;
  446. var
  447. i : Integer;
  448. begin
  449. Result := nil;
  450. i := IndexOf(Item);
  451. if i >= 0 then
  452. begin
  453. Result := InternalItems[i];
  454. System.Move(Result^, InternalItems[FCapacity]^, FItemSize);
  455. Delete(i);
  456. end;
  457. end;
  458. class procedure TFPSList.Error(const Msg: string; Data: PtrInt);
  459. begin
  460. raise EListError.CreateFmt(Msg,[Data]) at get_caller_addr(get_frame);
  461. end;
  462. procedure TFPSList.Exchange(Index1, Index2: Integer);
  463. begin
  464. if ((Index1 >= FCount) or (Index1 < 0)) then
  465. Error(SListIndexError, Index1);
  466. if ((Index2 >= FCount) or (Index2 < 0)) then
  467. Error(SListIndexError, Index2);
  468. InternalExchange(Index1, Index2);
  469. end;
  470. procedure TFPSList.InternalExchange(Index1, Index2: Integer);
  471. begin
  472. System.Move(InternalItems[Index1]^, InternalItems[FCapacity]^, FItemSize);
  473. System.Move(InternalItems[Index2]^, InternalItems[Index1]^, FItemSize);
  474. System.Move(InternalItems[FCapacity]^, InternalItems[Index2]^, FItemSize);
  475. end;
  476. function TFPSList.Expand: TFPSList;
  477. var
  478. IncSize : Longint;
  479. begin
  480. if FCount < FCapacity then exit;
  481. IncSize := 4;
  482. if FCapacity > 3 then IncSize := IncSize + 4;
  483. if FCapacity > 8 then IncSize := IncSize + 8;
  484. if FCapacity > 127 then Inc(IncSize, FCapacity shr 2);
  485. SetCapacity(FCapacity + IncSize);
  486. Result := Self;
  487. end;
  488. function TFPSList.First: Pointer;
  489. begin
  490. If FCount = 0 then
  491. Result := Nil
  492. else
  493. Result := InternalItems[0];
  494. end;
  495. function TFPSList.IndexOf(Item: Pointer): Integer;
  496. var
  497. ListItem: Pointer;
  498. begin
  499. Result := 0;
  500. ListItem := First;
  501. while (Result < FCount) and (CompareByte(ListItem^, Item^, FItemSize) <> 0) do
  502. begin
  503. Inc(Result);
  504. ListItem := PByte(ListItem)+FItemSize;
  505. end;
  506. if Result = FCount then Result := -1;
  507. end;
  508. function TFPSList.Insert(Index: Integer): Pointer;
  509. begin
  510. if (Index < 0) or (Index > FCount) then
  511. Error(SListIndexError, Index);
  512. if FCount = FCapacity then Self.Expand;
  513. Result := InternalItems[Index];
  514. if Index<FCount then
  515. begin
  516. System.Move(Result^, (Result+FItemSize)^, (FCount - Index) * FItemSize);
  517. { clear for compiler assisted types }
  518. System.FillByte(Result^, FItemSize, 0);
  519. end;
  520. Inc(FCount);
  521. end;
  522. procedure TFPSList.Insert(Index: Integer; Item: Pointer);
  523. begin
  524. CopyItem(Item, Insert(Index));
  525. end;
  526. function TFPSList.Last: Pointer;
  527. begin
  528. if FCount = 0 then
  529. Result := nil
  530. else
  531. Result := InternalItems[FCount - 1];
  532. end;
  533. procedure TFPSList.Move(CurIndex, NewIndex: Integer);
  534. var
  535. CurItem, NewItem, TmpItem, Src, Dest: Pointer;
  536. MoveCount: Integer;
  537. begin
  538. if (CurIndex < 0) or (CurIndex >= Count) then
  539. Error(SListIndexError, CurIndex);
  540. if (NewIndex < 0) or (NewIndex >= Count) then
  541. Error(SListIndexError, NewIndex);
  542. if CurIndex = NewIndex then
  543. exit;
  544. CurItem := InternalItems[CurIndex];
  545. NewItem := InternalItems[NewIndex];
  546. TmpItem := InternalItems[FCapacity];
  547. System.Move(CurItem^, TmpItem^, FItemSize);
  548. if NewIndex > CurIndex then
  549. begin
  550. Src := InternalItems[CurIndex+1];
  551. Dest := CurItem;
  552. MoveCount := NewIndex - CurIndex;
  553. end else begin
  554. Src := NewItem;
  555. Dest := InternalItems[NewIndex+1];
  556. MoveCount := CurIndex - NewIndex;
  557. end;
  558. System.Move(Src^, Dest^, MoveCount * FItemSize);
  559. System.Move(TmpItem^, NewItem^, FItemSize);
  560. end;
  561. function TFPSList.Remove(Item: Pointer): Integer;
  562. begin
  563. Result := IndexOf(Item);
  564. if Result <> -1 then
  565. Delete(Result);
  566. end;
  567. procedure TFPSList.Pack;
  568. var
  569. NewCount,
  570. i : integer;
  571. pdest,
  572. psrc : Pointer;
  573. begin
  574. NewCount:=0;
  575. psrc:=First;
  576. pdest:=psrc;
  577. For I:=0 To FCount-1 Do
  578. begin
  579. if assigned(pointer(psrc^)) then
  580. begin
  581. System.Move(psrc^, pdest^, FItemSize);
  582. inc(pdest);
  583. inc(NewCount);
  584. end;
  585. inc(psrc);
  586. end;
  587. FCount:=NewCount;
  588. end;
  589. // Needed by Sort method.
  590. procedure TFPSList.QuickSort(L, R: Integer; Compare: TFPSListCompareFunc);
  591. var
  592. I, J, P: Integer;
  593. PivotItem: Pointer;
  594. begin
  595. repeat
  596. I := L;
  597. J := R;
  598. P := (L + R) div 2;
  599. repeat
  600. PivotItem := InternalItems[P];
  601. while Compare(PivotItem, InternalItems[I]) > 0 do
  602. Inc(I);
  603. while Compare(PivotItem, InternalItems[J]) < 0 do
  604. Dec(J);
  605. if I <= J then
  606. begin
  607. InternalExchange(I, J);
  608. if P = I then
  609. P := J
  610. else if P = J then
  611. P := I;
  612. Inc(I);
  613. Dec(J);
  614. end;
  615. until I > J;
  616. if L < J then
  617. QuickSort(L, J, Compare);
  618. L := I;
  619. until I >= R;
  620. end;
  621. procedure TFPSList.Sort(Compare: TFPSListCompareFunc);
  622. begin
  623. if not Assigned(FList) or (FCount < 2) then exit;
  624. QuickSort(0, FCount-1, Compare);
  625. end;
  626. procedure TFPSList.Assign(Obj: TFPSList);
  627. var
  628. i: Integer;
  629. begin
  630. if Obj.ItemSize <> FItemSize then
  631. Error(SListItemSizeError, 0);
  632. Clear;
  633. for I := 0 to Obj.Count - 1 do
  634. Add(Obj[i]);
  635. end;
  636. {****************************************************************************}
  637. {* TFPGListEnumerator *}
  638. {****************************************************************************}
  639. function TFPGListEnumerator.GetCurrent: T;
  640. begin
  641. Result := T(FList.Items[FPosition]^);
  642. end;
  643. constructor TFPGListEnumerator.Create(AList: TFPSList);
  644. begin
  645. inherited Create;
  646. FList := AList;
  647. FPosition := -1;
  648. end;
  649. function TFPGListEnumerator.MoveNext: Boolean;
  650. begin
  651. inc(FPosition);
  652. Result := FPosition < FList.Count;
  653. end;
  654. {****************************************************************************}
  655. {* TFPGList *}
  656. {****************************************************************************}
  657. constructor TFPGList.Create;
  658. begin
  659. inherited Create(sizeof(T));
  660. end;
  661. procedure TFPGList.CopyItem(Src, Dest: Pointer);
  662. begin
  663. T(Dest^) := T(Src^);
  664. end;
  665. procedure TFPGList.Deref(Item: Pointer);
  666. begin
  667. Finalize(T(Item^));
  668. end;
  669. function TFPGList.Get(Index: Integer): T;
  670. begin
  671. Result := T(inherited Get(Index)^);
  672. end;
  673. function TFPGList.GetList: PTypeList;
  674. begin
  675. Result := PTypeList(FList);
  676. end;
  677. function TFPGList.ItemPtrCompare(Item1, Item2: Pointer): Integer;
  678. begin
  679. Result := FOnCompare(T(Item1^), T(Item2^));
  680. end;
  681. procedure TFPGList.Put(Index: Integer; const Item: T);
  682. begin
  683. inherited Put(Index, @Item);
  684. end;
  685. function TFPGList.Add(const Item: T): Integer;
  686. begin
  687. Result := inherited Add(@Item);
  688. end;
  689. function TFPGList.Extract(const Item: T): T;
  690. var
  691. ResPtr: Pointer;
  692. begin
  693. ResPtr := inherited Extract(@Item);
  694. if ResPtr <> nil then
  695. Result := T(ResPtr^)
  696. else
  697. FillByte(Result, sizeof(T), 0);
  698. end;
  699. function TFPGList.First: T;
  700. begin
  701. Result := T(inherited First^);
  702. end;
  703. function TFPGList.GetEnumerator: TFPGListEnumeratorSpec;
  704. begin
  705. Result := TFPGListEnumeratorSpec.Create(Self);
  706. end;
  707. function TFPGList.IndexOf(const Item: T): Integer;
  708. begin
  709. Result := 0;
  710. {$info TODO: fix inlining to work! InternalItems[Result]^}
  711. while (Result < FCount) and (PT(FList)[Result] <> Item) do
  712. Inc(Result);
  713. if Result = FCount then
  714. Result := -1;
  715. end;
  716. procedure TFPGList.Insert(Index: Integer; const Item: T);
  717. begin
  718. T(inherited Insert(Index)^) := Item;
  719. end;
  720. function TFPGList.Last: T;
  721. begin
  722. Result := T(inherited Last^);
  723. end;
  724. {$ifndef VER2_4}
  725. procedure TFPGList.Assign(Source: TFPGList);
  726. var
  727. i: Integer;
  728. begin
  729. Clear;
  730. for I := 0 to Source.Count - 1 do
  731. Add(Source[i]);
  732. end;
  733. {$endif VER2_4}
  734. function TFPGList.Remove(const Item: T): Integer;
  735. begin
  736. Result := IndexOf(Item);
  737. if Result >= 0 then
  738. Delete(Result);
  739. end;
  740. procedure TFPGList.Sort(Compare: TCompareFunc);
  741. begin
  742. FOnCompare := Compare;
  743. inherited Sort(@ItemPtrCompare);
  744. end;
  745. {****************************************************************************}
  746. {* TFPGObjectList *}
  747. {****************************************************************************}
  748. constructor TFPGObjectList.Create(FreeObjects: Boolean);
  749. begin
  750. inherited Create;
  751. FFreeObjects := FreeObjects;
  752. end;
  753. procedure TFPGObjectList.CopyItem(Src, Dest: Pointer);
  754. begin
  755. T(Dest^) := T(Src^);
  756. end;
  757. procedure TFPGObjectList.Deref(Item: Pointer);
  758. begin
  759. if FFreeObjects then
  760. T(Item^).Free;
  761. end;
  762. function TFPGObjectList.Get(Index: Integer): T;
  763. begin
  764. Result := T(inherited Get(Index)^);
  765. end;
  766. function TFPGObjectList.GetList: PTypeList;
  767. begin
  768. Result := PTypeList(FList);
  769. end;
  770. function TFPGObjectList.ItemPtrCompare(Item1, Item2: Pointer): Integer;
  771. begin
  772. Result := FOnCompare(T(Item1^), T(Item2^));
  773. end;
  774. procedure TFPGObjectList.Put(Index: Integer; const Item: T);
  775. begin
  776. inherited Put(Index, @Item);
  777. end;
  778. function TFPGObjectList.Add(const Item: T): Integer;
  779. begin
  780. Result := inherited Add(@Item);
  781. end;
  782. function TFPGObjectList.Extract(const Item: T): T;
  783. var
  784. ResPtr: Pointer;
  785. begin
  786. ResPtr := inherited Extract(@Item);
  787. if ResPtr <> nil then
  788. Result := T(ResPtr^)
  789. else
  790. FillByte(Result, sizeof(T), 0);
  791. end;
  792. function TFPGObjectList.First: T;
  793. begin
  794. Result := T(inherited First^);
  795. end;
  796. function TFPGObjectList.GetEnumerator: TFPGListEnumeratorSpec;
  797. begin
  798. Result := TFPGListEnumeratorSpec.Create(Self);
  799. end;
  800. function TFPGObjectList.IndexOf(const Item: T): Integer;
  801. begin
  802. Result := 0;
  803. {$info TODO: fix inlining to work! InternalItems[Result]^}
  804. while (Result < FCount) and (PT(FList)[Result] <> Item) do
  805. Inc(Result);
  806. if Result = FCount then
  807. Result := -1;
  808. end;
  809. procedure TFPGObjectList.Insert(Index: Integer; const Item: T);
  810. begin
  811. T(inherited Insert(Index)^) := Item;
  812. end;
  813. function TFPGObjectList.Last: T;
  814. begin
  815. Result := T(inherited Last^);
  816. end;
  817. {$ifndef VER2_4}
  818. procedure TFPGObjectList.Assign(Source: TFPGObjectList);
  819. var
  820. i: Integer;
  821. begin
  822. Clear;
  823. for I := 0 to Source.Count - 1 do
  824. Add(Source[i]);
  825. end;
  826. {$endif VER2_4}
  827. function TFPGObjectList.Remove(const Item: T): Integer;
  828. begin
  829. Result := IndexOf(Item);
  830. if Result >= 0 then
  831. Delete(Result);
  832. end;
  833. procedure TFPGObjectList.Sort(Compare: TCompareFunc);
  834. begin
  835. FOnCompare := Compare;
  836. inherited Sort(@ItemPtrCompare);
  837. end;
  838. {****************************************************************************}
  839. {* TFPGInterfacedObjectList *}
  840. {****************************************************************************}
  841. constructor TFPGInterfacedObjectList.Create;
  842. begin
  843. inherited Create;
  844. end;
  845. procedure TFPGInterfacedObjectList.CopyItem(Src, Dest: Pointer);
  846. begin
  847. if Assigned(Pointer(Dest^)) then
  848. T(Dest^)._Release;
  849. T(Dest^) := T(Src^);
  850. if Assigned(Pointer(Dest^)) then
  851. T(Dest^)._AddRef;
  852. end;
  853. procedure TFPGInterfacedObjectList.Deref(Item: Pointer);
  854. begin
  855. if Assigned(Pointer(Item^)) then
  856. T(Item^)._Release;
  857. end;
  858. function TFPGInterfacedObjectList.Get(Index: Integer): T;
  859. begin
  860. Result := T(inherited Get(Index)^);
  861. end;
  862. function TFPGInterfacedObjectList.GetList: PTypeList;
  863. begin
  864. Result := PTypeList(FList);
  865. end;
  866. function TFPGInterfacedObjectList.ItemPtrCompare(Item1, Item2: Pointer): Integer;
  867. begin
  868. Result := FOnCompare(T(Item1^), T(Item2^));
  869. end;
  870. procedure TFPGInterfacedObjectList.Put(Index: Integer; const Item: T);
  871. begin
  872. inherited Put(Index, @Item);
  873. end;
  874. function TFPGInterfacedObjectList.Add(const Item: T): Integer;
  875. begin
  876. Result := inherited Add(@Item);
  877. end;
  878. function TFPGInterfacedObjectList.Extract(const Item: T): T;
  879. var
  880. ResPtr: Pointer;
  881. begin
  882. ResPtr := inherited Extract(@Item);
  883. if ResPtr <> nil then
  884. Result := T(ResPtr^)
  885. else
  886. FillByte(Result, sizeof(T), 0);
  887. end;
  888. function TFPGInterfacedObjectList.First: T;
  889. begin
  890. Result := T(inherited First^);
  891. end;
  892. function TFPGInterfacedObjectList.GetEnumerator: TFPGListEnumeratorSpec;
  893. begin
  894. Result := TFPGListEnumeratorSpec.Create(Self);
  895. end;
  896. function TFPGInterfacedObjectList.IndexOf(const Item: T): Integer;
  897. begin
  898. Result := 0;
  899. {$info TODO: fix inlining to work! InternalItems[Result]^}
  900. while (Result < FCount) and (PT(FList)[Result] <> Item) do
  901. Inc(Result);
  902. if Result = FCount then
  903. Result := -1;
  904. end;
  905. procedure TFPGInterfacedObjectList.Insert(Index: Integer; const Item: T);
  906. begin
  907. T(inherited Insert(Index)^) := Item;
  908. end;
  909. function TFPGInterfacedObjectList.Last: T;
  910. begin
  911. Result := T(inherited Last^);
  912. end;
  913. {$ifndef VER2_4}
  914. procedure TFPGInterfacedObjectList.Assign(Source: TFPGInterfacedObjectList);
  915. var
  916. i: Integer;
  917. begin
  918. Clear;
  919. for I := 0 to Source.Count - 1 do
  920. Add(Source[i]);
  921. end;
  922. {$endif VER2_4}
  923. function TFPGInterfacedObjectList.Remove(const Item: T): Integer;
  924. begin
  925. Result := IndexOf(Item);
  926. if Result >= 0 then
  927. Delete(Result);
  928. end;
  929. procedure TFPGInterfacedObjectList.Sort(Compare: TCompareFunc);
  930. begin
  931. FOnCompare := Compare;
  932. inherited Sort(@ItemPtrCompare);
  933. end;
  934. {****************************************************************************
  935. TFPSMap
  936. ****************************************************************************}
  937. constructor TFPSMap.Create(AKeySize: Integer; ADataSize: integer);
  938. begin
  939. inherited Create(AKeySize+ADataSize);
  940. FKeySize := AKeySize;
  941. FDataSize := ADataSize;
  942. InitOnPtrCompare;
  943. end;
  944. procedure TFPSMap.CopyKey(Src, Dest: Pointer);
  945. begin
  946. System.Move(Src^, Dest^, FKeySize);
  947. end;
  948. procedure TFPSMap.CopyData(Src, Dest: Pointer);
  949. begin
  950. System.Move(Src^, Dest^, FDataSize);
  951. end;
  952. function TFPSMap.GetKey(Index: Integer): Pointer;
  953. begin
  954. Result := Items[Index];
  955. end;
  956. function TFPSMap.GetData(Index: Integer): Pointer;
  957. begin
  958. Result := PByte(Items[Index])+FKeySize;
  959. end;
  960. function TFPSMap.GetKeyData(AKey: Pointer): Pointer;
  961. var
  962. I: Integer;
  963. begin
  964. I := IndexOf(AKey);
  965. if I >= 0 then
  966. Result := InternalItems[I]+FKeySize
  967. else
  968. Error(SMapKeyError, PtrUInt(AKey));
  969. end;
  970. function TFPSMap.BinaryCompareKey(Key1, Key2: Pointer): Integer;
  971. begin
  972. Result := CompareByte(Key1^, Key2^, FKeySize);
  973. end;
  974. function TFPSMap.BinaryCompareData(Data1, Data2: Pointer): Integer;
  975. begin
  976. Result := CompareByte(Data1^, Data1^, FDataSize);
  977. end;
  978. procedure TFPSMap.SetOnKeyPtrCompare(Proc: TFPSListCompareFunc);
  979. begin
  980. if Proc <> nil then
  981. FOnKeyPtrCompare := Proc
  982. else
  983. FOnKeyPtrCompare := @BinaryCompareKey;
  984. end;
  985. procedure TFPSMap.SetOnDataPtrCompare(Proc: TFPSListCompareFunc);
  986. begin
  987. if Proc <> nil then
  988. FOnDataPtrCompare := Proc
  989. else
  990. FOnDataPtrCompare := @BinaryCompareData;
  991. end;
  992. procedure TFPSMap.InitOnPtrCompare;
  993. begin
  994. SetOnKeyPtrCompare(nil);
  995. SetOnDataPtrCompare(nil);
  996. end;
  997. procedure TFPSMap.PutKey(Index: Integer; AKey: Pointer);
  998. begin
  999. if FSorted then
  1000. Error(SSortedListError, 0);
  1001. CopyKey(AKey, Items[Index]);
  1002. end;
  1003. procedure TFPSMap.PutData(Index: Integer; AData: Pointer);
  1004. begin
  1005. CopyData(AData, PByte(Items[Index])+FKeySize);
  1006. end;
  1007. procedure TFPSMap.PutKeyData(AKey: Pointer; NewData: Pointer);
  1008. var
  1009. I: Integer;
  1010. begin
  1011. I := IndexOf(AKey);
  1012. if I >= 0 then
  1013. Data[I] := NewData
  1014. else
  1015. Add(AKey, NewData);
  1016. end;
  1017. procedure TFPSMap.SetSorted(Value: Boolean);
  1018. begin
  1019. if Value = FSorted then exit;
  1020. FSorted := Value;
  1021. if Value then Sort;
  1022. end;
  1023. function TFPSMap.Add(AKey: Pointer): Integer;
  1024. begin
  1025. if Sorted then
  1026. begin
  1027. if Find(AKey, Result) then
  1028. case Duplicates of
  1029. dupIgnore: exit;
  1030. dupError: Error(SDuplicateItem, 0)
  1031. end;
  1032. end else
  1033. Result := Count;
  1034. CopyKey(AKey, inherited Insert(Result));
  1035. end;
  1036. function TFPSMap.Add(AKey, AData: Pointer): Integer;
  1037. begin
  1038. Result := Add(AKey);
  1039. Data[Result] := AData;
  1040. end;
  1041. function TFPSMap.Find(AKey: Pointer; out Index: Integer): Boolean;
  1042. { Searches for the first item <= Key, returns True if exact match,
  1043. sets index to the index f the found string. }
  1044. var
  1045. I,L,R,Dir: Integer;
  1046. begin
  1047. Result := false;
  1048. // Use binary search.
  1049. L := 0;
  1050. R := FCount-1;
  1051. while L<=R do
  1052. begin
  1053. I := (L+R) div 2;
  1054. Dir := FOnKeyPtrCompare(Items[I], AKey);
  1055. if Dir < 0 then
  1056. L := I+1
  1057. else begin
  1058. R := I-1;
  1059. if Dir = 0 then
  1060. begin
  1061. Result := true;
  1062. if Duplicates <> dupAccept then
  1063. L := I;
  1064. end;
  1065. end;
  1066. end;
  1067. Index := L;
  1068. end;
  1069. function TFPSMap.LinearIndexOf(AKey: Pointer): Integer;
  1070. var
  1071. ListItem: Pointer;
  1072. begin
  1073. Result := 0;
  1074. ListItem := First;
  1075. while (Result < FCount) and (FOnKeyPtrCompare(ListItem, AKey) <> 0) do
  1076. begin
  1077. Inc(Result);
  1078. ListItem := PByte(ListItem)+FItemSize;
  1079. end;
  1080. if Result = FCount then Result := -1;
  1081. end;
  1082. function TFPSMap.IndexOf(AKey: Pointer): Integer;
  1083. begin
  1084. if Sorted then
  1085. begin
  1086. if not Find(AKey, Result) then
  1087. Result := -1;
  1088. end else
  1089. Result := LinearIndexOf(AKey);
  1090. end;
  1091. function TFPSMap.IndexOfData(AData: Pointer): Integer;
  1092. var
  1093. ListItem: Pointer;
  1094. begin
  1095. Result := 0;
  1096. ListItem := First+FKeySize;
  1097. while (Result < FCount) and (FOnDataPtrCompare(ListItem, AData) <> 0) do
  1098. begin
  1099. Inc(Result);
  1100. ListItem := PByte(ListItem)+FItemSize;
  1101. end;
  1102. if Result = FCount then Result := -1;
  1103. end;
  1104. function TFPSMap.Insert(Index: Integer): Pointer;
  1105. begin
  1106. if FSorted then
  1107. Error(SSortedListError, 0);
  1108. Result := inherited Insert(Index);
  1109. end;
  1110. procedure TFPSMap.Insert(Index: Integer; out AKey, AData: Pointer);
  1111. begin
  1112. AKey := Insert(Index);
  1113. AData := PByte(AKey) + FKeySize;
  1114. end;
  1115. procedure TFPSMap.InsertKey(Index: Integer; AKey: Pointer);
  1116. begin
  1117. CopyKey(AKey, Insert(Index));
  1118. end;
  1119. procedure TFPSMap.InsertKeyData(Index: Integer; AKey, AData: Pointer);
  1120. var
  1121. ListItem: Pointer;
  1122. begin
  1123. ListItem := Insert(Index);
  1124. CopyKey(AKey, ListItem);
  1125. CopyData(AData, PByte(ListItem)+FKeySize);
  1126. end;
  1127. function TFPSMap.Remove(AKey: Pointer): Integer;
  1128. begin
  1129. Result := IndexOf(AKey);
  1130. if Result >= 0 then
  1131. Delete(Result);
  1132. end;
  1133. procedure TFPSMap.Sort;
  1134. begin
  1135. inherited Sort(FOnKeyPtrCompare);
  1136. end;
  1137. {****************************************************************************
  1138. TFPGMap
  1139. ****************************************************************************}
  1140. constructor TFPGMap.Create;
  1141. begin
  1142. inherited Create(SizeOf(TKey), SizeOf(TData));
  1143. end;
  1144. procedure TFPGMap.CopyItem(Src, Dest: Pointer);
  1145. begin
  1146. CopyKey(Src, Dest);
  1147. CopyData(PByte(Src)+KeySize, PByte(Dest)+KeySize);
  1148. end;
  1149. procedure TFPGMap.CopyKey(Src, Dest: Pointer);
  1150. begin
  1151. TKey(Dest^) := TKey(Src^);
  1152. end;
  1153. procedure TFPGMap.CopyData(Src, Dest: Pointer);
  1154. begin
  1155. TData(Dest^) := TData(Src^);
  1156. end;
  1157. procedure TFPGMap.Deref(Item: Pointer);
  1158. begin
  1159. Finalize(TKey(Item^));
  1160. Finalize(TData(Pointer(PByte(Item)+KeySize)^));
  1161. end;
  1162. function TFPGMap.GetKey(Index: Integer): TKey;
  1163. begin
  1164. Result := TKey(inherited GetKey(Index)^);
  1165. end;
  1166. function TFPGMap.GetData(Index: Integer): TData;
  1167. begin
  1168. Result := TData(inherited GetData(Index)^);
  1169. end;
  1170. function TFPGMap.GetKeyData(const AKey: TKey): TData;
  1171. begin
  1172. Result := TData(inherited GetKeyData(@AKey)^);
  1173. end;
  1174. function TFPGMap.KeyCompare(Key1, Key2: Pointer): Integer;
  1175. begin
  1176. if PKey(Key1)^ < PKey(Key2)^ then
  1177. Result := -1
  1178. else if PKey(Key1)^ > PKey(Key2)^ then
  1179. Result := 1
  1180. else
  1181. Result := 0;
  1182. end;
  1183. {function TFPGMap.DataCompare(Data1, Data2: Pointer): Integer;
  1184. begin
  1185. if PData(Data1)^ < PData(Data2)^ then
  1186. Result := -1
  1187. else if PData(Data1)^ > PData(Data2)^ then
  1188. Result := 1
  1189. else
  1190. Result := 0;
  1191. end;}
  1192. function TFPGMap.KeyCustomCompare(Key1, Key2: Pointer): Integer;
  1193. begin
  1194. Result := FOnKeyCompare(TKey(Key1^), TKey(Key2^));
  1195. end;
  1196. function TFPGMap.DataCustomCompare(Data1, Data2: Pointer): Integer;
  1197. begin
  1198. Result := FOnDataCompare(TData(Data1^), TData(Data2^));
  1199. end;
  1200. procedure TFPGMap.SetOnKeyCompare(NewCompare: TKeyCompareFunc);
  1201. begin
  1202. FOnKeyCompare := NewCompare;
  1203. if NewCompare <> nil then
  1204. OnKeyPtrCompare := @KeyCustomCompare
  1205. else
  1206. OnKeyPtrCompare := @KeyCompare;
  1207. end;
  1208. procedure TFPGMap.SetOnDataCompare(NewCompare: TDataCompareFunc);
  1209. begin
  1210. FOnDataCompare := NewCompare;
  1211. if NewCompare <> nil then
  1212. OnDataPtrCompare := @DataCustomCompare
  1213. else
  1214. OnDataPtrCompare := nil;
  1215. end;
  1216. procedure TFPGMap.InitOnPtrCompare;
  1217. begin
  1218. SetOnKeyCompare(nil);
  1219. SetOnDataCompare(nil);
  1220. end;
  1221. procedure TFPGMap.PutKey(Index: Integer; const NewKey: TKey);
  1222. begin
  1223. inherited PutKey(Index, @NewKey);
  1224. end;
  1225. procedure TFPGMap.PutData(Index: Integer; const NewData: TData);
  1226. begin
  1227. inherited PutData(Index, @NewData);
  1228. end;
  1229. procedure TFPGMap.PutKeyData(const AKey: TKey; const NewData: TData);
  1230. begin
  1231. inherited PutKeyData(@AKey, @NewData);
  1232. end;
  1233. function TFPGMap.Add(const AKey: TKey): Integer;
  1234. begin
  1235. Result := inherited Add(@AKey);
  1236. end;
  1237. function TFPGMap.Add(const AKey: TKey; const AData: TData): Integer;
  1238. begin
  1239. Result := inherited Add(@AKey, @AData);
  1240. end;
  1241. function TFPGMap.Find(const AKey: TKey; out Index: Integer): Boolean;
  1242. begin
  1243. Result := inherited Find(@AKey, Index);
  1244. end;
  1245. function TFPGMap.IndexOf(const AKey: TKey): Integer;
  1246. begin
  1247. Result := inherited IndexOf(@AKey);
  1248. end;
  1249. function TFPGMap.IndexOfData(const AData: TData): Integer;
  1250. begin
  1251. { TODO: loop ? }
  1252. Result := inherited IndexOfData(@AData);
  1253. end;
  1254. procedure TFPGMap.InsertKey(Index: Integer; const AKey: TKey);
  1255. begin
  1256. inherited InsertKey(Index, @AKey);
  1257. end;
  1258. procedure TFPGMap.InsertKeyData(Index: Integer; const AKey: TKey; const AData: TData);
  1259. begin
  1260. inherited InsertKeyData(Index, @AKey, @AData);
  1261. end;
  1262. function TFPGMap.Remove(const AKey: TKey): Integer;
  1263. begin
  1264. Result := inherited Remove(@AKey);
  1265. end;
  1266. {****************************************************************************
  1267. TFPGMapInterfacedObjectData
  1268. ****************************************************************************}
  1269. constructor TFPGMapInterfacedObjectData.Create;
  1270. begin
  1271. inherited Create(SizeOf(TKey), SizeOf(TData));
  1272. end;
  1273. procedure TFPGMapInterfacedObjectData.CopyItem(Src, Dest: Pointer);
  1274. begin
  1275. CopyKey(Src, Dest);
  1276. CopyData(PByte(Src)+KeySize, PByte(Dest)+KeySize);
  1277. end;
  1278. procedure TFPGMapInterfacedObjectData.CopyKey(Src, Dest: Pointer);
  1279. begin
  1280. TKey(Dest^) := TKey(Src^);
  1281. end;
  1282. procedure TFPGMapInterfacedObjectData.CopyData(Src, Dest: Pointer);
  1283. begin
  1284. if Assigned(Pointer(Dest^)) then
  1285. TData(Dest^)._Release;
  1286. TData(Dest^) := TData(Src^);
  1287. if Assigned(Pointer(Dest^)) then
  1288. TData(Dest^)._AddRef;
  1289. end;
  1290. procedure TFPGMapInterfacedObjectData.Deref(Item: Pointer);
  1291. begin
  1292. Finalize(TKey(Item^));
  1293. if Assigned(PPointer(PByte(Item)+KeySize)^) then
  1294. TData(Pointer(PByte(Item)+KeySize)^)._Release;
  1295. end;
  1296. function TFPGMapInterfacedObjectData.GetKey(Index: Integer): TKey;
  1297. begin
  1298. Result := TKey(inherited GetKey(Index)^);
  1299. end;
  1300. function TFPGMapInterfacedObjectData.GetData(Index: Integer): TData;
  1301. begin
  1302. Result := TData(inherited GetData(Index)^);
  1303. end;
  1304. function TFPGMapInterfacedObjectData.GetKeyData(const AKey: TKey): TData;
  1305. begin
  1306. Result := TData(inherited GetKeyData(@AKey)^);
  1307. end;
  1308. function TFPGMapInterfacedObjectData.KeyCompare(Key1, Key2: Pointer): Integer;
  1309. begin
  1310. if PKey(Key1)^ < PKey(Key2)^ then
  1311. Result := -1
  1312. else if PKey(Key1)^ > PKey(Key2)^ then
  1313. Result := 1
  1314. else
  1315. Result := 0;
  1316. end;
  1317. {function TFPGMapInterfacedObjectData.DataCompare(Data1, Data2: Pointer): Integer;
  1318. begin
  1319. if PData(Data1)^ < PData(Data2)^ then
  1320. Result := -1
  1321. else if PData(Data1)^ > PData(Data2)^ then
  1322. Result := 1
  1323. else
  1324. Result := 0;
  1325. end;}
  1326. function TFPGMapInterfacedObjectData.KeyCustomCompare(Key1, Key2: Pointer): Integer;
  1327. begin
  1328. Result := FOnKeyCompare(TKey(Key1^), TKey(Key2^));
  1329. end;
  1330. function TFPGMapInterfacedObjectData.DataCustomCompare(Data1, Data2: Pointer): Integer;
  1331. begin
  1332. Result := FOnDataCompare(TData(Data1^), TData(Data2^));
  1333. end;
  1334. procedure TFPGMapInterfacedObjectData.SetOnKeyCompare(NewCompare: TKeyCompareFunc);
  1335. begin
  1336. FOnKeyCompare := NewCompare;
  1337. if NewCompare <> nil then
  1338. OnKeyPtrCompare := @KeyCustomCompare
  1339. else
  1340. OnKeyPtrCompare := @KeyCompare;
  1341. end;
  1342. procedure TFPGMapInterfacedObjectData.SetOnDataCompare(NewCompare: TDataCompareFunc);
  1343. begin
  1344. FOnDataCompare := NewCompare;
  1345. if NewCompare <> nil then
  1346. OnDataPtrCompare := @DataCustomCompare
  1347. else
  1348. OnDataPtrCompare := nil;
  1349. end;
  1350. procedure TFPGMapInterfacedObjectData.InitOnPtrCompare;
  1351. begin
  1352. SetOnKeyCompare(nil);
  1353. SetOnDataCompare(nil);
  1354. end;
  1355. procedure TFPGMapInterfacedObjectData.PutKey(Index: Integer; const NewKey: TKey);
  1356. begin
  1357. inherited PutKey(Index, @NewKey);
  1358. end;
  1359. procedure TFPGMapInterfacedObjectData.PutData(Index: Integer; const NewData: TData);
  1360. begin
  1361. inherited PutData(Index, @NewData);
  1362. end;
  1363. procedure TFPGMapInterfacedObjectData.PutKeyData(const AKey: TKey; const NewData: TData);
  1364. begin
  1365. inherited PutKeyData(@AKey, @NewData);
  1366. end;
  1367. function TFPGMapInterfacedObjectData.Add(const AKey: TKey): Integer;
  1368. begin
  1369. Result := inherited Add(@AKey);
  1370. end;
  1371. function TFPGMapInterfacedObjectData.Add(const AKey: TKey; const AData: TData): Integer;
  1372. begin
  1373. Result := inherited Add(@AKey, @AData);
  1374. end;
  1375. function TFPGMapInterfacedObjectData.Find(const AKey: TKey; out Index: Integer): Boolean;
  1376. begin
  1377. Result := inherited Find(@AKey, Index);
  1378. end;
  1379. function TFPGMapInterfacedObjectData.IndexOf(const AKey: TKey): Integer;
  1380. begin
  1381. Result := inherited IndexOf(@AKey);
  1382. end;
  1383. function TFPGMapInterfacedObjectData.IndexOfData(const AData: TData): Integer;
  1384. begin
  1385. { TODO: loop ? }
  1386. Result := inherited IndexOfData(@AData);
  1387. end;
  1388. procedure TFPGMapInterfacedObjectData.InsertKey(Index: Integer; const AKey: TKey);
  1389. begin
  1390. inherited InsertKey(Index, @AKey);
  1391. end;
  1392. procedure TFPGMapInterfacedObjectData.InsertKeyData(Index: Integer; const AKey: TKey; const AData: TData);
  1393. begin
  1394. inherited InsertKeyData(Index, @AKey, @AData);
  1395. end;
  1396. function TFPGMapInterfacedObjectData.Remove(const AKey: TKey): Integer;
  1397. begin
  1398. Result := inherited Remove(@AKey);
  1399. end;
  1400. end.