fgl.pp 59 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115
  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. if FCount < FCapacity then exit;
  629. IncSize := 4;
  630. if FCapacity > 3 then IncSize := IncSize + 4;
  631. if FCapacity > 8 then IncSize := IncSize + 8;
  632. if FCapacity > 127 then Inc(IncSize, FCapacity shr 2);
  633. if FCapacity+IncSize>MaxListSize then
  634. IncSize:=MaxListSize-FCapacity;
  635. // If we were at max capacity already, force error.
  636. If IncSize<=0 then
  637. IncSize:=1; // Will trigger error
  638. SetCapacity(FCapacity + IncSize);
  639. Result := Self;
  640. end;
  641. function TFPSList.GetFirst: Pointer;
  642. begin
  643. If FCount = 0 then
  644. Result := Nil
  645. else
  646. Result := InternalItems[0];
  647. end;
  648. procedure TFPSList.SetFirst(const Value: Pointer);
  649. begin
  650. Put(0, Value);
  651. end;
  652. function TFPSList.IndexOf(Item: Pointer): Integer;
  653. var
  654. ListItem: Pointer;
  655. begin
  656. Result := 0;
  657. ListItem := First;
  658. while (Result < FCount) and (CompareByte(ListItem^, Item^, FItemSize) <> 0) do
  659. begin
  660. Inc(Result);
  661. ListItem := PByte(ListItem)+FItemSize;
  662. end;
  663. if Result = FCount then Result := -1;
  664. end;
  665. function TFPSList.Insert(Index: Integer): Pointer;
  666. begin
  667. if (Index < 0) or (Index > FCount) then
  668. Error(SListIndexError, Index);
  669. if FCount = FCapacity then Self.Expand;
  670. Result := InternalItems[Index];
  671. if Index<FCount then
  672. begin
  673. System.Move(Result^, (Result+FItemSize)^, (FCount - Index) * FItemSize);
  674. { clear for compiler assisted types }
  675. System.FillByte(Result^, FItemSize, 0);
  676. end;
  677. Inc(FCount);
  678. end;
  679. procedure TFPSList.Insert(Index: Integer; Item: Pointer);
  680. begin
  681. CopyItem(Item, Insert(Index));
  682. end;
  683. function TFPSList.GetLast: Pointer;
  684. begin
  685. if FCount = 0 then
  686. Result := nil
  687. else
  688. Result := InternalItems[FCount - 1];
  689. end;
  690. procedure TFPSList.SetLast(const Value: Pointer);
  691. begin
  692. Put(FCount - 1, Value);
  693. end;
  694. procedure TFPSList.Move(CurIndex, NewIndex: Integer);
  695. var
  696. CurItem, NewItem, TmpItem, Src, Dest: Pointer;
  697. MoveCount: Integer;
  698. begin
  699. CheckIndex(CurIndex);
  700. CheckIndex(NewIndex);
  701. if CurIndex = NewIndex then
  702. exit;
  703. CurItem := InternalItems[CurIndex];
  704. NewItem := InternalItems[NewIndex];
  705. TmpItem := InternalItems[FCapacity];
  706. System.Move(CurItem^, TmpItem^, FItemSize);
  707. if NewIndex > CurIndex then
  708. begin
  709. Src := InternalItems[CurIndex+1];
  710. Dest := CurItem;
  711. MoveCount := NewIndex - CurIndex;
  712. end else begin
  713. Src := NewItem;
  714. Dest := InternalItems[NewIndex+1];
  715. MoveCount := CurIndex - NewIndex;
  716. end;
  717. System.Move(Src^, Dest^, MoveCount * FItemSize);
  718. System.Move(TmpItem^, NewItem^, FItemSize);
  719. end;
  720. function TFPSList.Remove(Item: Pointer): Integer;
  721. begin
  722. Result := IndexOf(Item);
  723. if Result <> -1 then
  724. Delete(Result);
  725. end;
  726. const LocalThreshold = 64;
  727. procedure TFPSList.Pack;
  728. var
  729. LItemSize : integer;
  730. NewCount,
  731. i : integer;
  732. pdest,
  733. psrc : Pointer;
  734. localnul : array[0..LocalThreshold-1] of byte;
  735. pnul : pointer;
  736. begin
  737. LItemSize:=FItemSize;
  738. pnul:=@localnul;
  739. if LItemSize>Localthreshold then
  740. getmem(pnul,LItemSize);
  741. fillchar(pnul^,LItemSize,#0);
  742. NewCount:=0;
  743. psrc:=First;
  744. pdest:=psrc;
  745. For I:=0 To FCount-1 Do
  746. begin
  747. if not CompareMem(psrc,pnul,LItemSize) then
  748. begin
  749. System.Move(psrc^, pdest^, LItemSize);
  750. inc(pdest,LItemSIze);
  751. inc(NewCount);
  752. end
  753. else
  754. deref(psrc);
  755. inc(psrc,LitemSize);
  756. end;
  757. if LItemSize>Localthreshold then
  758. FreeMem(pnul,LItemSize);
  759. FCount:=NewCount;
  760. end;
  761. procedure TFPSList.Sort(Compare: TFPSListCompareFunc);
  762. begin
  763. Sort(Compare, {$IFDEF FPC_DOTTEDUNITS}System.{$ENDIF}SortBase.DefaultSortingAlgorithm);
  764. end;
  765. type
  766. PFPSList_Sort_Comparer_Context = ^TFPSList_Sort_Comparer_Context;
  767. TFPSList_Sort_Comparer_Context = record
  768. Compare: TFPSListCompareFunc;
  769. end;
  770. function TFPSList_Sort_Comparer(Item1, Item2, Context: Pointer): Integer;
  771. begin
  772. Result := PFPSList_Sort_Comparer_Context(Context)^.Compare(Item1, Item2);
  773. end;
  774. procedure TFPSList.Sort(Compare: TFPSListCompareFunc; SortingAlgorithm: PSortingAlgorithm);
  775. var
  776. Context: TFPSList_Sort_Comparer_Context;
  777. begin
  778. Context.Compare := Compare;
  779. SortingAlgorithm^.ItemListSorter_ContextComparer(FList, FCount, FItemSize, @TFPSList_Sort_Comparer, @Context);
  780. end;
  781. procedure TFPSList.QuickSort(L, R: Integer; Compare: TFPSListCompareFunc);
  782. var
  783. Context: TFPSList_Sort_Comparer_Context;
  784. SortingAlgorithm: PSortingAlgorithm;
  785. begin
  786. if (R > L) and (L >= 0) then
  787. begin
  788. Context.Compare := Compare;
  789. SortingAlgorithm := {$IFDEF FPC_DOTTEDUNITS}System.{$ENDIF}SortBase.DefaultSortingAlgorithm;
  790. SortingAlgorithm^.ItemListSorter_ContextComparer(FList + FItemSize*L, R-L+1, FItemSize, @TFPSList_Sort_Comparer, @Context);
  791. end;
  792. end;
  793. procedure TFPSList.AddList(Obj: TFPSList);
  794. var
  795. i: Integer;
  796. begin
  797. if Obj.ItemSize <> FItemSize then
  798. Error(SListItemSizeError, 0);
  799. // Do this now.
  800. Capacity:=Capacity+Obj.Count;
  801. if ItemIsManaged then
  802. begin
  803. // nothing for it, need to do it manually to give deref a chance.
  804. For I:=0 to Obj.Count-1 do
  805. Add(Obj[i])
  806. end
  807. else
  808. begin
  809. if Obj.Count=0 then
  810. exit;
  811. CopyItems(Obj.InternalItems[0],InternalItems[FCount],Obj.Count);
  812. FCount:=FCount+Obj.Count;
  813. end
  814. end;
  815. procedure TFPSList.Assign(Obj: TFPSList);
  816. begin
  817. // We must do this check here, to avoid clearing the list.
  818. if Obj.ItemSize <> FItemSize then
  819. Error(SListItemSizeError, 0);
  820. Clear;
  821. AddList(Obj);
  822. end;
  823. {****************************************************************************}
  824. {* TFPGListEnumerator *}
  825. {****************************************************************************}
  826. function TFPGListEnumerator.GetCurrent: T;
  827. begin
  828. Result := T(FList.Items[FPosition]^);
  829. end;
  830. constructor TFPGListEnumerator.Create(AList: TFPSList);
  831. begin
  832. inherited Create;
  833. FList := AList;
  834. FPosition := -1;
  835. end;
  836. function TFPGListEnumerator.MoveNext: Boolean;
  837. begin
  838. inc(FPosition);
  839. Result := FPosition < FList.Count;
  840. end;
  841. {****************************************************************************}
  842. {* TFPGList *}
  843. {****************************************************************************}
  844. constructor TFPGList.Create;
  845. begin
  846. inherited Create(sizeof(T));
  847. end;
  848. procedure TFPGList.CopyItem(Src, Dest: Pointer);
  849. begin
  850. T(Dest^) := T(Src^);
  851. end;
  852. procedure TFPGList.Deref(Item: Pointer);
  853. begin
  854. Finalize(T(Item^));
  855. end;
  856. function TFPGList.Get(Index: Integer): T;
  857. begin
  858. Result := T(inherited Get(Index)^);
  859. end;
  860. function TFPGList.GetList: PTypeList;
  861. begin
  862. Result := PTypeList(@FList);
  863. end;
  864. function TFPGList.ItemPtrCompare(Item1, Item2: Pointer): Integer;
  865. begin
  866. Result := FOnCompare(T(Item1^), T(Item2^));
  867. end;
  868. procedure TFPGList.Put(Index: Integer; const Item: T);
  869. begin
  870. inherited Put(Index, @Item);
  871. end;
  872. function TFPGList.Add(const Item: T): Integer;
  873. begin
  874. Result := inherited Add(@Item);
  875. end;
  876. function TFPGList.Extract(const Item: T): T;
  877. begin
  878. inherited Extract(@Item, @Result);
  879. end;
  880. function TFPGList.GetFirst: T;
  881. begin
  882. if FCount<>0 then
  883. Result := T(inherited GetFirst^)
  884. else
  885. Result:=Default(T);
  886. end;
  887. procedure TFPGList.SetFirst(const Value: T);
  888. begin
  889. inherited SetFirst(@Value);
  890. end;
  891. class function TFPGList.ItemIsManaged: Boolean;
  892. begin
  893. {$IFNDEF VER3_0}
  894. Result:=IsManagedType(T);
  895. {$ELSE}
  896. Result:=True; // Fallback to old behaviour
  897. {$ENDIF}
  898. end;
  899. function TFPGList.GetEnumerator: TFPGListEnumeratorSpec;
  900. begin
  901. Result := TFPGListEnumeratorSpec.Create(Self);
  902. end;
  903. function TFPGList.IndexOf(const Item: T): Integer;
  904. begin
  905. Result := 0;
  906. {$info TODO: fix inlining to work! InternalItems[Result]^}
  907. while (Result < FCount) and (PT(FList)[Result] <> Item) do
  908. Inc(Result);
  909. if Result = FCount then
  910. Result := -1;
  911. end;
  912. procedure TFPGList.Insert(Index: Integer; const Item: T);
  913. begin
  914. T(inherited Insert(Index)^) := Item;
  915. end;
  916. function TFPGList.GetLast: T;
  917. begin
  918. if FCount<>0 then
  919. Result := T(inherited GetLast^)
  920. else
  921. result:=Default(T);
  922. end;
  923. procedure TFPGList.SetLast(const Value: T);
  924. begin
  925. inherited SetLast(@Value);
  926. end;
  927. procedure TFPGList.AddList(Source: TFPGList);
  928. var
  929. i: Integer;
  930. begin
  931. if ItemIsManaged then
  932. begin
  933. Capacity:=Capacity+Source.Count;
  934. for I := 0 to Source.Count - 1 do
  935. Add(Source[i]);
  936. end
  937. else
  938. Inherited AddList(TFPSList(source))
  939. end;
  940. procedure TFPGList.Assign(Source: TFPGList);
  941. begin
  942. if ItemIsManaged then
  943. begin
  944. Clear;
  945. AddList(Source);
  946. end
  947. else
  948. Inherited Assign(TFPSList(source))
  949. end;
  950. function TFPGList.Remove(const Item: T): Integer;
  951. begin
  952. Result := IndexOf(Item);
  953. if Result >= 0 then
  954. Delete(Result);
  955. end;
  956. procedure TFPGList.Sort(Compare: TCompareFunc);
  957. begin
  958. FOnCompare := Compare;
  959. inherited Sort(@ItemPtrCompare);
  960. end;
  961. procedure TFPGList.Sort(Compare: TCompareFunc; SortingAlgorithm: PSortingAlgorithm);
  962. begin
  963. FOnCompare := Compare;
  964. inherited Sort(@ItemPtrCompare, SortingAlgorithm);
  965. end;
  966. {****************************************************************************}
  967. {* TFPGObjectList *}
  968. {****************************************************************************}
  969. constructor TFPGObjectList.Create(FreeObjects: Boolean);
  970. begin
  971. inherited Create;
  972. FFreeObjects := FreeObjects;
  973. end;
  974. procedure TFPGObjectList.CopyItem(Src, Dest: Pointer);
  975. begin
  976. T(Dest^) := T(Src^);
  977. end;
  978. procedure TFPGObjectList.Deref(Item: Pointer);
  979. begin
  980. if FFreeObjects then
  981. T(Item^).Free;
  982. end;
  983. function TFPGObjectList.Get(Index: Integer): T;
  984. begin
  985. Result := T(inherited Get(Index)^);
  986. end;
  987. function TFPGObjectList.GetList: PTypeList;
  988. begin
  989. Result := PTypeList(@FList);
  990. end;
  991. function TFPGObjectList.ItemPtrCompare(Item1, Item2: Pointer): Integer;
  992. begin
  993. Result := FOnCompare(T(Item1^), T(Item2^));
  994. end;
  995. procedure TFPGObjectList.Put(Index: Integer; const Item: T);
  996. begin
  997. inherited Put(Index, @Item);
  998. end;
  999. function TFPGObjectList.Add(const Item: T): Integer;
  1000. begin
  1001. Result := inherited Add(@Item);
  1002. end;
  1003. function TFPGObjectList.Extract(const Item: T): T;
  1004. begin
  1005. inherited Extract(@Item, @Result);
  1006. end;
  1007. function TFPGObjectList.GetFirst: T;
  1008. begin
  1009. if FCount<>0 then
  1010. Result := T(inherited GetFirst^)
  1011. else
  1012. Result := Default(T)
  1013. end;
  1014. procedure TFPGObjectList.SetFirst(const Value: T);
  1015. begin
  1016. inherited SetFirst(@Value);
  1017. end;
  1018. function TFPGObjectList.GetEnumerator: TFPGListEnumeratorSpec;
  1019. begin
  1020. Result := TFPGListEnumeratorSpec.Create(Self);
  1021. end;
  1022. function TFPGObjectList.IndexOf(const Item: T): Integer;
  1023. begin
  1024. Result :=
  1025. {$if sizeof(pointer) = sizeof(word)}
  1026. IndexWord
  1027. {$elseif sizeof(pointer) = sizeof(dword)}
  1028. IndexDWord
  1029. {$elseif sizeof(pointer) = sizeof(qword)}
  1030. IndexQWord
  1031. {$else}
  1032. {$error unknown pointer size}
  1033. {$endif}
  1034. (FList^, FCount, PtrUint(Pointer(Item)));
  1035. end;
  1036. procedure TFPGObjectList.Insert(Index: Integer; const Item: T);
  1037. begin
  1038. T(inherited Insert(Index)^) := Item;
  1039. end;
  1040. function TFPGObjectList.GetLast: T;
  1041. begin
  1042. if FCount<>0 then
  1043. Result := T(inherited GetLast^)
  1044. else
  1045. Result :=Default(T);
  1046. end;
  1047. procedure TFPGObjectList.SetLast(const Value: T);
  1048. begin
  1049. inherited SetLast(@Value);
  1050. end;
  1051. procedure TFPGObjectList.AddList(Source: TFPGObjectList);
  1052. var
  1053. i: Integer;
  1054. begin
  1055. for I := 0 to Source.Count - 1 do
  1056. Add(Source[i]);
  1057. end;
  1058. procedure TFPGObjectList.Assign(Source: TFPGObjectList);
  1059. begin
  1060. Clear;
  1061. AddList(Source);
  1062. end;
  1063. function TFPGObjectList.Remove(const Item: T): Integer;
  1064. begin
  1065. Result := IndexOf(Item);
  1066. if Result >= 0 then
  1067. Delete(Result);
  1068. end;
  1069. procedure TFPGObjectList.Sort(Compare: TCompareFunc);
  1070. begin
  1071. FOnCompare := Compare;
  1072. inherited Sort(@ItemPtrCompare);
  1073. end;
  1074. procedure TFPGObjectList.Sort(Compare: TCompareFunc; SortingAlgorithm: PSortingAlgorithm);
  1075. begin
  1076. FOnCompare := Compare;
  1077. inherited Sort(@ItemPtrCompare, SortingAlgorithm);
  1078. end;
  1079. {****************************************************************************}
  1080. {* TFPGInterfacedObjectList *}
  1081. {****************************************************************************}
  1082. constructor TFPGInterfacedObjectList.Create;
  1083. begin
  1084. inherited Create;
  1085. end;
  1086. procedure TFPGInterfacedObjectList.CopyItem(Src, Dest: Pointer);
  1087. begin
  1088. if Assigned(Pointer(Dest^)) then
  1089. T(Dest^)._Release;
  1090. Pointer(Dest^) := Pointer(Src^);
  1091. if Assigned(Pointer(Dest^)) then
  1092. T(Dest^)._AddRef;
  1093. end;
  1094. procedure TFPGInterfacedObjectList.Deref(Item: Pointer);
  1095. begin
  1096. if Assigned(Pointer(Item^)) then
  1097. T(Item^)._Release;
  1098. end;
  1099. function TFPGInterfacedObjectList.Get(Index: Integer): T;
  1100. begin
  1101. Result := T(inherited Get(Index)^);
  1102. end;
  1103. function TFPGInterfacedObjectList.GetList: PTypeList;
  1104. begin
  1105. Result := PTypeList(@FList);
  1106. end;
  1107. function TFPGInterfacedObjectList.ItemPtrCompare(Item1, Item2: Pointer): Integer;
  1108. begin
  1109. Result := FOnCompare(T(Item1^), T(Item2^));
  1110. end;
  1111. procedure TFPGInterfacedObjectList.Put(Index: Integer; const Item: T);
  1112. begin
  1113. CheckIndex(Index);
  1114. InternalItems[Index] := @Item; // eventually calls copyitem()
  1115. end;
  1116. function TFPGInterfacedObjectList.Add(const Item: T): Integer;
  1117. begin
  1118. Result := inherited Add(@Item);
  1119. end;
  1120. function TFPGInterfacedObjectList.Extract(const Item: T): T;
  1121. begin
  1122. inherited Extract(@Item, @Result);
  1123. end;
  1124. function TFPGInterfacedObjectList.GetFirst: T;
  1125. begin
  1126. Result := T(inherited GetFirst^);
  1127. end;
  1128. procedure TFPGInterfacedObjectList.SetFirst(const Value: T);
  1129. begin
  1130. inherited SetFirst(@Value);
  1131. end;
  1132. function TFPGInterfacedObjectList.GetEnumerator: TFPGListEnumeratorSpec;
  1133. begin
  1134. Result := TFPGListEnumeratorSpec.Create(Self);
  1135. end;
  1136. function TFPGInterfacedObjectList.IndexOf(const Item: T): Integer;
  1137. begin
  1138. Result :=
  1139. {$if sizeof(pointer) = sizeof(word)}
  1140. IndexWord
  1141. {$elseif sizeof(pointer) = sizeof(dword)}
  1142. IndexDWord
  1143. {$elseif sizeof(pointer) = sizeof(qword)}
  1144. IndexQWord
  1145. {$else}
  1146. {$error unknown pointer size}
  1147. {$endif}
  1148. (FList^, FCount, PtrUint(Pointer(Item)));
  1149. end;
  1150. procedure TFPGInterfacedObjectList.Insert(Index: Integer; const Item: T);
  1151. begin
  1152. T(inherited Insert(Index)^) := Item;
  1153. end;
  1154. function TFPGInterfacedObjectList.GetLast: T;
  1155. begin
  1156. Result := T(inherited GetLast^);
  1157. end;
  1158. procedure TFPGInterfacedObjectList.SetLast(const Value: T);
  1159. begin
  1160. inherited SetLast(@Value);
  1161. end;
  1162. procedure TFPGInterfacedObjectList.Assign(Source: TFPGInterfacedObjectList);
  1163. begin
  1164. Clear;
  1165. AddList(Source);
  1166. end;
  1167. procedure TFPGInterfacedObjectList.AddList(Source: TFPGInterfacedObjectList);
  1168. var
  1169. i: Integer;
  1170. begin
  1171. for I := 0 to Source.Count - 1 do
  1172. Add(Source[i]);
  1173. end;
  1174. function TFPGInterfacedObjectList.Remove(const Item: T): Integer;
  1175. begin
  1176. Result := IndexOf(Item);
  1177. if Result >= 0 then
  1178. Delete(Result);
  1179. end;
  1180. procedure TFPGInterfacedObjectList.Sort(Compare: TCompareFunc);
  1181. begin
  1182. FOnCompare := Compare;
  1183. inherited Sort(@ItemPtrCompare);
  1184. end;
  1185. procedure TFPGInterfacedObjectList.Sort(Compare: TCompareFunc; SortingAlgorithm: PSortingAlgorithm);
  1186. begin
  1187. FOnCompare := Compare;
  1188. inherited Sort(@ItemPtrCompare, SortingAlgorithm);
  1189. end;
  1190. {****************************************************************************
  1191. TFPSMap
  1192. ****************************************************************************}
  1193. constructor TFPSMap.Create(AKeySize: Integer; ADataSize: integer);
  1194. begin
  1195. inherited Create(AKeySize+ADataSize);
  1196. FKeySize := AKeySize;
  1197. FDataSize := ADataSize;
  1198. InitOnPtrCompare;
  1199. end;
  1200. procedure TFPSMap.CopyKey(Src, Dest: Pointer);
  1201. begin
  1202. System.Move(Src^, Dest^, FKeySize);
  1203. end;
  1204. procedure TFPSMap.CopyData(Src, Dest: Pointer);
  1205. begin
  1206. System.Move(Src^, Dest^, FDataSize);
  1207. end;
  1208. function TFPSMap.GetKey(Index: Integer): Pointer;
  1209. begin
  1210. Result := Items[Index];
  1211. end;
  1212. function TFPSMap.GetData(Index: Integer): Pointer;
  1213. begin
  1214. Result := PByte(Items[Index])+FKeySize;
  1215. end;
  1216. function TFPSMap.GetKeyData(AKey: Pointer): Pointer;
  1217. var
  1218. I: Integer;
  1219. begin
  1220. I := IndexOf(AKey);
  1221. if I >= 0 then
  1222. Result := InternalItems[I]+FKeySize
  1223. else
  1224. Error(SMapKeyError, PtrUInt(AKey));
  1225. end;
  1226. function TFPSMap.BinaryCompareKey(Key1, Key2: Pointer): Integer;
  1227. begin
  1228. Result := CompareByte(Key1^, Key2^, FKeySize);
  1229. end;
  1230. function TFPSMap.BinaryCompareData(Data1, Data2: Pointer): Integer;
  1231. begin
  1232. Result := CompareByte(Data1^, Data2^, FDataSize);
  1233. end;
  1234. procedure TFPSMap.SetOnKeyPtrCompare(Proc: TFPSListCompareFunc);
  1235. begin
  1236. if Proc <> nil then
  1237. FOnKeyPtrCompare := Proc
  1238. else
  1239. FOnKeyPtrCompare := @BinaryCompareKey;
  1240. end;
  1241. procedure TFPSMap.SetOnDataPtrCompare(Proc: TFPSListCompareFunc);
  1242. begin
  1243. if Proc <> nil then
  1244. FOnDataPtrCompare := Proc
  1245. else
  1246. FOnDataPtrCompare := @BinaryCompareData;
  1247. end;
  1248. procedure TFPSMap.InitOnPtrCompare;
  1249. begin
  1250. SetOnKeyPtrCompare(nil);
  1251. SetOnDataPtrCompare(nil);
  1252. end;
  1253. procedure TFPSMap.PutKey(Index: Integer; AKey: Pointer);
  1254. begin
  1255. if FSorted then
  1256. Error(SSortedListError, 0);
  1257. CopyKey(AKey, Items[Index]);
  1258. end;
  1259. procedure TFPSMap.PutData(Index: Integer; AData: Pointer);
  1260. begin
  1261. CopyData(AData, PByte(Items[Index])+FKeySize);
  1262. end;
  1263. procedure TFPSMap.PutKeyData(AKey: Pointer; NewData: Pointer);
  1264. var
  1265. I: Integer;
  1266. begin
  1267. I := IndexOf(AKey);
  1268. if I >= 0 then
  1269. Data[I] := NewData
  1270. else
  1271. Add(AKey, NewData);
  1272. end;
  1273. procedure TFPSMap.SetSorted(Value: Boolean);
  1274. begin
  1275. if Value = FSorted then exit;
  1276. FSorted := Value;
  1277. if Value then Sort;
  1278. end;
  1279. function TFPSMap.Add(AKey: Pointer): Integer;
  1280. begin
  1281. if Sorted then
  1282. begin
  1283. if Find(AKey, Result) then
  1284. case Duplicates of
  1285. dupIgnore: exit;
  1286. dupError: Error(SDuplicateItem, 0)
  1287. end;
  1288. end else
  1289. Result := Count;
  1290. CopyKey(AKey, inherited Insert(Result));
  1291. end;
  1292. function TFPSMap.Add(AKey, AData: Pointer): Integer;
  1293. begin
  1294. Result := Add(AKey);
  1295. Data[Result] := AData;
  1296. end;
  1297. function TFPSMap.Find(AKey: Pointer; out Index: Integer): Boolean;
  1298. { Searches for the first item <= Key, returns True if exact match,
  1299. sets index to the index of the found string. }
  1300. var
  1301. I,L,R,Dir: Integer;
  1302. begin
  1303. Result := false;
  1304. Index := -1;
  1305. if not Sorted then
  1306. raise EListError.Create(SErrFindNeedsSortedList);
  1307. // Use binary search.
  1308. L := 0;
  1309. R := FCount-1;
  1310. while L<=R do
  1311. begin
  1312. I := L + (R - L) div 2;
  1313. Dir := FOnKeyPtrCompare(Items[I], AKey);
  1314. if Dir < 0 then
  1315. L := I+1
  1316. else begin
  1317. R := I-1;
  1318. if Dir = 0 then
  1319. begin
  1320. Result := true;
  1321. if Duplicates <> dupAccept then
  1322. L := I;
  1323. end;
  1324. end;
  1325. end;
  1326. Index := L;
  1327. end;
  1328. function TFPSMap.LinearIndexOf(AKey: Pointer): Integer;
  1329. var
  1330. ListItem: Pointer;
  1331. begin
  1332. Result := 0;
  1333. ListItem := First;
  1334. while (Result < FCount) and (FOnKeyPtrCompare(ListItem, AKey) <> 0) do
  1335. begin
  1336. Inc(Result);
  1337. ListItem := PByte(ListItem)+FItemSize;
  1338. end;
  1339. if Result = FCount then Result := -1;
  1340. end;
  1341. function TFPSMap.IndexOf(AKey: Pointer): Integer;
  1342. begin
  1343. if Sorted then
  1344. begin
  1345. if not Find(AKey, Result) then
  1346. Result := -1;
  1347. end else
  1348. Result := LinearIndexOf(AKey);
  1349. end;
  1350. function TFPSMap.IndexOfData(AData: Pointer): Integer;
  1351. var
  1352. ListItem: Pointer;
  1353. begin
  1354. Result := 0;
  1355. ListItem := First+FKeySize;
  1356. while (Result < FCount) and (FOnDataPtrCompare(ListItem, AData) <> 0) do
  1357. begin
  1358. Inc(Result);
  1359. ListItem := PByte(ListItem)+FItemSize;
  1360. end;
  1361. if Result = FCount then Result := -1;
  1362. end;
  1363. function TFPSMap.Insert(Index: Integer): Pointer;
  1364. begin
  1365. if FSorted then
  1366. Error(SSortedListError, 0);
  1367. Result := inherited Insert(Index);
  1368. end;
  1369. procedure TFPSMap.Insert(Index: Integer; out AKey, AData: Pointer);
  1370. begin
  1371. AKey := Insert(Index);
  1372. AData := PByte(AKey) + FKeySize;
  1373. end;
  1374. procedure TFPSMap.InsertKey(Index: Integer; AKey: Pointer);
  1375. begin
  1376. CopyKey(AKey, Insert(Index));
  1377. end;
  1378. procedure TFPSMap.InsertKeyData(Index: Integer; AKey, AData: Pointer);
  1379. var
  1380. ListItem: Pointer;
  1381. begin
  1382. ListItem := Insert(Index);
  1383. CopyKey(AKey, ListItem);
  1384. CopyData(AData, PByte(ListItem)+FKeySize);
  1385. end;
  1386. function TFPSMap.Remove(AKey: Pointer): Integer;
  1387. begin
  1388. Result := IndexOf(AKey);
  1389. if Result >= 0 then
  1390. Delete(Result);
  1391. end;
  1392. procedure TFPSMap.Sort;
  1393. begin
  1394. inherited Sort(FOnKeyPtrCompare);
  1395. end;
  1396. procedure TFPSMap.Sort(SortingAlgorithm: PSortingAlgorithm);
  1397. begin
  1398. inherited Sort(FOnKeyPtrCompare, SortingAlgorithm);
  1399. end;
  1400. {****************************************************************************
  1401. TFPGMap
  1402. ****************************************************************************}
  1403. constructor TFPGMap.Create;
  1404. begin
  1405. inherited Create(SizeOf(TKey), SizeOf(TData));
  1406. end;
  1407. procedure TFPGMap.CopyItem(Src, Dest: Pointer);
  1408. begin
  1409. CopyKey(Src, Dest);
  1410. CopyData(PByte(Src)+KeySize, PByte(Dest)+KeySize);
  1411. end;
  1412. procedure TFPGMap.CopyKey(Src, Dest: Pointer);
  1413. begin
  1414. TKey(Dest^) := TKey(Src^);
  1415. end;
  1416. procedure TFPGMap.CopyData(Src, Dest: Pointer);
  1417. begin
  1418. TData(Dest^) := TData(Src^);
  1419. end;
  1420. procedure TFPGMap.Deref(Item: Pointer);
  1421. begin
  1422. Finalize(TKey(Item^));
  1423. Finalize(TData(Pointer(PByte(Item)+KeySize)^));
  1424. end;
  1425. function TFPGMap.GetKey(Index: Integer): TKey;
  1426. begin
  1427. Result := TKey(inherited GetKey(Index)^);
  1428. end;
  1429. function TFPGMap.GetData(Index: Integer): TData;
  1430. begin
  1431. Result := TData(inherited GetData(Index)^);
  1432. end;
  1433. function TFPGMap.GetKeyData(const AKey: TKey): TData;
  1434. begin
  1435. Result := TData(inherited GetKeyData(@AKey)^);
  1436. end;
  1437. function TFPGMap.KeyCompare(Key1, Key2: Pointer): Integer;
  1438. begin
  1439. if PKey(Key1)^ < PKey(Key2)^ then
  1440. Result := -1
  1441. else if PKey(Key1)^ > PKey(Key2)^ then
  1442. Result := 1
  1443. else
  1444. Result := 0;
  1445. end;
  1446. {function TFPGMap.DataCompare(Data1, Data2: Pointer): Integer;
  1447. begin
  1448. if PData(Data1)^ < PData(Data2)^ then
  1449. Result := -1
  1450. else if PData(Data1)^ > PData(Data2)^ then
  1451. Result := 1
  1452. else
  1453. Result := 0;
  1454. end;}
  1455. function TFPGMap.KeyCustomCompare(Key1, Key2: Pointer): Integer;
  1456. begin
  1457. Result := FOnKeyCompare(TKey(Key1^), TKey(Key2^));
  1458. end;
  1459. function TFPGMap.DataCustomCompare(Data1, Data2: Pointer): Integer;
  1460. begin
  1461. Result := FOnDataCompare(TData(Data1^), TData(Data2^));
  1462. end;
  1463. procedure TFPGMap.SetOnKeyCompare(NewCompare: TKeyCompareFunc);
  1464. begin
  1465. FOnKeyCompare := NewCompare;
  1466. if NewCompare <> nil then
  1467. OnKeyPtrCompare := @KeyCustomCompare
  1468. else
  1469. OnKeyPtrCompare := @KeyCompare;
  1470. end;
  1471. procedure TFPGMap.SetOnDataCompare(NewCompare: TDataCompareFunc);
  1472. begin
  1473. FOnDataCompare := NewCompare;
  1474. if NewCompare <> nil then
  1475. OnDataPtrCompare := @DataCustomCompare
  1476. else
  1477. OnDataPtrCompare := nil;
  1478. end;
  1479. procedure TFPGMap.InitOnPtrCompare;
  1480. begin
  1481. SetOnKeyCompare(nil);
  1482. SetOnDataCompare(nil);
  1483. end;
  1484. procedure TFPGMap.PutKey(Index: Integer; const NewKey: TKey);
  1485. begin
  1486. inherited PutKey(Index, @NewKey);
  1487. end;
  1488. procedure TFPGMap.PutData(Index: Integer; const NewData: TData);
  1489. begin
  1490. inherited PutData(Index, @NewData);
  1491. end;
  1492. procedure TFPGMap.PutKeyData(const AKey: TKey; const NewData: TData);
  1493. begin
  1494. inherited PutKeyData(@AKey, @NewData);
  1495. end;
  1496. function TFPGMap.Add(const AKey: TKey): Integer;
  1497. begin
  1498. Result := inherited Add(@AKey);
  1499. end;
  1500. function TFPGMap.Add(const AKey: TKey; const AData: TData): Integer;
  1501. begin
  1502. Result := inherited Add(@AKey, @AData);
  1503. end;
  1504. function TFPGMap.Find(const AKey: TKey; out Index: Integer): Boolean;
  1505. begin
  1506. Result := inherited Find(@AKey, Index);
  1507. end;
  1508. function TFPGMap.TryGetData(const AKey: TKey; out AData: TData): Boolean;
  1509. var
  1510. I: Integer;
  1511. begin
  1512. I := IndexOf(AKey);
  1513. Result := (I >= 0);
  1514. if Result then
  1515. AData := TData(inherited GetData(I)^)
  1516. else
  1517. AData := Default(TData);
  1518. end;
  1519. procedure TFPGMap.AddOrSetData(const AKey: TKey; const AData: TData);
  1520. begin
  1521. inherited PutKeyData(@AKey, @AData);
  1522. end;
  1523. function TFPGMap.IndexOf(const AKey: TKey): Integer;
  1524. begin
  1525. Result := inherited IndexOf(@AKey);
  1526. end;
  1527. function TFPGMap.IndexOfData(const AData: TData): Integer;
  1528. begin
  1529. { TODO: loop ? }
  1530. Result := inherited IndexOfData(@AData);
  1531. end;
  1532. procedure TFPGMap.InsertKey(Index: Integer; const AKey: TKey);
  1533. begin
  1534. inherited InsertKey(Index, @AKey);
  1535. end;
  1536. procedure TFPGMap.InsertKeyData(Index: Integer; const AKey: TKey; const AData: TData);
  1537. begin
  1538. inherited InsertKeyData(Index, @AKey, @AData);
  1539. end;
  1540. function TFPGMap.Remove(const AKey: TKey): Integer;
  1541. begin
  1542. Result := inherited Remove(@AKey);
  1543. end;
  1544. {****************************************************************************
  1545. TFPGMapObject
  1546. ****************************************************************************}
  1547. constructor TFPGMapObject.Create(AFreeObjects: Boolean);
  1548. begin
  1549. inherited Create(SizeOf(TKey), SizeOf(TData));
  1550. FFreeObjects := AFreeObjects;
  1551. end;
  1552. constructor TFPGMapObject.Create;
  1553. begin
  1554. Create(True);
  1555. end;
  1556. procedure TFPGMapObject.CopyItem(Src, Dest: Pointer);
  1557. begin
  1558. CopyKey(Src, Dest);
  1559. CopyData(PByte(Src)+KeySize, PByte(Dest)+KeySize);
  1560. end;
  1561. procedure TFPGMapObject.CopyKey(Src, Dest: Pointer);
  1562. begin
  1563. TKey(Dest^) := TKey(Src^);
  1564. end;
  1565. procedure TFPGMapObject.CopyData(Src, Dest: Pointer);
  1566. begin
  1567. if Assigned(Pointer(Dest^)) And FFreeObjects then
  1568. TData(Dest^).Free;
  1569. TData(Dest^) := TData(Src^);
  1570. end;
  1571. procedure TFPGMapObject.Deref(Item: Pointer);
  1572. begin
  1573. Finalize(TKey(Item^));
  1574. if Assigned(PPointer(PByte(Item)+KeySize)^) and FFreeObjects then
  1575. TData(Pointer(PByte(Item)+KeySize)^).Free;
  1576. end;
  1577. function TFPGMapObject.GetKey(Index: Integer): TKey;
  1578. begin
  1579. Result := TKey(inherited GetKey(Index)^);
  1580. end;
  1581. function TFPGMapObject.GetData(Index: Integer): TData;
  1582. begin
  1583. Result := TData(inherited GetData(Index)^);
  1584. end;
  1585. function TFPGMapObject.GetKeyData(const AKey: TKey): TData;
  1586. begin
  1587. Result := TData(inherited GetKeyData(@AKey)^);
  1588. end;
  1589. function TFPGMapObject.KeyCompare(Key1, Key2: Pointer): Integer;
  1590. begin
  1591. if PKey(Key1)^ < PKey(Key2)^ then
  1592. Result := -1
  1593. else if PKey(Key1)^ > PKey(Key2)^ then
  1594. Result := 1
  1595. else
  1596. Result := 0;
  1597. end;
  1598. {function TFPGMapObject.DataCompare(Data1, Data2: Pointer): Integer;
  1599. begin
  1600. if PData(Data1)^ < PData(Data2)^ then
  1601. Result := -1
  1602. else if PData(Data1)^ > PData(Data2)^ then
  1603. Result := 1
  1604. else
  1605. Result := 0;
  1606. end;}
  1607. function TFPGMapObject.KeyCustomCompare(Key1, Key2: Pointer): Integer;
  1608. begin
  1609. Result := FOnKeyCompare(TKey(Key1^), TKey(Key2^));
  1610. end;
  1611. function TFPGMapObject.DataCustomCompare(Data1, Data2: Pointer): Integer;
  1612. begin
  1613. Result := FOnDataCompare(TData(Data1^), TData(Data2^));
  1614. end;
  1615. procedure TFPGMapObject.SetOnKeyCompare(NewCompare: TKeyCompareFunc);
  1616. begin
  1617. FOnKeyCompare := NewCompare;
  1618. if NewCompare <> nil then
  1619. OnKeyPtrCompare := @KeyCustomCompare
  1620. else
  1621. OnKeyPtrCompare := @KeyCompare;
  1622. end;
  1623. procedure TFPGMapObject.SetOnDataCompare(NewCompare: TDataCompareFunc);
  1624. begin
  1625. FOnDataCompare := NewCompare;
  1626. if NewCompare <> nil then
  1627. OnDataPtrCompare := @DataCustomCompare
  1628. else
  1629. OnDataPtrCompare := nil;
  1630. end;
  1631. procedure TFPGMapObject.InitOnPtrCompare;
  1632. begin
  1633. SetOnKeyCompare(nil);
  1634. SetOnDataCompare(nil);
  1635. end;
  1636. procedure TFPGMapObject.PutKey(Index: Integer; const NewKey: TKey);
  1637. begin
  1638. inherited PutKey(Index, @NewKey);
  1639. end;
  1640. procedure TFPGMapObject.PutData(Index: Integer; const NewData: TData);
  1641. begin
  1642. inherited PutData(Index, @NewData);
  1643. end;
  1644. procedure TFPGMapObject.PutKeyData(const AKey: TKey; const NewData: TData);
  1645. begin
  1646. inherited PutKeyData(@AKey, @NewData);
  1647. end;
  1648. function TFPGMapObject.Add(const AKey: TKey): Integer;
  1649. begin
  1650. Result := inherited Add(@AKey);
  1651. end;
  1652. function TFPGMapObject.Add(const AKey: TKey; const AData: TData): Integer;
  1653. begin
  1654. Result := inherited Add(@AKey, @AData);
  1655. end;
  1656. function TFPGMapObject.Find(const AKey: TKey; out Index: Integer): Boolean;
  1657. begin
  1658. Result := inherited Find(@AKey, Index);
  1659. end;
  1660. function TFPGMapObject.TryGetData(const AKey: TKey; out AData: TData): Boolean;
  1661. var
  1662. I: Integer;
  1663. begin
  1664. I := IndexOf(AKey);
  1665. Result := (I >= 0);
  1666. if Result then
  1667. AData := TData(inherited GetData(I)^)
  1668. else
  1669. AData := Default(TData);
  1670. end;
  1671. procedure TFPGMapObject.AddOrSetData(const AKey: TKey; const AData: TData);
  1672. begin
  1673. inherited PutKeyData(@AKey, @AData);
  1674. end;
  1675. function TFPGMapObject.IndexOf(const AKey: TKey): Integer;
  1676. begin
  1677. Result := inherited IndexOf(@AKey);
  1678. end;
  1679. function TFPGMapObject.IndexOfData(const AData: TData): Integer;
  1680. begin
  1681. { TODO: loop ? }
  1682. Result := inherited IndexOfData(@AData);
  1683. end;
  1684. procedure TFPGMapObject.InsertKey(Index: Integer; const AKey: TKey);
  1685. begin
  1686. inherited InsertKey(Index, @AKey);
  1687. end;
  1688. procedure TFPGMapObject.InsertKeyData(Index: Integer; const AKey: TKey; const AData: TData);
  1689. begin
  1690. inherited InsertKeyData(Index, @AKey, @AData);
  1691. end;
  1692. function TFPGMapObject.Remove(const AKey: TKey): Integer;
  1693. begin
  1694. Result := inherited Remove(@AKey);
  1695. end;
  1696. {****************************************************************************
  1697. TFPGMapInterfacedObjectData
  1698. ****************************************************************************}
  1699. constructor TFPGMapInterfacedObjectData.Create;
  1700. begin
  1701. inherited Create(SizeOf(TKey), SizeOf(TData));
  1702. end;
  1703. procedure TFPGMapInterfacedObjectData.CopyItem(Src, Dest: Pointer);
  1704. begin
  1705. CopyKey(Src, Dest);
  1706. CopyData(PByte(Src)+KeySize, PByte(Dest)+KeySize);
  1707. end;
  1708. procedure TFPGMapInterfacedObjectData.CopyKey(Src, Dest: Pointer);
  1709. begin
  1710. TKey(Dest^) := TKey(Src^);
  1711. end;
  1712. procedure TFPGMapInterfacedObjectData.CopyData(Src, Dest: Pointer);
  1713. begin
  1714. if Assigned(Pointer(Dest^)) then
  1715. TData(Dest^)._Release;
  1716. TData(Dest^) := TData(Src^);
  1717. if Assigned(Pointer(Dest^)) then
  1718. TData(Dest^)._AddRef;
  1719. end;
  1720. procedure TFPGMapInterfacedObjectData.Deref(Item: Pointer);
  1721. begin
  1722. Finalize(TKey(Item^));
  1723. if Assigned(PPointer(PByte(Item)+KeySize)^) then
  1724. TData(Pointer(PByte(Item)+KeySize)^)._Release;
  1725. end;
  1726. function TFPGMapInterfacedObjectData.GetKey(Index: Integer): TKey;
  1727. begin
  1728. Result := TKey(inherited GetKey(Index)^);
  1729. end;
  1730. function TFPGMapInterfacedObjectData.GetData(Index: Integer): TData;
  1731. begin
  1732. Result := TData(inherited GetData(Index)^);
  1733. end;
  1734. function TFPGMapInterfacedObjectData.GetKeyData(const AKey: TKey): TData;
  1735. begin
  1736. Result := TData(inherited GetKeyData(@AKey)^);
  1737. end;
  1738. function TFPGMapInterfacedObjectData.KeyCompare(Key1, Key2: Pointer): Integer;
  1739. begin
  1740. if PKey(Key1)^ < PKey(Key2)^ then
  1741. Result := -1
  1742. else if PKey(Key1)^ > PKey(Key2)^ then
  1743. Result := 1
  1744. else
  1745. Result := 0;
  1746. end;
  1747. {function TFPGMapInterfacedObjectData.DataCompare(Data1, Data2: Pointer): Integer;
  1748. begin
  1749. if PData(Data1)^ < PData(Data2)^ then
  1750. Result := -1
  1751. else if PData(Data1)^ > PData(Data2)^ then
  1752. Result := 1
  1753. else
  1754. Result := 0;
  1755. end;}
  1756. function TFPGMapInterfacedObjectData.KeyCustomCompare(Key1, Key2: Pointer): Integer;
  1757. begin
  1758. Result := FOnKeyCompare(TKey(Key1^), TKey(Key2^));
  1759. end;
  1760. function TFPGMapInterfacedObjectData.DataCustomCompare(Data1, Data2: Pointer): Integer;
  1761. begin
  1762. Result := FOnDataCompare(TData(Data1^), TData(Data2^));
  1763. end;
  1764. procedure TFPGMapInterfacedObjectData.SetOnKeyCompare(NewCompare: TKeyCompareFunc);
  1765. begin
  1766. FOnKeyCompare := NewCompare;
  1767. if NewCompare <> nil then
  1768. OnKeyPtrCompare := @KeyCustomCompare
  1769. else
  1770. OnKeyPtrCompare := @KeyCompare;
  1771. end;
  1772. procedure TFPGMapInterfacedObjectData.SetOnDataCompare(NewCompare: TDataCompareFunc);
  1773. begin
  1774. FOnDataCompare := NewCompare;
  1775. if NewCompare <> nil then
  1776. OnDataPtrCompare := @DataCustomCompare
  1777. else
  1778. OnDataPtrCompare := nil;
  1779. end;
  1780. procedure TFPGMapInterfacedObjectData.InitOnPtrCompare;
  1781. begin
  1782. SetOnKeyCompare(nil);
  1783. SetOnDataCompare(nil);
  1784. end;
  1785. procedure TFPGMapInterfacedObjectData.PutKey(Index: Integer; const NewKey: TKey);
  1786. begin
  1787. inherited PutKey(Index, @NewKey);
  1788. end;
  1789. procedure TFPGMapInterfacedObjectData.PutData(Index: Integer; const NewData: TData);
  1790. begin
  1791. inherited PutData(Index, @NewData);
  1792. end;
  1793. procedure TFPGMapInterfacedObjectData.PutKeyData(const AKey: TKey; const NewData: TData);
  1794. begin
  1795. inherited PutKeyData(@AKey, @NewData);
  1796. end;
  1797. function TFPGMapInterfacedObjectData.Add(const AKey: TKey): Integer;
  1798. begin
  1799. Result := inherited Add(@AKey);
  1800. end;
  1801. function TFPGMapInterfacedObjectData.Add(const AKey: TKey; const AData: TData): Integer;
  1802. begin
  1803. Result := inherited Add(@AKey, @AData);
  1804. end;
  1805. function TFPGMapInterfacedObjectData.Find(const AKey: TKey; out Index: Integer): Boolean;
  1806. begin
  1807. Result := inherited Find(@AKey, Index);
  1808. end;
  1809. function TFPGMapInterfacedObjectData.TryGetData(const AKey: TKey; out AData: TData): Boolean;
  1810. var
  1811. I: Integer;
  1812. begin
  1813. I := IndexOf(AKey);
  1814. Result := (I >= 0);
  1815. if Result then
  1816. AData := TData(inherited GetData(I)^)
  1817. else
  1818. AData := Default(TData);
  1819. end;
  1820. procedure TFPGMapInterfacedObjectData.AddOrSetData(const AKey: TKey;
  1821. const AData: TData);
  1822. begin
  1823. inherited PutKeyData(@AKey, @AData);
  1824. end;
  1825. function TFPGMapInterfacedObjectData.IndexOf(const AKey: TKey): Integer;
  1826. begin
  1827. Result := inherited IndexOf(@AKey);
  1828. end;
  1829. function TFPGMapInterfacedObjectData.IndexOfData(const AData: TData): Integer;
  1830. begin
  1831. { TODO: loop ? }
  1832. Result := inherited IndexOfData(@AData);
  1833. end;
  1834. procedure TFPGMapInterfacedObjectData.InsertKey(Index: Integer; const AKey: TKey);
  1835. begin
  1836. inherited InsertKey(Index, @AKey);
  1837. end;
  1838. procedure TFPGMapInterfacedObjectData.InsertKeyData(Index: Integer; const AKey: TKey; const AData: TData);
  1839. begin
  1840. inherited InsertKeyData(Index, @AKey, @AData);
  1841. end;
  1842. function TFPGMapInterfacedObjectData.Remove(const AKey: TKey): Integer;
  1843. begin
  1844. Result := inherited Remove(@AKey);
  1845. end;
  1846. end.