fgl.pp 59 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118
  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 FGLINLINE}
  14. {$ifdef FGLINLINE}
  15. {$inline on}
  16. {$endif FGLINLINE}
  17. {$IFNDEF FPC_DOTTEDUNITS}
  18. unit fgl;
  19. {$ENDIF FPC_DOTTEDUNITS}
  20. interface
  21. {$IFDEF FPC_DOTTEDUNITS}
  22. uses
  23. System.Types, System.SysUtils, System.SortBase;
  24. {$ELSE FPC_DOTTEDUNITS}
  25. uses
  26. types, sysutils, sortbase;
  27. {$ENDIF FPC_DOTTEDUNITS}
  28. const
  29. MaxListSize = Maxint div 16;
  30. type
  31. EListError = class(Exception);
  32. TFPSList = class;
  33. TFPSListCompareFunc = function(Key1, Key2: Pointer): Integer of object;
  34. { TFPSList }
  35. TFPSList = class(TObject)
  36. protected
  37. FList: PByte;
  38. FCount: Integer;
  39. FCapacity: Integer; { list has room for capacity+1 items, contains room for a temporary item }
  40. FItemSize: Integer;
  41. procedure CopyItem(Src, Dest: Pointer); virtual;
  42. procedure CopyItems(Src, Dest: Pointer; aCount : Integer); virtual;
  43. procedure Deref(Item: Pointer); virtual; overload;
  44. procedure Deref(FromIndex, ToIndex: Integer); overload;
  45. function Get(Index: Integer): Pointer;
  46. procedure InternalExchange(Index1, Index2: Integer);
  47. function InternalGet(Index: Integer): Pointer; {$ifdef FGLINLINE} inline; {$endif}
  48. procedure InternalPut(Index: Integer; NewItem: Pointer);
  49. procedure Put(Index: Integer; Item: Pointer);
  50. procedure QuickSort(L, R: Integer; Compare: TFPSListCompareFunc);
  51. procedure SetCapacity(NewCapacity: Integer);
  52. procedure SetCount(NewCount: Integer);
  53. procedure RaiseIndexError(Index : Integer);
  54. property InternalItems[Index: Integer]: Pointer read InternalGet write InternalPut;
  55. function GetLast: Pointer;
  56. procedure SetLast(const Value: Pointer);
  57. function GetFirst: Pointer;
  58. procedure SetFirst(const Value: Pointer);
  59. Procedure CheckIndex(AIndex : Integer); inline;
  60. public
  61. constructor Create(AItemSize: Integer = sizeof(Pointer));
  62. destructor Destroy; override;
  63. class Function ItemIsManaged : Boolean; virtual;
  64. function Add(Item: Pointer): Integer;
  65. procedure Clear;
  66. procedure Delete(Index: Integer);
  67. procedure DeleteRange(IndexFrom, IndexTo : Integer);
  68. class procedure Error(const Msg: string; Data: PtrInt);
  69. procedure Exchange(Index1, Index2: Integer);
  70. function Expand: TFPSList;
  71. procedure Extract(Item: Pointer; ResultPtr: Pointer);
  72. function IndexOf(Item: Pointer): Integer;
  73. procedure Insert(Index: Integer; Item: Pointer);
  74. function Insert(Index: Integer): Pointer;
  75. procedure Move(CurIndex, NewIndex: Integer);
  76. procedure Assign(Obj: TFPSList);
  77. procedure AddList(Obj: TFPSList);
  78. function Remove(Item: Pointer): Integer;
  79. procedure Pack;
  80. procedure Sort(Compare: TFPSListCompareFunc);
  81. procedure Sort(Compare: TFPSListCompareFunc; SortingAlgorithm: PSortingAlgorithm);
  82. property Capacity: Integer read FCapacity write SetCapacity;
  83. property Count: Integer read FCount write SetCount;
  84. property Items[Index: Integer]: Pointer read Get write Put; default;
  85. property ItemSize: Integer read FItemSize;
  86. property List: PByte read FList;
  87. property First: Pointer read GetFirst write SetFirst;
  88. property Last: Pointer read GetLast write SetLast;
  89. end;
  90. const
  91. {$ifdef cpu16}
  92. MaxGListSize = {MaxInt div} 1024 deprecated;
  93. {$else cpu16}
  94. MaxGListSize = MaxInt div 1024 deprecated;
  95. {$endif cpu16}
  96. type
  97. generic TFPGListEnumerator<T> = class(TObject)
  98. protected
  99. FList: TFPSList;
  100. FPosition: Integer;
  101. function GetCurrent: T;
  102. public
  103. constructor Create(AList: TFPSList);
  104. function MoveNext: Boolean;
  105. property Current: T read GetCurrent;
  106. end;
  107. { TFPGList }
  108. generic TFPGList<T> = class(TFPSList)
  109. private
  110. type
  111. TCompareFunc = function(const Item1, Item2: T): Integer;
  112. PT = ^T;
  113. TTypeList = PT;
  114. PTypeList = ^TTypeList;
  115. protected
  116. var
  117. FOnCompare: TCompareFunc;
  118. procedure CopyItem(Src, Dest: Pointer); override;
  119. procedure Deref(Item: Pointer); override;
  120. function Get(Index: Integer): T; {$ifdef FGLINLINE} inline; {$endif}
  121. function GetList: PTypeList; {$ifdef FGLINLINE} inline; {$endif}
  122. function ItemPtrCompare(Item1, Item2: Pointer): Integer;
  123. procedure Put(Index: Integer; const Item: T); {$ifdef FGLINLINE} inline; {$endif}
  124. function GetLast: T; {$ifdef FGLINLINE} inline; {$endif}
  125. procedure SetLast(const Value: T); {$ifdef FGLINLINE} inline; {$endif}
  126. function GetFirst: T; {$ifdef FGLINLINE} inline; {$endif}
  127. procedure SetFirst(const Value: T); {$ifdef FGLINLINE} inline; {$endif}
  128. public
  129. Type
  130. TFPGListEnumeratorSpec = specialize TFPGListEnumerator<T>;
  131. constructor Create;
  132. class Function ItemIsManaged : Boolean; override;
  133. function Add(const Item: T): Integer; {$ifdef FGLINLINE} inline; {$endif}
  134. function Extract(const Item: T): T; {$ifdef FGLINLINE} inline; {$endif}
  135. property First: T read GetFirst write SetFirst;
  136. function GetEnumerator: TFPGListEnumeratorSpec; {$ifdef FGLINLINE} inline; {$endif}
  137. function IndexOf(const Item: T): Integer;
  138. procedure Insert(Index: Integer; const Item: T); {$ifdef FGLINLINE} inline; {$endif}
  139. property Last: T read GetLast write SetLast;
  140. procedure Assign(Source: TFPGList);
  141. procedure AddList(Source: TFPGList);
  142. function Remove(const Item: T): Integer; {$ifdef FGLINLINE} inline; {$endif}
  143. procedure Sort(Compare: TCompareFunc);
  144. procedure Sort(Compare: TCompareFunc; SortingAlgorithm: PSortingAlgorithm);
  145. property Items[Index: Integer]: T read Get write Put; default;
  146. property List: PTypeList read GetList;
  147. end;
  148. generic TFPGObjectList<T: TObject> = class(TFPSList)
  149. private
  150. type
  151. TCompareFunc = function(const Item1, Item2: T): Integer;
  152. PT = ^T;
  153. TTypeList = PT;
  154. PTypeList = ^TTypeList;
  155. TFPGListEnumeratorSpec = specialize TFPGListEnumerator<T>;
  156. protected
  157. var
  158. FOnCompare: TCompareFunc;
  159. FFreeObjects: Boolean;
  160. procedure CopyItem(Src, Dest: Pointer); override;
  161. procedure Deref(Item: Pointer); override;
  162. function Get(Index: Integer): T; {$ifdef FGLINLINE} inline; {$endif}
  163. function GetList: PTypeList; {$ifdef FGLINLINE} inline; {$endif}
  164. function ItemPtrCompare(Item1, Item2: Pointer): Integer;
  165. procedure Put(Index: Integer; const Item: T); {$ifdef FGLINLINE} inline; {$endif}
  166. function GetLast: T; {$ifdef FGLINLINE} inline; {$endif}
  167. procedure SetLast(const Value: T); {$ifdef FGLINLINE} inline; {$endif}
  168. function GetFirst: T; {$ifdef FGLINLINE} inline; {$endif}
  169. procedure SetFirst(const Value: T); {$ifdef FGLINLINE} inline; {$endif}
  170. public
  171. constructor Create(FreeObjects: Boolean = True);
  172. function Add(const Item: T): Integer; {$ifdef FGLINLINE} inline; {$endif}
  173. function Extract(const Item: T): T; {$ifdef FGLINLINE} inline; {$endif}
  174. property First: T read GetFirst write SetFirst;
  175. function GetEnumerator: TFPGListEnumeratorSpec; {$ifdef FGLINLINE} inline; {$endif}
  176. function IndexOf(const Item: T): Integer;
  177. procedure Insert(Index: Integer; const Item: T); {$ifdef FGLINLINE} inline; {$endif}
  178. property Last: T read GetLast write SetLast;
  179. procedure AddList(Source: TFPGObjectList);
  180. procedure Assign(Source: TFPGObjectList);
  181. function Remove(const Item: T): Integer; {$ifdef FGLINLINE} inline; {$endif}
  182. procedure Sort(Compare: TCompareFunc);
  183. procedure Sort(Compare: TCompareFunc; SortingAlgorithm: PSortingAlgorithm);
  184. property Items[Index: Integer]: T read Get write Put; default;
  185. property List: PTypeList read GetList;
  186. property FreeObjects: Boolean read FFreeObjects write FFreeObjects;
  187. end;
  188. generic TFPGInterfacedObjectList<T> = class(TFPSList)
  189. private
  190. type
  191. TCompareFunc = function(const Item1, Item2: T): Integer;
  192. PT = ^T;
  193. TTypeList = PT;
  194. PTypeList = ^TTypeList;
  195. TFPGListEnumeratorSpec = specialize TFPGListEnumerator<T>;
  196. protected
  197. var
  198. FOnCompare: TCompareFunc;
  199. procedure CopyItem(Src, Dest: Pointer); override;
  200. procedure Deref(Item: Pointer); override;
  201. function Get(Index: Integer): T; {$ifdef FGLINLINE} inline; {$endif}
  202. function GetList: PTypeList; {$ifdef FGLINLINE} inline; {$endif}
  203. function ItemPtrCompare(Item1, Item2: Pointer): Integer;
  204. procedure Put(Index: Integer; const Item: T); {$ifdef FGLINLINE} inline; {$endif}
  205. function GetLast: T; {$ifdef FGLINLINE} inline; {$endif}
  206. procedure SetLast(const Value: T); {$ifdef FGLINLINE} inline; {$endif}
  207. function GetFirst: T; {$ifdef FGLINLINE} inline; {$endif}
  208. procedure SetFirst(const Value: T); {$ifdef FGLINLINE} inline; {$endif}
  209. public
  210. constructor Create;
  211. function Add(const Item: T): Integer; {$ifdef FGLINLINE} inline; {$endif}
  212. function Extract(const Item: T): T; {$ifdef FGLINLINE} inline; {$endif}
  213. property First: T read GetFirst write SetFirst;
  214. function GetEnumerator: TFPGListEnumeratorSpec; {$ifdef FGLINLINE} inline; {$endif}
  215. function IndexOf(const Item: T): Integer;
  216. procedure Insert(Index: Integer; const Item: T); {$ifdef FGLINLINE} inline; {$endif}
  217. property Last: T read GetLast write SetLast;
  218. procedure Assign(Source: TFPGInterfacedObjectList);
  219. procedure AddList(Source: TFPGInterfacedObjectList);
  220. function Remove(const Item: T): Integer; {$ifdef FGLINLINE} inline; {$endif}
  221. procedure Sort(Compare: TCompareFunc);
  222. procedure Sort(Compare: TCompareFunc; SortingAlgorithm: PSortingAlgorithm);
  223. property Items[Index: Integer]: T read Get write Put; default;
  224. property List: PTypeList read GetList;
  225. end;
  226. TFPSMap = class(TFPSList)
  227. private
  228. FKeySize: Integer;
  229. FDataSize: Integer;
  230. FDuplicates: TDuplicates;
  231. FSorted: Boolean;
  232. FOnKeyPtrCompare: TFPSListCompareFunc;
  233. FOnDataPtrCompare: TFPSListCompareFunc;
  234. procedure SetSorted(Value: Boolean);
  235. protected
  236. function BinaryCompareKey(Key1, Key2: Pointer): Integer;
  237. function BinaryCompareData(Data1, Data2: Pointer): Integer;
  238. procedure SetOnKeyPtrCompare(Proc: TFPSListCompareFunc);
  239. procedure SetOnDataPtrCompare(Proc: TFPSListCompareFunc);
  240. procedure InitOnPtrCompare; virtual;
  241. procedure CopyKey(Src, Dest: Pointer); virtual;
  242. procedure CopyData(Src, Dest: Pointer); virtual;
  243. function GetKey(Index: Integer): Pointer;
  244. function GetKeyData(AKey: Pointer): Pointer;
  245. function GetData(Index: Integer): Pointer;
  246. function LinearIndexOf(AKey: Pointer): Integer;
  247. procedure PutKey(Index: Integer; AKey: Pointer);
  248. procedure PutKeyData(AKey: Pointer; NewData: Pointer);
  249. procedure PutData(Index: Integer; AData: Pointer);
  250. public
  251. constructor Create(AKeySize: Integer = sizeof(Pointer);
  252. ADataSize: integer = sizeof(Pointer));
  253. function Add(AKey, AData: Pointer): Integer;
  254. function Add(AKey: Pointer): Integer;
  255. function Find(AKey: Pointer; out Index: Integer): Boolean;
  256. function IndexOf(AKey: Pointer): Integer;
  257. function IndexOfData(AData: Pointer): Integer;
  258. function Insert(Index: Integer): Pointer;
  259. procedure Insert(Index: Integer; out AKey, AData: Pointer);
  260. procedure InsertKey(Index: Integer; AKey: Pointer);
  261. procedure InsertKeyData(Index: Integer; AKey, AData: Pointer);
  262. function Remove(AKey: Pointer): Integer;
  263. procedure Sort;
  264. procedure Sort(SortingAlgorithm: PSortingAlgorithm);
  265. property Duplicates: TDuplicates read FDuplicates write FDuplicates;
  266. property KeySize: Integer read FKeySize;
  267. property DataSize: Integer read FDataSize;
  268. property Keys[Index: Integer]: Pointer read GetKey write PutKey;
  269. property Data[Index: Integer]: Pointer read GetData write PutData;
  270. property KeyData[Key: Pointer]: Pointer read GetKeyData write PutKeyData; default;
  271. property Sorted: Boolean read FSorted write SetSorted;
  272. property OnPtrCompare: TFPSListCompareFunc read FOnKeyPtrCompare write SetOnKeyPtrCompare; //deprecated;
  273. property OnKeyPtrCompare: TFPSListCompareFunc read FOnKeyPtrCompare write SetOnKeyPtrCompare;
  274. property OnDataPtrCompare: TFPSListCompareFunc read FOnDataPtrCompare write SetOnDataPtrCompare;
  275. end;
  276. generic TFPGMap<TKey, TData> = class(TFPSMap)
  277. private
  278. type
  279. TKeyCompareFunc = function(const Key1, Key2: TKey): Integer;
  280. TDataCompareFunc = function(const Data1, Data2: TData): Integer;
  281. PKey = ^TKey;
  282. // unsed PData = ^TData;
  283. protected
  284. var
  285. FOnKeyCompare: TKeyCompareFunc;
  286. FOnDataCompare: TDataCompareFunc;
  287. procedure CopyItem(Src, Dest: Pointer); override;
  288. procedure CopyKey(Src, Dest: Pointer); override;
  289. procedure CopyData(Src, Dest: Pointer); override;
  290. procedure Deref(Item: Pointer); override;
  291. procedure InitOnPtrCompare; override;
  292. function GetKey(Index: Integer): TKey; {$ifdef FGLINLINE} inline; {$endif}
  293. function GetKeyData(const AKey: TKey): TData; {$ifdef FGLINLINE} inline; {$endif}
  294. function GetData(Index: Integer): TData; {$ifdef FGLINLINE} inline; {$endif}
  295. function KeyCompare(Key1, Key2: Pointer): Integer;
  296. function KeyCustomCompare(Key1, Key2: Pointer): Integer;
  297. //function DataCompare(Data1, Data2: Pointer): Integer;
  298. function DataCustomCompare(Data1, Data2: Pointer): Integer;
  299. procedure PutKey(Index: Integer; const NewKey: TKey); {$ifdef FGLINLINE} inline; {$endif}
  300. procedure PutKeyData(const AKey: TKey; const NewData: TData); {$ifdef FGLINLINE} inline; {$endif}
  301. procedure PutData(Index: Integer; const NewData: TData); {$ifdef FGLINLINE} inline; {$endif}
  302. procedure SetOnKeyCompare(NewCompare: TKeyCompareFunc);
  303. procedure SetOnDataCompare(NewCompare: TDataCompareFunc);
  304. public
  305. constructor Create;
  306. function Add(const AKey: TKey; const AData: TData): Integer; {$ifdef FGLINLINE} inline; {$endif}
  307. function Add(const AKey: TKey): Integer; {$ifdef FGLINLINE} inline; {$endif}
  308. function Find(const AKey: TKey; out Index: Integer): Boolean; {$ifdef FGLINLINE} inline; {$endif}
  309. function TryGetData(const AKey: TKey; out AData: TData): Boolean; {$ifdef FGLINLINE} inline; {$endif}
  310. procedure AddOrSetData(const AKey: TKey; const AData: TData); {$ifdef FGLINLINE} inline; {$endif}
  311. function IndexOf(const AKey: TKey): Integer; {$ifdef FGLINLINE} inline; {$endif}
  312. function IndexOfData(const AData: TData): Integer;
  313. procedure InsertKey(Index: Integer; const AKey: TKey);
  314. procedure InsertKeyData(Index: Integer; const AKey: TKey; const AData: TData);
  315. function Remove(const AKey: TKey): Integer;
  316. property Keys[Index: Integer]: TKey read GetKey write PutKey;
  317. property Data[Index: Integer]: TData read GetData write PutData;
  318. property KeyData[const AKey: TKey]: TData read GetKeyData write PutKeyData; default;
  319. property OnCompare: TKeyCompareFunc read FOnKeyCompare write SetOnKeyCompare; //deprecated;
  320. property OnKeyCompare: TKeyCompareFunc read FOnKeyCompare write SetOnKeyCompare;
  321. property OnDataCompare: TDataCompareFunc read FOnDataCompare write SetOnDataCompare;
  322. end;
  323. generic TFPGMapObject<TKey; TData: TObject> = class(TFPSMap)
  324. private
  325. type
  326. TKeyCompareFunc = function(const Key1, Key2: TKey): Integer;
  327. TDataCompareFunc = function(const Data1, Data2: TData): Integer;
  328. PKey = ^TKey;
  329. // unsed PData = ^TData;
  330. protected
  331. var
  332. FOnKeyCompare: TKeyCompareFunc;
  333. FOnDataCompare: TDataCompareFunc;
  334. FFreeObjects: Boolean;
  335. procedure CopyItem(Src, Dest: Pointer); override;
  336. procedure CopyKey(Src, Dest: Pointer); override;
  337. procedure CopyData(Src, Dest: Pointer); override;
  338. procedure Deref(Item: Pointer); override;
  339. procedure InitOnPtrCompare; override;
  340. function GetKey(Index: Integer): TKey; {$ifdef FGLINLINE} inline; {$endif}
  341. function GetKeyData(const AKey: TKey): TData; {$ifdef FGLINLINE} inline; {$endif}
  342. function GetData(Index: Integer): TData; {$ifdef FGLINLINE} inline; {$endif}
  343. function KeyCompare(Key1, Key2: Pointer): Integer;
  344. function KeyCustomCompare(Key1, Key2: Pointer): Integer;
  345. //function DataCompare(Data1, Data2: Pointer): Integer;
  346. function DataCustomCompare(Data1, Data2: Pointer): Integer;
  347. procedure PutKey(Index: Integer; const NewKey: TKey); {$ifdef FGLINLINE} inline; {$endif}
  348. procedure PutKeyData(const AKey: TKey; const NewData: TData); {$ifdef FGLINLINE} inline; {$endif}
  349. procedure PutData(Index: Integer; const NewData: TData); {$ifdef FGLINLINE} inline; {$endif}
  350. procedure SetOnKeyCompare(NewCompare: TKeyCompareFunc);
  351. procedure SetOnDataCompare(NewCompare: TDataCompareFunc);
  352. public
  353. constructor Create(AFreeObjects: Boolean);
  354. constructor Create;
  355. function Add(const AKey: TKey; const AData: TData): Integer; {$ifdef FGLINLINE} inline; {$endif}
  356. function Add(const AKey: TKey): Integer; {$ifdef FGLINLINE} inline; {$endif}
  357. function Find(const AKey: TKey; out Index: Integer): Boolean; {$ifdef FGLINLINE} inline; {$endif}
  358. function TryGetData(const AKey: TKey; out AData: TData): Boolean; {$ifdef FGLINLINE} inline; {$endif}
  359. procedure AddOrSetData(const AKey: TKey; const AData: TData); {$ifdef FGLINLINE} inline; {$endif}
  360. function IndexOf(const AKey: TKey): Integer; {$ifdef FGLINLINE} inline; {$endif}
  361. function IndexOfData(const AData: TData): Integer;
  362. procedure InsertKey(Index: Integer; const AKey: TKey);
  363. procedure InsertKeyData(Index: Integer; const AKey: TKey; const AData: TData);
  364. function Remove(const AKey: TKey): Integer;
  365. property Keys[Index: Integer]: TKey read GetKey write PutKey;
  366. property Data[Index: Integer]: TData read GetData write PutData;
  367. property KeyData[const AKey: TKey]: TData read GetKeyData write PutKeyData; default;
  368. property OnCompare: TKeyCompareFunc read FOnKeyCompare write SetOnKeyCompare; //deprecated;
  369. property OnKeyCompare: TKeyCompareFunc read FOnKeyCompare write SetOnKeyCompare;
  370. property OnDataCompare: TDataCompareFunc read FOnDataCompare write SetOnDataCompare;
  371. end;
  372. generic TFPGMapInterfacedObjectData<TKey, TData> = class(TFPSMap)
  373. private
  374. type
  375. TKeyCompareFunc = function(const Key1, Key2: TKey): Integer;
  376. TDataCompareFunc = function(const Data1, Data2: TData): Integer;
  377. PKey = ^TKey;
  378. // unsed PData = ^TData;
  379. protected
  380. var
  381. FOnKeyCompare: TKeyCompareFunc;
  382. FOnDataCompare: TDataCompareFunc;
  383. procedure CopyItem(Src, Dest: Pointer); override;
  384. procedure CopyKey(Src, Dest: Pointer); override;
  385. procedure CopyData(Src, Dest: Pointer); override;
  386. procedure Deref(Item: Pointer); override;
  387. procedure InitOnPtrCompare; override;
  388. function GetKey(Index: Integer): TKey; {$ifdef FGLINLINE} inline; {$endif}
  389. function GetKeyData(const AKey: TKey): TData; {$ifdef FGLINLINE} inline; {$endif}
  390. function GetData(Index: Integer): TData; {$ifdef FGLINLINE} inline; {$endif}
  391. function KeyCompare(Key1, Key2: Pointer): Integer;
  392. function KeyCustomCompare(Key1, Key2: Pointer): Integer;
  393. //function DataCompare(Data1, Data2: Pointer): Integer;
  394. function DataCustomCompare(Data1, Data2: Pointer): Integer;
  395. procedure PutKey(Index: Integer; const NewKey: TKey); {$ifdef FGLINLINE} inline; {$endif}
  396. procedure PutKeyData(const AKey: TKey; const NewData: TData); {$ifdef FGLINLINE} inline; {$endif}
  397. procedure PutData(Index: Integer; const NewData: TData); {$ifdef FGLINLINE} inline; {$endif}
  398. procedure SetOnKeyCompare(NewCompare: TKeyCompareFunc);
  399. procedure SetOnDataCompare(NewCompare: TDataCompareFunc);
  400. public
  401. constructor Create;
  402. function Add(const AKey: TKey; const AData: TData): Integer; {$ifdef FGLINLINE} inline; {$endif}
  403. function Add(const AKey: TKey): Integer; {$ifdef FGLINLINE} inline; {$endif}
  404. function Find(const AKey: TKey; out Index: Integer): Boolean; {$ifdef FGLINLINE} inline; {$endif}
  405. function TryGetData(const AKey: TKey; out AData: TData): Boolean; {$ifdef FGLINLINE} inline; {$endif}
  406. procedure AddOrSetData(const AKey: TKey; const AData: TData); {$ifdef FGLINLINE} inline; {$endif}
  407. function IndexOf(const AKey: TKey): Integer; {$ifdef FGLINLINE} inline; {$endif}
  408. function IndexOfData(const AData: TData): Integer;
  409. procedure InsertKey(Index: Integer; const AKey: TKey);
  410. procedure InsertKeyData(Index: Integer; const AKey: TKey; const AData: TData);
  411. function Remove(const AKey: TKey): Integer;
  412. property Keys[Index: Integer]: TKey read GetKey write PutKey;
  413. property Data[Index: Integer]: TData read GetData write PutData;
  414. property KeyData[const AKey: TKey]: TData read GetKeyData write PutKeyData; default;
  415. property OnCompare: TKeyCompareFunc read FOnKeyCompare write SetOnKeyCompare; //deprecated;
  416. property OnKeyCompare: TKeyCompareFunc read FOnKeyCompare write SetOnKeyCompare;
  417. property OnDataCompare: TDataCompareFunc read FOnDataCompare write SetOnDataCompare;
  418. end;
  419. implementation
  420. {$IFDEF FPC_DOTTEDUNITS}
  421. uses
  422. System.RtlConsts;
  423. {$ELSE FPC_DOTTEDUNITS}
  424. uses
  425. rtlconsts;
  426. {$ENDIF FPC_DOTTEDUNITS}
  427. {****************************************************************************
  428. TFPSList
  429. ****************************************************************************}
  430. constructor TFPSList.Create(AItemSize: integer);
  431. begin
  432. inherited Create;
  433. FItemSize := AItemSize;
  434. end;
  435. destructor TFPSList.Destroy;
  436. begin
  437. Clear;
  438. // Clear() does not clear the whole list; there is always a single temp entry
  439. // at the end which is never freed. Take care of that one here.
  440. FreeMem(FList);
  441. inherited Destroy;
  442. end;
  443. procedure TFPSList.CopyItem(Src, Dest: Pointer);
  444. begin
  445. System.Move(Src^, Dest^, FItemSize);
  446. end;
  447. procedure TFPSList.CopyItems(Src, Dest: Pointer; aCount: Integer);
  448. begin
  449. System.Move(Src^, Dest^, FItemSize*aCount);
  450. end;
  451. procedure TFPSList.RaiseIndexError(Index : Integer);
  452. begin
  453. Error(SListIndexError, Index);
  454. end;
  455. function TFPSList.InternalGet(Index: Integer): Pointer;
  456. begin
  457. Result:=FList+Index*ItemSize;
  458. end;
  459. procedure TFPSList.InternalPut(Index: Integer; NewItem: Pointer);
  460. var
  461. ListItem: Pointer;
  462. begin
  463. ListItem := InternalItems[Index];
  464. CopyItem(NewItem, ListItem);
  465. end;
  466. function TFPSList.Get(Index: Integer): Pointer;
  467. begin
  468. CheckIndex(Index);
  469. Result := InternalItems[Index];
  470. end;
  471. procedure TFPSList.Put(Index: Integer; Item: Pointer);
  472. var p : Pointer;
  473. begin
  474. CheckIndex(Index);
  475. p:=InternalItems[Index];
  476. if assigned(p) then
  477. DeRef(p);
  478. InternalItems[Index] := Item;
  479. end;
  480. procedure TFPSList.SetCapacity(NewCapacity: Integer);
  481. begin
  482. if (NewCapacity < FCount) or (NewCapacity > MaxListSize) then
  483. Error(SListCapacityError, NewCapacity);
  484. if NewCapacity = FCapacity then
  485. exit;
  486. ReallocMem(FList, (NewCapacity+1) * FItemSize);
  487. FillChar(InternalItems[FCapacity]^, (NewCapacity+1-FCapacity) * FItemSize, #0);
  488. FCapacity := NewCapacity;
  489. end;
  490. procedure TFPSList.Deref(Item: Pointer);
  491. begin
  492. end;
  493. procedure TFPSList.Deref(FromIndex, ToIndex: Integer);
  494. var
  495. ListItem, ListItemLast: Pointer;
  496. begin
  497. ListItem := InternalItems[FromIndex];
  498. ListItemLast := InternalItems[ToIndex];
  499. repeat
  500. Deref(ListItem);
  501. if ListItem = ListItemLast then
  502. break;
  503. ListItem := PByte(ListItem) + ItemSize;
  504. until false;
  505. end;
  506. procedure TFPSList.SetCount(NewCount: Integer);
  507. begin
  508. if (NewCount < 0) or (NewCount > MaxListSize) then
  509. Error(SListCountError, NewCount);
  510. if NewCount > FCapacity then
  511. SetCapacity(NewCount);
  512. if NewCount > FCount then
  513. FillByte(InternalItems[FCount]^, (NewCount-FCount) * FItemSize, 0)
  514. else if NewCount < FCount then
  515. Deref(NewCount, FCount-1);
  516. FCount := NewCount;
  517. end;
  518. function TFPSList.Add(Item: Pointer): Integer;
  519. begin
  520. if FCount = FCapacity then
  521. Self.Expand;
  522. CopyItem(Item, InternalItems[FCount]);
  523. Result := FCount;
  524. Inc(FCount);
  525. end;
  526. procedure TFPSList.CheckIndex(AIndex : Integer);
  527. begin
  528. if (AIndex < 0) or (AIndex >= FCount) then
  529. Error(SListIndexError, AIndex);
  530. end;
  531. class function TFPSList.ItemIsManaged: Boolean;
  532. begin
  533. Result:=False;
  534. end;
  535. procedure TFPSList.Clear;
  536. begin
  537. if Assigned(FList) then
  538. begin
  539. SetCount(0);
  540. SetCapacity(0);
  541. end;
  542. end;
  543. procedure TFPSList.Delete(Index: Integer);
  544. var
  545. ListItem: Pointer;
  546. begin
  547. CheckIndex(Index);
  548. Dec(FCount);
  549. ListItem := InternalItems[Index];
  550. Deref(ListItem);
  551. System.Move(InternalItems[Index+1]^, ListItem^, (FCount - Index) * FItemSize);
  552. // Shrink the list if appropriate
  553. if (FCapacity > 256) and (FCount < FCapacity shr 2) then
  554. begin
  555. FCapacity := FCapacity shr 1;
  556. ReallocMem(FList, (FCapacity+1) * FItemSize);
  557. end;
  558. { Keep the ending of the list filled with zeros, don't leave garbage data
  559. there. Otherwise, we could accidentally have there a copy of some item
  560. on the list, and accidentally Deref it too soon.
  561. See http://bugs.freepascal.org/view.php?id=20005. }
  562. FillChar(InternalItems[FCount]^, FItemSize, #0);
  563. end;
  564. procedure TFPSList.DeleteRange(IndexFrom, IndexTo : Integer);
  565. var
  566. ListItem: Pointer;
  567. I: Integer;
  568. OldCnt : Integer;
  569. begin
  570. CheckIndex(IndexTo);
  571. CheckIndex(IndexFrom);
  572. OldCnt:=FCount;
  573. Dec(FCount,IndexTo-IndexFrom+1);
  574. For I :=IndexFrom To Indexto Do
  575. begin
  576. ListItem := InternalItems[I];
  577. Deref(ListItem);
  578. end;
  579. System.Move(InternalItems[IndexTo+1]^, InternalItems[IndexFrom]^, (OldCnt - IndexTo-1) * FItemSize);
  580. // Shrink the list if appropriate
  581. if (FCapacity > 256) and (FCount < FCapacity shr 2) then
  582. begin
  583. FCapacity := FCapacity shr 1;
  584. ReallocMem(FList, (FCapacity+1) * FItemSize);
  585. end;
  586. { Keep the ending of the list filled with zeros, don't leave garbage data
  587. there. Otherwise, we could accidentally have there a copy of some item
  588. on the list, and accidentally Deref it too soon.
  589. See http://bugs.freepascal.org/view.php?id=20005. }
  590. FillChar(InternalItems[FCount]^, (FCapacity+1-FCount) * FItemSize, #0);
  591. end;
  592. procedure TFPSList.Extract(Item: Pointer; ResultPtr: Pointer);
  593. var
  594. i : Integer;
  595. ListItemPtr : Pointer;
  596. begin
  597. i := IndexOf(Item);
  598. if i >= 0 then
  599. begin
  600. ListItemPtr := InternalItems[i];
  601. System.Move(ListItemPtr^, ResultPtr^, FItemSize);
  602. { fill with zeros, to avoid freeing/decreasing reference on following Delete }
  603. System.FillByte(ListItemPtr^, FItemSize, 0);
  604. Delete(i);
  605. end else
  606. System.FillByte(ResultPtr^, FItemSize, 0);
  607. end;
  608. class procedure TFPSList.Error(const Msg: string; Data: PtrInt);
  609. begin
  610. raise EListError.CreateFmt(Msg,[Data]) at get_caller_addr(get_frame), get_caller_frame(get_frame);
  611. end;
  612. procedure TFPSList.Exchange(Index1, Index2: Integer);
  613. begin
  614. CheckIndex(Index1);
  615. CheckIndex(Index2);
  616. InternalExchange(Index1, Index2);
  617. end;
  618. procedure TFPSList.InternalExchange(Index1, Index2: Integer);
  619. begin
  620. System.Move(InternalItems[Index1]^, InternalItems[FCapacity]^, FItemSize);
  621. System.Move(InternalItems[Index2]^, InternalItems[Index1]^, FItemSize);
  622. System.Move(InternalItems[FCapacity]^, InternalItems[Index2]^, FItemSize);
  623. end;
  624. function TFPSList.Expand: TFPSList;
  625. var
  626. IncSize : Longint;
  627. begin
  628. Result := Self;
  629. if FCount < FCapacity then
  630. exit;
  631. if FCapacity > 127 then
  632. IncSize:=FCapacity shr 2
  633. else if FCapacity > 8 then
  634. IncSize := 16
  635. else if FCapacity > 3 then
  636. IncSize := 8
  637. else
  638. IncSize := 4;
  639. // If we were at max capacity already, force error.
  640. If IncSize<=0 then
  641. IncSize:=1; // Will trigger error
  642. SetCapacity(FCapacity + IncSize);
  643. end;
  644. function TFPSList.GetFirst: Pointer;
  645. begin
  646. If FCount = 0 then
  647. Result := Nil
  648. else
  649. Result := InternalItems[0];
  650. end;
  651. procedure TFPSList.SetFirst(const Value: Pointer);
  652. begin
  653. Put(0, Value);
  654. end;
  655. function TFPSList.IndexOf(Item: Pointer): Integer;
  656. var
  657. ListItem: Pointer;
  658. begin
  659. Result := 0;
  660. ListItem := First;
  661. while (Result < FCount) and (CompareByte(ListItem^, Item^, FItemSize) <> 0) do
  662. begin
  663. Inc(Result);
  664. ListItem := PByte(ListItem)+FItemSize;
  665. end;
  666. if Result = FCount then Result := -1;
  667. end;
  668. function TFPSList.Insert(Index: Integer): Pointer;
  669. begin
  670. if (Index < 0) or (Index > FCount) then
  671. Error(SListIndexError, Index);
  672. if FCount = FCapacity then Self.Expand;
  673. Result := InternalItems[Index];
  674. if Index<FCount then
  675. begin
  676. System.Move(Result^, (Result+FItemSize)^, (FCount - Index) * FItemSize);
  677. { clear for compiler assisted types }
  678. System.FillByte(Result^, FItemSize, 0);
  679. end;
  680. Inc(FCount);
  681. end;
  682. procedure TFPSList.Insert(Index: Integer; Item: Pointer);
  683. begin
  684. CopyItem(Item, Insert(Index));
  685. end;
  686. function TFPSList.GetLast: Pointer;
  687. begin
  688. if FCount = 0 then
  689. Result := nil
  690. else
  691. Result := InternalItems[FCount - 1];
  692. end;
  693. procedure TFPSList.SetLast(const Value: Pointer);
  694. begin
  695. Put(FCount - 1, Value);
  696. end;
  697. procedure TFPSList.Move(CurIndex, NewIndex: Integer);
  698. var
  699. CurItem, NewItem, TmpItem, Src, Dest: Pointer;
  700. MoveCount: Integer;
  701. begin
  702. CheckIndex(CurIndex);
  703. CheckIndex(NewIndex);
  704. if CurIndex = NewIndex then
  705. exit;
  706. CurItem := InternalItems[CurIndex];
  707. NewItem := InternalItems[NewIndex];
  708. TmpItem := InternalItems[FCapacity];
  709. System.Move(CurItem^, TmpItem^, FItemSize);
  710. if NewIndex > CurIndex then
  711. begin
  712. Src := InternalItems[CurIndex+1];
  713. Dest := CurItem;
  714. MoveCount := NewIndex - CurIndex;
  715. end else begin
  716. Src := NewItem;
  717. Dest := InternalItems[NewIndex+1];
  718. MoveCount := CurIndex - NewIndex;
  719. end;
  720. System.Move(Src^, Dest^, MoveCount * FItemSize);
  721. System.Move(TmpItem^, NewItem^, FItemSize);
  722. end;
  723. function TFPSList.Remove(Item: Pointer): Integer;
  724. begin
  725. Result := IndexOf(Item);
  726. if Result <> -1 then
  727. Delete(Result);
  728. end;
  729. const LocalThreshold = 64;
  730. procedure TFPSList.Pack;
  731. var
  732. LItemSize : integer;
  733. NewCount,
  734. i : integer;
  735. pdest,
  736. psrc : Pointer;
  737. localnul : array[0..LocalThreshold-1] of byte;
  738. pnul : pointer;
  739. begin
  740. LItemSize:=FItemSize;
  741. pnul:=@localnul;
  742. if LItemSize>Localthreshold then
  743. getmem(pnul,LItemSize);
  744. fillchar(pnul^,LItemSize,#0);
  745. NewCount:=0;
  746. psrc:=First;
  747. pdest:=psrc;
  748. For I:=0 To FCount-1 Do
  749. begin
  750. if not CompareMem(psrc,pnul,LItemSize) then
  751. begin
  752. System.Move(psrc^, pdest^, LItemSize);
  753. inc(pdest,LItemSIze);
  754. inc(NewCount);
  755. end
  756. else
  757. deref(psrc);
  758. inc(psrc,LitemSize);
  759. end;
  760. if LItemSize>Localthreshold then
  761. FreeMem(pnul,LItemSize);
  762. FCount:=NewCount;
  763. end;
  764. procedure TFPSList.Sort(Compare: TFPSListCompareFunc);
  765. begin
  766. Sort(Compare, {$IFDEF FPC_DOTTEDUNITS}System.{$ENDIF}SortBase.DefaultSortingAlgorithm);
  767. end;
  768. type
  769. PFPSList_Sort_Comparer_Context = ^TFPSList_Sort_Comparer_Context;
  770. TFPSList_Sort_Comparer_Context = record
  771. Compare: TFPSListCompareFunc;
  772. end;
  773. function TFPSList_Sort_Comparer(Item1, Item2, Context: Pointer): Integer;
  774. begin
  775. Result := PFPSList_Sort_Comparer_Context(Context)^.Compare(Item1, Item2);
  776. end;
  777. procedure TFPSList.Sort(Compare: TFPSListCompareFunc; SortingAlgorithm: PSortingAlgorithm);
  778. var
  779. Context: TFPSList_Sort_Comparer_Context;
  780. begin
  781. Context.Compare := Compare;
  782. SortingAlgorithm^.ItemListSorter_ContextComparer(FList, FCount, FItemSize, @TFPSList_Sort_Comparer, @Context);
  783. end;
  784. procedure TFPSList.QuickSort(L, R: Integer; Compare: TFPSListCompareFunc);
  785. var
  786. Context: TFPSList_Sort_Comparer_Context;
  787. SortingAlgorithm: PSortingAlgorithm;
  788. begin
  789. if (R > L) and (L >= 0) then
  790. begin
  791. Context.Compare := Compare;
  792. SortingAlgorithm := {$IFDEF FPC_DOTTEDUNITS}System.{$ENDIF}SortBase.DefaultSortingAlgorithm;
  793. SortingAlgorithm^.ItemListSorter_ContextComparer(FList + FItemSize*L, R-L+1, FItemSize, @TFPSList_Sort_Comparer, @Context);
  794. end;
  795. end;
  796. procedure TFPSList.AddList(Obj: TFPSList);
  797. var
  798. i: Integer;
  799. begin
  800. if Obj.ItemSize <> FItemSize then
  801. Error(SListItemSizeError, 0);
  802. // Do this now.
  803. Capacity:=Capacity+Obj.Count;
  804. if ItemIsManaged then
  805. begin
  806. // nothing for it, need to do it manually to give deref a chance.
  807. For I:=0 to Obj.Count-1 do
  808. Add(Obj[i])
  809. end
  810. else
  811. begin
  812. if Obj.Count=0 then
  813. exit;
  814. CopyItems(Obj.InternalItems[0],InternalItems[FCount],Obj.Count);
  815. FCount:=FCount+Obj.Count;
  816. end
  817. end;
  818. procedure TFPSList.Assign(Obj: TFPSList);
  819. begin
  820. // We must do this check here, to avoid clearing the list.
  821. if Obj.ItemSize <> FItemSize then
  822. Error(SListItemSizeError, 0);
  823. Clear;
  824. AddList(Obj);
  825. end;
  826. {****************************************************************************}
  827. {* TFPGListEnumerator *}
  828. {****************************************************************************}
  829. function TFPGListEnumerator.GetCurrent: T;
  830. begin
  831. Result := T(FList.Items[FPosition]^);
  832. end;
  833. constructor TFPGListEnumerator.Create(AList: TFPSList);
  834. begin
  835. inherited Create;
  836. FList := AList;
  837. FPosition := -1;
  838. end;
  839. function TFPGListEnumerator.MoveNext: Boolean;
  840. begin
  841. inc(FPosition);
  842. Result := FPosition < FList.Count;
  843. end;
  844. {****************************************************************************}
  845. {* TFPGList *}
  846. {****************************************************************************}
  847. constructor TFPGList.Create;
  848. begin
  849. inherited Create(sizeof(T));
  850. end;
  851. procedure TFPGList.CopyItem(Src, Dest: Pointer);
  852. begin
  853. T(Dest^) := T(Src^);
  854. end;
  855. procedure TFPGList.Deref(Item: Pointer);
  856. begin
  857. Finalize(T(Item^));
  858. end;
  859. function TFPGList.Get(Index: Integer): T;
  860. begin
  861. Result := T(inherited Get(Index)^);
  862. end;
  863. function TFPGList.GetList: PTypeList;
  864. begin
  865. Result := PTypeList(@FList);
  866. end;
  867. function TFPGList.ItemPtrCompare(Item1, Item2: Pointer): Integer;
  868. begin
  869. Result := FOnCompare(T(Item1^), T(Item2^));
  870. end;
  871. procedure TFPGList.Put(Index: Integer; const Item: T);
  872. begin
  873. inherited Put(Index, @Item);
  874. end;
  875. function TFPGList.Add(const Item: T): Integer;
  876. begin
  877. Result := inherited Add(@Item);
  878. end;
  879. function TFPGList.Extract(const Item: T): T;
  880. begin
  881. inherited Extract(@Item, @Result);
  882. end;
  883. function TFPGList.GetFirst: T;
  884. begin
  885. if FCount<>0 then
  886. Result := T(inherited GetFirst^)
  887. else
  888. Result:=Default(T);
  889. end;
  890. procedure TFPGList.SetFirst(const Value: T);
  891. begin
  892. inherited SetFirst(@Value);
  893. end;
  894. class function TFPGList.ItemIsManaged: Boolean;
  895. begin
  896. {$IFNDEF VER3_0}
  897. Result:=IsManagedType(T);
  898. {$ELSE}
  899. Result:=True; // Fallback to old behaviour
  900. {$ENDIF}
  901. end;
  902. function TFPGList.GetEnumerator: TFPGListEnumeratorSpec;
  903. begin
  904. Result := TFPGListEnumeratorSpec.Create(Self);
  905. end;
  906. function TFPGList.IndexOf(const Item: T): Integer;
  907. begin
  908. Result := 0;
  909. {$info TODO: fix inlining to work! InternalItems[Result]^}
  910. while (Result < FCount) and (PT(FList)[Result] <> Item) do
  911. Inc(Result);
  912. if Result = FCount then
  913. Result := -1;
  914. end;
  915. procedure TFPGList.Insert(Index: Integer; const Item: T);
  916. begin
  917. T(inherited Insert(Index)^) := Item;
  918. end;
  919. function TFPGList.GetLast: T;
  920. begin
  921. if FCount<>0 then
  922. Result := T(inherited GetLast^)
  923. else
  924. result:=Default(T);
  925. end;
  926. procedure TFPGList.SetLast(const Value: T);
  927. begin
  928. inherited SetLast(@Value);
  929. end;
  930. procedure TFPGList.AddList(Source: TFPGList);
  931. var
  932. i: Integer;
  933. begin
  934. if ItemIsManaged then
  935. begin
  936. Capacity:=Capacity+Source.Count;
  937. for I := 0 to Source.Count - 1 do
  938. Add(Source[i]);
  939. end
  940. else
  941. Inherited AddList(TFPSList(source))
  942. end;
  943. procedure TFPGList.Assign(Source: TFPGList);
  944. begin
  945. if ItemIsManaged then
  946. begin
  947. Clear;
  948. AddList(Source);
  949. end
  950. else
  951. Inherited Assign(TFPSList(source))
  952. end;
  953. function TFPGList.Remove(const Item: T): Integer;
  954. begin
  955. Result := IndexOf(Item);
  956. if Result >= 0 then
  957. Delete(Result);
  958. end;
  959. procedure TFPGList.Sort(Compare: TCompareFunc);
  960. begin
  961. FOnCompare := Compare;
  962. inherited Sort(@ItemPtrCompare);
  963. end;
  964. procedure TFPGList.Sort(Compare: TCompareFunc; SortingAlgorithm: PSortingAlgorithm);
  965. begin
  966. FOnCompare := Compare;
  967. inherited Sort(@ItemPtrCompare, SortingAlgorithm);
  968. end;
  969. {****************************************************************************}
  970. {* TFPGObjectList *}
  971. {****************************************************************************}
  972. constructor TFPGObjectList.Create(FreeObjects: Boolean);
  973. begin
  974. inherited Create;
  975. FFreeObjects := FreeObjects;
  976. end;
  977. procedure TFPGObjectList.CopyItem(Src, Dest: Pointer);
  978. begin
  979. T(Dest^) := T(Src^);
  980. end;
  981. procedure TFPGObjectList.Deref(Item: Pointer);
  982. begin
  983. if FFreeObjects then
  984. T(Item^).Free;
  985. end;
  986. function TFPGObjectList.Get(Index: Integer): T;
  987. begin
  988. Result := T(inherited Get(Index)^);
  989. end;
  990. function TFPGObjectList.GetList: PTypeList;
  991. begin
  992. Result := PTypeList(@FList);
  993. end;
  994. function TFPGObjectList.ItemPtrCompare(Item1, Item2: Pointer): Integer;
  995. begin
  996. Result := FOnCompare(T(Item1^), T(Item2^));
  997. end;
  998. procedure TFPGObjectList.Put(Index: Integer; const Item: T);
  999. begin
  1000. inherited Put(Index, @Item);
  1001. end;
  1002. function TFPGObjectList.Add(const Item: T): Integer;
  1003. begin
  1004. Result := inherited Add(@Item);
  1005. end;
  1006. function TFPGObjectList.Extract(const Item: T): T;
  1007. begin
  1008. inherited Extract(@Item, @Result);
  1009. end;
  1010. function TFPGObjectList.GetFirst: T;
  1011. begin
  1012. if FCount<>0 then
  1013. Result := T(inherited GetFirst^)
  1014. else
  1015. Result := Default(T)
  1016. end;
  1017. procedure TFPGObjectList.SetFirst(const Value: T);
  1018. begin
  1019. inherited SetFirst(@Value);
  1020. end;
  1021. function TFPGObjectList.GetEnumerator: TFPGListEnumeratorSpec;
  1022. begin
  1023. Result := TFPGListEnumeratorSpec.Create(Self);
  1024. end;
  1025. function TFPGObjectList.IndexOf(const Item: T): Integer;
  1026. begin
  1027. Result :=
  1028. {$if sizeof(pointer) = sizeof(word)}
  1029. IndexWord
  1030. {$elseif sizeof(pointer) = sizeof(dword)}
  1031. IndexDWord
  1032. {$elseif sizeof(pointer) = sizeof(qword)}
  1033. IndexQWord
  1034. {$else}
  1035. {$error unknown pointer size}
  1036. {$endif}
  1037. (FList^, FCount, PtrUint(Pointer(Item)));
  1038. end;
  1039. procedure TFPGObjectList.Insert(Index: Integer; const Item: T);
  1040. begin
  1041. T(inherited Insert(Index)^) := Item;
  1042. end;
  1043. function TFPGObjectList.GetLast: T;
  1044. begin
  1045. if FCount<>0 then
  1046. Result := T(inherited GetLast^)
  1047. else
  1048. Result :=Default(T);
  1049. end;
  1050. procedure TFPGObjectList.SetLast(const Value: T);
  1051. begin
  1052. inherited SetLast(@Value);
  1053. end;
  1054. procedure TFPGObjectList.AddList(Source: TFPGObjectList);
  1055. var
  1056. i: Integer;
  1057. begin
  1058. for I := 0 to Source.Count - 1 do
  1059. Add(Source[i]);
  1060. end;
  1061. procedure TFPGObjectList.Assign(Source: TFPGObjectList);
  1062. begin
  1063. Clear;
  1064. AddList(Source);
  1065. end;
  1066. function TFPGObjectList.Remove(const Item: T): Integer;
  1067. begin
  1068. Result := IndexOf(Item);
  1069. if Result >= 0 then
  1070. Delete(Result);
  1071. end;
  1072. procedure TFPGObjectList.Sort(Compare: TCompareFunc);
  1073. begin
  1074. FOnCompare := Compare;
  1075. inherited Sort(@ItemPtrCompare);
  1076. end;
  1077. procedure TFPGObjectList.Sort(Compare: TCompareFunc; SortingAlgorithm: PSortingAlgorithm);
  1078. begin
  1079. FOnCompare := Compare;
  1080. inherited Sort(@ItemPtrCompare, SortingAlgorithm);
  1081. end;
  1082. {****************************************************************************}
  1083. {* TFPGInterfacedObjectList *}
  1084. {****************************************************************************}
  1085. constructor TFPGInterfacedObjectList.Create;
  1086. begin
  1087. inherited Create;
  1088. end;
  1089. procedure TFPGInterfacedObjectList.CopyItem(Src, Dest: Pointer);
  1090. begin
  1091. if Assigned(Pointer(Dest^)) then
  1092. T(Dest^)._Release;
  1093. Pointer(Dest^) := Pointer(Src^);
  1094. if Assigned(Pointer(Dest^)) then
  1095. T(Dest^)._AddRef;
  1096. end;
  1097. procedure TFPGInterfacedObjectList.Deref(Item: Pointer);
  1098. begin
  1099. if Assigned(Pointer(Item^)) then
  1100. T(Item^)._Release;
  1101. end;
  1102. function TFPGInterfacedObjectList.Get(Index: Integer): T;
  1103. begin
  1104. Result := T(inherited Get(Index)^);
  1105. end;
  1106. function TFPGInterfacedObjectList.GetList: PTypeList;
  1107. begin
  1108. Result := PTypeList(@FList);
  1109. end;
  1110. function TFPGInterfacedObjectList.ItemPtrCompare(Item1, Item2: Pointer): Integer;
  1111. begin
  1112. Result := FOnCompare(T(Item1^), T(Item2^));
  1113. end;
  1114. procedure TFPGInterfacedObjectList.Put(Index: Integer; const Item: T);
  1115. begin
  1116. CheckIndex(Index);
  1117. InternalItems[Index] := @Item; // eventually calls copyitem()
  1118. end;
  1119. function TFPGInterfacedObjectList.Add(const Item: T): Integer;
  1120. begin
  1121. Result := inherited Add(@Item);
  1122. end;
  1123. function TFPGInterfacedObjectList.Extract(const Item: T): T;
  1124. begin
  1125. inherited Extract(@Item, @Result);
  1126. end;
  1127. function TFPGInterfacedObjectList.GetFirst: T;
  1128. begin
  1129. Result := T(inherited GetFirst^);
  1130. end;
  1131. procedure TFPGInterfacedObjectList.SetFirst(const Value: T);
  1132. begin
  1133. inherited SetFirst(@Value);
  1134. end;
  1135. function TFPGInterfacedObjectList.GetEnumerator: TFPGListEnumeratorSpec;
  1136. begin
  1137. Result := TFPGListEnumeratorSpec.Create(Self);
  1138. end;
  1139. function TFPGInterfacedObjectList.IndexOf(const Item: T): Integer;
  1140. begin
  1141. Result :=
  1142. {$if sizeof(pointer) = sizeof(word)}
  1143. IndexWord
  1144. {$elseif sizeof(pointer) = sizeof(dword)}
  1145. IndexDWord
  1146. {$elseif sizeof(pointer) = sizeof(qword)}
  1147. IndexQWord
  1148. {$else}
  1149. {$error unknown pointer size}
  1150. {$endif}
  1151. (FList^, FCount, PtrUint(Pointer(Item)));
  1152. end;
  1153. procedure TFPGInterfacedObjectList.Insert(Index: Integer; const Item: T);
  1154. begin
  1155. T(inherited Insert(Index)^) := Item;
  1156. end;
  1157. function TFPGInterfacedObjectList.GetLast: T;
  1158. begin
  1159. Result := T(inherited GetLast^);
  1160. end;
  1161. procedure TFPGInterfacedObjectList.SetLast(const Value: T);
  1162. begin
  1163. inherited SetLast(@Value);
  1164. end;
  1165. procedure TFPGInterfacedObjectList.Assign(Source: TFPGInterfacedObjectList);
  1166. begin
  1167. Clear;
  1168. AddList(Source);
  1169. end;
  1170. procedure TFPGInterfacedObjectList.AddList(Source: TFPGInterfacedObjectList);
  1171. var
  1172. i: Integer;
  1173. begin
  1174. for I := 0 to Source.Count - 1 do
  1175. Add(Source[i]);
  1176. end;
  1177. function TFPGInterfacedObjectList.Remove(const Item: T): Integer;
  1178. begin
  1179. Result := IndexOf(Item);
  1180. if Result >= 0 then
  1181. Delete(Result);
  1182. end;
  1183. procedure TFPGInterfacedObjectList.Sort(Compare: TCompareFunc);
  1184. begin
  1185. FOnCompare := Compare;
  1186. inherited Sort(@ItemPtrCompare);
  1187. end;
  1188. procedure TFPGInterfacedObjectList.Sort(Compare: TCompareFunc; SortingAlgorithm: PSortingAlgorithm);
  1189. begin
  1190. FOnCompare := Compare;
  1191. inherited Sort(@ItemPtrCompare, SortingAlgorithm);
  1192. end;
  1193. {****************************************************************************
  1194. TFPSMap
  1195. ****************************************************************************}
  1196. constructor TFPSMap.Create(AKeySize: Integer; ADataSize: integer);
  1197. begin
  1198. inherited Create(AKeySize+ADataSize);
  1199. FKeySize := AKeySize;
  1200. FDataSize := ADataSize;
  1201. InitOnPtrCompare;
  1202. end;
  1203. procedure TFPSMap.CopyKey(Src, Dest: Pointer);
  1204. begin
  1205. System.Move(Src^, Dest^, FKeySize);
  1206. end;
  1207. procedure TFPSMap.CopyData(Src, Dest: Pointer);
  1208. begin
  1209. System.Move(Src^, Dest^, FDataSize);
  1210. end;
  1211. function TFPSMap.GetKey(Index: Integer): Pointer;
  1212. begin
  1213. Result := Items[Index];
  1214. end;
  1215. function TFPSMap.GetData(Index: Integer): Pointer;
  1216. begin
  1217. Result := PByte(Items[Index])+FKeySize;
  1218. end;
  1219. function TFPSMap.GetKeyData(AKey: Pointer): Pointer;
  1220. var
  1221. I: Integer;
  1222. begin
  1223. I := IndexOf(AKey);
  1224. if I >= 0 then
  1225. Result := InternalItems[I]+FKeySize
  1226. else
  1227. Error(SMapKeyError, PtrUInt(AKey));
  1228. end;
  1229. function TFPSMap.BinaryCompareKey(Key1, Key2: Pointer): Integer;
  1230. begin
  1231. Result := CompareByte(Key1^, Key2^, FKeySize);
  1232. end;
  1233. function TFPSMap.BinaryCompareData(Data1, Data2: Pointer): Integer;
  1234. begin
  1235. Result := CompareByte(Data1^, Data2^, FDataSize);
  1236. end;
  1237. procedure TFPSMap.SetOnKeyPtrCompare(Proc: TFPSListCompareFunc);
  1238. begin
  1239. if Proc <> nil then
  1240. FOnKeyPtrCompare := Proc
  1241. else
  1242. FOnKeyPtrCompare := @BinaryCompareKey;
  1243. end;
  1244. procedure TFPSMap.SetOnDataPtrCompare(Proc: TFPSListCompareFunc);
  1245. begin
  1246. if Proc <> nil then
  1247. FOnDataPtrCompare := Proc
  1248. else
  1249. FOnDataPtrCompare := @BinaryCompareData;
  1250. end;
  1251. procedure TFPSMap.InitOnPtrCompare;
  1252. begin
  1253. SetOnKeyPtrCompare(nil);
  1254. SetOnDataPtrCompare(nil);
  1255. end;
  1256. procedure TFPSMap.PutKey(Index: Integer; AKey: Pointer);
  1257. begin
  1258. if FSorted then
  1259. Error(SSortedListError, 0);
  1260. CopyKey(AKey, Items[Index]);
  1261. end;
  1262. procedure TFPSMap.PutData(Index: Integer; AData: Pointer);
  1263. begin
  1264. CopyData(AData, PByte(Items[Index])+FKeySize);
  1265. end;
  1266. procedure TFPSMap.PutKeyData(AKey: Pointer; NewData: Pointer);
  1267. var
  1268. I: Integer;
  1269. begin
  1270. I := IndexOf(AKey);
  1271. if I >= 0 then
  1272. Data[I] := NewData
  1273. else
  1274. Add(AKey, NewData);
  1275. end;
  1276. procedure TFPSMap.SetSorted(Value: Boolean);
  1277. begin
  1278. if Value = FSorted then exit;
  1279. FSorted := Value;
  1280. if Value then Sort;
  1281. end;
  1282. function TFPSMap.Add(AKey: Pointer): Integer;
  1283. begin
  1284. if Sorted then
  1285. begin
  1286. if Find(AKey, Result) then
  1287. case Duplicates of
  1288. dupIgnore: exit;
  1289. dupError: Error(SDuplicateItem, 0)
  1290. end;
  1291. end else
  1292. Result := Count;
  1293. CopyKey(AKey, inherited Insert(Result));
  1294. end;
  1295. function TFPSMap.Add(AKey, AData: Pointer): Integer;
  1296. begin
  1297. Result := Add(AKey);
  1298. Data[Result] := AData;
  1299. end;
  1300. function TFPSMap.Find(AKey: Pointer; out Index: Integer): Boolean;
  1301. { Searches for the first item <= Key, returns True if exact match,
  1302. sets index to the index of the found string. }
  1303. var
  1304. I,L,R,Dir: Integer;
  1305. begin
  1306. Result := false;
  1307. Index := -1;
  1308. if not Sorted then
  1309. raise EListError.Create(SErrFindNeedsSortedList);
  1310. // Use binary search.
  1311. L := 0;
  1312. R := FCount-1;
  1313. while L<=R do
  1314. begin
  1315. I := L + (R - L) div 2;
  1316. Dir := FOnKeyPtrCompare(Items[I], AKey);
  1317. if Dir < 0 then
  1318. L := I+1
  1319. else begin
  1320. R := I-1;
  1321. if Dir = 0 then
  1322. begin
  1323. Result := true;
  1324. if Duplicates <> dupAccept then
  1325. L := I;
  1326. end;
  1327. end;
  1328. end;
  1329. Index := L;
  1330. end;
  1331. function TFPSMap.LinearIndexOf(AKey: Pointer): Integer;
  1332. var
  1333. ListItem: Pointer;
  1334. begin
  1335. Result := 0;
  1336. ListItem := First;
  1337. while (Result < FCount) and (FOnKeyPtrCompare(ListItem, AKey) <> 0) do
  1338. begin
  1339. Inc(Result);
  1340. ListItem := PByte(ListItem)+FItemSize;
  1341. end;
  1342. if Result = FCount then Result := -1;
  1343. end;
  1344. function TFPSMap.IndexOf(AKey: Pointer): Integer;
  1345. begin
  1346. if Sorted then
  1347. begin
  1348. if not Find(AKey, Result) then
  1349. Result := -1;
  1350. end else
  1351. Result := LinearIndexOf(AKey);
  1352. end;
  1353. function TFPSMap.IndexOfData(AData: Pointer): Integer;
  1354. var
  1355. ListItem: Pointer;
  1356. begin
  1357. Result := 0;
  1358. ListItem := First+FKeySize;
  1359. while (Result < FCount) and (FOnDataPtrCompare(ListItem, AData) <> 0) do
  1360. begin
  1361. Inc(Result);
  1362. ListItem := PByte(ListItem)+FItemSize;
  1363. end;
  1364. if Result = FCount then Result := -1;
  1365. end;
  1366. function TFPSMap.Insert(Index: Integer): Pointer;
  1367. begin
  1368. if FSorted then
  1369. Error(SSortedListError, 0);
  1370. Result := inherited Insert(Index);
  1371. end;
  1372. procedure TFPSMap.Insert(Index: Integer; out AKey, AData: Pointer);
  1373. begin
  1374. AKey := Insert(Index);
  1375. AData := PByte(AKey) + FKeySize;
  1376. end;
  1377. procedure TFPSMap.InsertKey(Index: Integer; AKey: Pointer);
  1378. begin
  1379. CopyKey(AKey, Insert(Index));
  1380. end;
  1381. procedure TFPSMap.InsertKeyData(Index: Integer; AKey, AData: Pointer);
  1382. var
  1383. ListItem: Pointer;
  1384. begin
  1385. ListItem := Insert(Index);
  1386. CopyKey(AKey, ListItem);
  1387. CopyData(AData, PByte(ListItem)+FKeySize);
  1388. end;
  1389. function TFPSMap.Remove(AKey: Pointer): Integer;
  1390. begin
  1391. Result := IndexOf(AKey);
  1392. if Result >= 0 then
  1393. Delete(Result);
  1394. end;
  1395. procedure TFPSMap.Sort;
  1396. begin
  1397. inherited Sort(FOnKeyPtrCompare);
  1398. end;
  1399. procedure TFPSMap.Sort(SortingAlgorithm: PSortingAlgorithm);
  1400. begin
  1401. inherited Sort(FOnKeyPtrCompare, SortingAlgorithm);
  1402. end;
  1403. {****************************************************************************
  1404. TFPGMap
  1405. ****************************************************************************}
  1406. constructor TFPGMap.Create;
  1407. begin
  1408. inherited Create(SizeOf(TKey), SizeOf(TData));
  1409. end;
  1410. procedure TFPGMap.CopyItem(Src, Dest: Pointer);
  1411. begin
  1412. CopyKey(Src, Dest);
  1413. CopyData(PByte(Src)+KeySize, PByte(Dest)+KeySize);
  1414. end;
  1415. procedure TFPGMap.CopyKey(Src, Dest: Pointer);
  1416. begin
  1417. TKey(Dest^) := TKey(Src^);
  1418. end;
  1419. procedure TFPGMap.CopyData(Src, Dest: Pointer);
  1420. begin
  1421. TData(Dest^) := TData(Src^);
  1422. end;
  1423. procedure TFPGMap.Deref(Item: Pointer);
  1424. begin
  1425. Finalize(TKey(Item^));
  1426. Finalize(TData(Pointer(PByte(Item)+KeySize)^));
  1427. end;
  1428. function TFPGMap.GetKey(Index: Integer): TKey;
  1429. begin
  1430. Result := TKey(inherited GetKey(Index)^);
  1431. end;
  1432. function TFPGMap.GetData(Index: Integer): TData;
  1433. begin
  1434. Result := TData(inherited GetData(Index)^);
  1435. end;
  1436. function TFPGMap.GetKeyData(const AKey: TKey): TData;
  1437. begin
  1438. Result := TData(inherited GetKeyData(@AKey)^);
  1439. end;
  1440. function TFPGMap.KeyCompare(Key1, Key2: Pointer): Integer;
  1441. begin
  1442. if PKey(Key1)^ < PKey(Key2)^ then
  1443. Result := -1
  1444. else if PKey(Key1)^ > PKey(Key2)^ then
  1445. Result := 1
  1446. else
  1447. Result := 0;
  1448. end;
  1449. {function TFPGMap.DataCompare(Data1, Data2: Pointer): Integer;
  1450. begin
  1451. if PData(Data1)^ < PData(Data2)^ then
  1452. Result := -1
  1453. else if PData(Data1)^ > PData(Data2)^ then
  1454. Result := 1
  1455. else
  1456. Result := 0;
  1457. end;}
  1458. function TFPGMap.KeyCustomCompare(Key1, Key2: Pointer): Integer;
  1459. begin
  1460. Result := FOnKeyCompare(TKey(Key1^), TKey(Key2^));
  1461. end;
  1462. function TFPGMap.DataCustomCompare(Data1, Data2: Pointer): Integer;
  1463. begin
  1464. Result := FOnDataCompare(TData(Data1^), TData(Data2^));
  1465. end;
  1466. procedure TFPGMap.SetOnKeyCompare(NewCompare: TKeyCompareFunc);
  1467. begin
  1468. FOnKeyCompare := NewCompare;
  1469. if NewCompare <> nil then
  1470. OnKeyPtrCompare := @KeyCustomCompare
  1471. else
  1472. OnKeyPtrCompare := @KeyCompare;
  1473. end;
  1474. procedure TFPGMap.SetOnDataCompare(NewCompare: TDataCompareFunc);
  1475. begin
  1476. FOnDataCompare := NewCompare;
  1477. if NewCompare <> nil then
  1478. OnDataPtrCompare := @DataCustomCompare
  1479. else
  1480. OnDataPtrCompare := nil;
  1481. end;
  1482. procedure TFPGMap.InitOnPtrCompare;
  1483. begin
  1484. SetOnKeyCompare(nil);
  1485. SetOnDataCompare(nil);
  1486. end;
  1487. procedure TFPGMap.PutKey(Index: Integer; const NewKey: TKey);
  1488. begin
  1489. inherited PutKey(Index, @NewKey);
  1490. end;
  1491. procedure TFPGMap.PutData(Index: Integer; const NewData: TData);
  1492. begin
  1493. inherited PutData(Index, @NewData);
  1494. end;
  1495. procedure TFPGMap.PutKeyData(const AKey: TKey; const NewData: TData);
  1496. begin
  1497. inherited PutKeyData(@AKey, @NewData);
  1498. end;
  1499. function TFPGMap.Add(const AKey: TKey): Integer;
  1500. begin
  1501. Result := inherited Add(@AKey);
  1502. end;
  1503. function TFPGMap.Add(const AKey: TKey; const AData: TData): Integer;
  1504. begin
  1505. Result := inherited Add(@AKey, @AData);
  1506. end;
  1507. function TFPGMap.Find(const AKey: TKey; out Index: Integer): Boolean;
  1508. begin
  1509. Result := inherited Find(@AKey, Index);
  1510. end;
  1511. function TFPGMap.TryGetData(const AKey: TKey; out AData: TData): Boolean;
  1512. var
  1513. I: Integer;
  1514. begin
  1515. I := IndexOf(AKey);
  1516. Result := (I >= 0);
  1517. if Result then
  1518. AData := TData(inherited GetData(I)^)
  1519. else
  1520. AData := Default(TData);
  1521. end;
  1522. procedure TFPGMap.AddOrSetData(const AKey: TKey; const AData: TData);
  1523. begin
  1524. inherited PutKeyData(@AKey, @AData);
  1525. end;
  1526. function TFPGMap.IndexOf(const AKey: TKey): Integer;
  1527. begin
  1528. Result := inherited IndexOf(@AKey);
  1529. end;
  1530. function TFPGMap.IndexOfData(const AData: TData): Integer;
  1531. begin
  1532. { TODO: loop ? }
  1533. Result := inherited IndexOfData(@AData);
  1534. end;
  1535. procedure TFPGMap.InsertKey(Index: Integer; const AKey: TKey);
  1536. begin
  1537. inherited InsertKey(Index, @AKey);
  1538. end;
  1539. procedure TFPGMap.InsertKeyData(Index: Integer; const AKey: TKey; const AData: TData);
  1540. begin
  1541. inherited InsertKeyData(Index, @AKey, @AData);
  1542. end;
  1543. function TFPGMap.Remove(const AKey: TKey): Integer;
  1544. begin
  1545. Result := inherited Remove(@AKey);
  1546. end;
  1547. {****************************************************************************
  1548. TFPGMapObject
  1549. ****************************************************************************}
  1550. constructor TFPGMapObject.Create(AFreeObjects: Boolean);
  1551. begin
  1552. inherited Create(SizeOf(TKey), SizeOf(TData));
  1553. FFreeObjects := AFreeObjects;
  1554. end;
  1555. constructor TFPGMapObject.Create;
  1556. begin
  1557. Create(True);
  1558. end;
  1559. procedure TFPGMapObject.CopyItem(Src, Dest: Pointer);
  1560. begin
  1561. CopyKey(Src, Dest);
  1562. CopyData(PByte(Src)+KeySize, PByte(Dest)+KeySize);
  1563. end;
  1564. procedure TFPGMapObject.CopyKey(Src, Dest: Pointer);
  1565. begin
  1566. TKey(Dest^) := TKey(Src^);
  1567. end;
  1568. procedure TFPGMapObject.CopyData(Src, Dest: Pointer);
  1569. begin
  1570. if Assigned(Pointer(Dest^)) And FFreeObjects then
  1571. TData(Dest^).Free;
  1572. TData(Dest^) := TData(Src^);
  1573. end;
  1574. procedure TFPGMapObject.Deref(Item: Pointer);
  1575. begin
  1576. Finalize(TKey(Item^));
  1577. if Assigned(PPointer(PByte(Item)+KeySize)^) and FFreeObjects then
  1578. TData(Pointer(PByte(Item)+KeySize)^).Free;
  1579. end;
  1580. function TFPGMapObject.GetKey(Index: Integer): TKey;
  1581. begin
  1582. Result := TKey(inherited GetKey(Index)^);
  1583. end;
  1584. function TFPGMapObject.GetData(Index: Integer): TData;
  1585. begin
  1586. Result := TData(inherited GetData(Index)^);
  1587. end;
  1588. function TFPGMapObject.GetKeyData(const AKey: TKey): TData;
  1589. begin
  1590. Result := TData(inherited GetKeyData(@AKey)^);
  1591. end;
  1592. function TFPGMapObject.KeyCompare(Key1, Key2: Pointer): Integer;
  1593. begin
  1594. if PKey(Key1)^ < PKey(Key2)^ then
  1595. Result := -1
  1596. else if PKey(Key1)^ > PKey(Key2)^ then
  1597. Result := 1
  1598. else
  1599. Result := 0;
  1600. end;
  1601. {function TFPGMapObject.DataCompare(Data1, Data2: Pointer): Integer;
  1602. begin
  1603. if PData(Data1)^ < PData(Data2)^ then
  1604. Result := -1
  1605. else if PData(Data1)^ > PData(Data2)^ then
  1606. Result := 1
  1607. else
  1608. Result := 0;
  1609. end;}
  1610. function TFPGMapObject.KeyCustomCompare(Key1, Key2: Pointer): Integer;
  1611. begin
  1612. Result := FOnKeyCompare(TKey(Key1^), TKey(Key2^));
  1613. end;
  1614. function TFPGMapObject.DataCustomCompare(Data1, Data2: Pointer): Integer;
  1615. begin
  1616. Result := FOnDataCompare(TData(Data1^), TData(Data2^));
  1617. end;
  1618. procedure TFPGMapObject.SetOnKeyCompare(NewCompare: TKeyCompareFunc);
  1619. begin
  1620. FOnKeyCompare := NewCompare;
  1621. if NewCompare <> nil then
  1622. OnKeyPtrCompare := @KeyCustomCompare
  1623. else
  1624. OnKeyPtrCompare := @KeyCompare;
  1625. end;
  1626. procedure TFPGMapObject.SetOnDataCompare(NewCompare: TDataCompareFunc);
  1627. begin
  1628. FOnDataCompare := NewCompare;
  1629. if NewCompare <> nil then
  1630. OnDataPtrCompare := @DataCustomCompare
  1631. else
  1632. OnDataPtrCompare := nil;
  1633. end;
  1634. procedure TFPGMapObject.InitOnPtrCompare;
  1635. begin
  1636. SetOnKeyCompare(nil);
  1637. SetOnDataCompare(nil);
  1638. end;
  1639. procedure TFPGMapObject.PutKey(Index: Integer; const NewKey: TKey);
  1640. begin
  1641. inherited PutKey(Index, @NewKey);
  1642. end;
  1643. procedure TFPGMapObject.PutData(Index: Integer; const NewData: TData);
  1644. begin
  1645. inherited PutData(Index, @NewData);
  1646. end;
  1647. procedure TFPGMapObject.PutKeyData(const AKey: TKey; const NewData: TData);
  1648. begin
  1649. inherited PutKeyData(@AKey, @NewData);
  1650. end;
  1651. function TFPGMapObject.Add(const AKey: TKey): Integer;
  1652. begin
  1653. Result := inherited Add(@AKey);
  1654. end;
  1655. function TFPGMapObject.Add(const AKey: TKey; const AData: TData): Integer;
  1656. begin
  1657. Result := inherited Add(@AKey, @AData);
  1658. end;
  1659. function TFPGMapObject.Find(const AKey: TKey; out Index: Integer): Boolean;
  1660. begin
  1661. Result := inherited Find(@AKey, Index);
  1662. end;
  1663. function TFPGMapObject.TryGetData(const AKey: TKey; out AData: TData): Boolean;
  1664. var
  1665. I: Integer;
  1666. begin
  1667. I := IndexOf(AKey);
  1668. Result := (I >= 0);
  1669. if Result then
  1670. AData := TData(inherited GetData(I)^)
  1671. else
  1672. AData := Default(TData);
  1673. end;
  1674. procedure TFPGMapObject.AddOrSetData(const AKey: TKey; const AData: TData);
  1675. begin
  1676. inherited PutKeyData(@AKey, @AData);
  1677. end;
  1678. function TFPGMapObject.IndexOf(const AKey: TKey): Integer;
  1679. begin
  1680. Result := inherited IndexOf(@AKey);
  1681. end;
  1682. function TFPGMapObject.IndexOfData(const AData: TData): Integer;
  1683. begin
  1684. { TODO: loop ? }
  1685. Result := inherited IndexOfData(@AData);
  1686. end;
  1687. procedure TFPGMapObject.InsertKey(Index: Integer; const AKey: TKey);
  1688. begin
  1689. inherited InsertKey(Index, @AKey);
  1690. end;
  1691. procedure TFPGMapObject.InsertKeyData(Index: Integer; const AKey: TKey; const AData: TData);
  1692. begin
  1693. inherited InsertKeyData(Index, @AKey, @AData);
  1694. end;
  1695. function TFPGMapObject.Remove(const AKey: TKey): Integer;
  1696. begin
  1697. Result := inherited Remove(@AKey);
  1698. end;
  1699. {****************************************************************************
  1700. TFPGMapInterfacedObjectData
  1701. ****************************************************************************}
  1702. constructor TFPGMapInterfacedObjectData.Create;
  1703. begin
  1704. inherited Create(SizeOf(TKey), SizeOf(TData));
  1705. end;
  1706. procedure TFPGMapInterfacedObjectData.CopyItem(Src, Dest: Pointer);
  1707. begin
  1708. CopyKey(Src, Dest);
  1709. CopyData(PByte(Src)+KeySize, PByte(Dest)+KeySize);
  1710. end;
  1711. procedure TFPGMapInterfacedObjectData.CopyKey(Src, Dest: Pointer);
  1712. begin
  1713. TKey(Dest^) := TKey(Src^);
  1714. end;
  1715. procedure TFPGMapInterfacedObjectData.CopyData(Src, Dest: Pointer);
  1716. begin
  1717. if Assigned(Pointer(Dest^)) then
  1718. TData(Dest^)._Release;
  1719. TData(Dest^) := TData(Src^);
  1720. if Assigned(Pointer(Dest^)) then
  1721. TData(Dest^)._AddRef;
  1722. end;
  1723. procedure TFPGMapInterfacedObjectData.Deref(Item: Pointer);
  1724. begin
  1725. Finalize(TKey(Item^));
  1726. if Assigned(PPointer(PByte(Item)+KeySize)^) then
  1727. TData(Pointer(PByte(Item)+KeySize)^)._Release;
  1728. end;
  1729. function TFPGMapInterfacedObjectData.GetKey(Index: Integer): TKey;
  1730. begin
  1731. Result := TKey(inherited GetKey(Index)^);
  1732. end;
  1733. function TFPGMapInterfacedObjectData.GetData(Index: Integer): TData;
  1734. begin
  1735. Result := TData(inherited GetData(Index)^);
  1736. end;
  1737. function TFPGMapInterfacedObjectData.GetKeyData(const AKey: TKey): TData;
  1738. begin
  1739. Result := TData(inherited GetKeyData(@AKey)^);
  1740. end;
  1741. function TFPGMapInterfacedObjectData.KeyCompare(Key1, Key2: Pointer): Integer;
  1742. begin
  1743. if PKey(Key1)^ < PKey(Key2)^ then
  1744. Result := -1
  1745. else if PKey(Key1)^ > PKey(Key2)^ then
  1746. Result := 1
  1747. else
  1748. Result := 0;
  1749. end;
  1750. {function TFPGMapInterfacedObjectData.DataCompare(Data1, Data2: Pointer): Integer;
  1751. begin
  1752. if PData(Data1)^ < PData(Data2)^ then
  1753. Result := -1
  1754. else if PData(Data1)^ > PData(Data2)^ then
  1755. Result := 1
  1756. else
  1757. Result := 0;
  1758. end;}
  1759. function TFPGMapInterfacedObjectData.KeyCustomCompare(Key1, Key2: Pointer): Integer;
  1760. begin
  1761. Result := FOnKeyCompare(TKey(Key1^), TKey(Key2^));
  1762. end;
  1763. function TFPGMapInterfacedObjectData.DataCustomCompare(Data1, Data2: Pointer): Integer;
  1764. begin
  1765. Result := FOnDataCompare(TData(Data1^), TData(Data2^));
  1766. end;
  1767. procedure TFPGMapInterfacedObjectData.SetOnKeyCompare(NewCompare: TKeyCompareFunc);
  1768. begin
  1769. FOnKeyCompare := NewCompare;
  1770. if NewCompare <> nil then
  1771. OnKeyPtrCompare := @KeyCustomCompare
  1772. else
  1773. OnKeyPtrCompare := @KeyCompare;
  1774. end;
  1775. procedure TFPGMapInterfacedObjectData.SetOnDataCompare(NewCompare: TDataCompareFunc);
  1776. begin
  1777. FOnDataCompare := NewCompare;
  1778. if NewCompare <> nil then
  1779. OnDataPtrCompare := @DataCustomCompare
  1780. else
  1781. OnDataPtrCompare := nil;
  1782. end;
  1783. procedure TFPGMapInterfacedObjectData.InitOnPtrCompare;
  1784. begin
  1785. SetOnKeyCompare(nil);
  1786. SetOnDataCompare(nil);
  1787. end;
  1788. procedure TFPGMapInterfacedObjectData.PutKey(Index: Integer; const NewKey: TKey);
  1789. begin
  1790. inherited PutKey(Index, @NewKey);
  1791. end;
  1792. procedure TFPGMapInterfacedObjectData.PutData(Index: Integer; const NewData: TData);
  1793. begin
  1794. inherited PutData(Index, @NewData);
  1795. end;
  1796. procedure TFPGMapInterfacedObjectData.PutKeyData(const AKey: TKey; const NewData: TData);
  1797. begin
  1798. inherited PutKeyData(@AKey, @NewData);
  1799. end;
  1800. function TFPGMapInterfacedObjectData.Add(const AKey: TKey): Integer;
  1801. begin
  1802. Result := inherited Add(@AKey);
  1803. end;
  1804. function TFPGMapInterfacedObjectData.Add(const AKey: TKey; const AData: TData): Integer;
  1805. begin
  1806. Result := inherited Add(@AKey, @AData);
  1807. end;
  1808. function TFPGMapInterfacedObjectData.Find(const AKey: TKey; out Index: Integer): Boolean;
  1809. begin
  1810. Result := inherited Find(@AKey, Index);
  1811. end;
  1812. function TFPGMapInterfacedObjectData.TryGetData(const AKey: TKey; out AData: TData): Boolean;
  1813. var
  1814. I: Integer;
  1815. begin
  1816. I := IndexOf(AKey);
  1817. Result := (I >= 0);
  1818. if Result then
  1819. AData := TData(inherited GetData(I)^)
  1820. else
  1821. AData := Default(TData);
  1822. end;
  1823. procedure TFPGMapInterfacedObjectData.AddOrSetData(const AKey: TKey;
  1824. const AData: TData);
  1825. begin
  1826. inherited PutKeyData(@AKey, @AData);
  1827. end;
  1828. function TFPGMapInterfacedObjectData.IndexOf(const AKey: TKey): Integer;
  1829. begin
  1830. Result := inherited IndexOf(@AKey);
  1831. end;
  1832. function TFPGMapInterfacedObjectData.IndexOfData(const AData: TData): Integer;
  1833. begin
  1834. { TODO: loop ? }
  1835. Result := inherited IndexOfData(@AData);
  1836. end;
  1837. procedure TFPGMapInterfacedObjectData.InsertKey(Index: Integer; const AKey: TKey);
  1838. begin
  1839. inherited InsertKey(Index, @AKey);
  1840. end;
  1841. procedure TFPGMapInterfacedObjectData.InsertKeyData(Index: Integer; const AKey: TKey; const AData: TData);
  1842. begin
  1843. inherited InsertKeyData(Index, @AKey, @AData);
  1844. end;
  1845. function TFPGMapInterfacedObjectData.Remove(const AKey: TKey): Integer;
  1846. begin
  1847. Result := inherited Remove(@AKey);
  1848. end;
  1849. end.