fgl.pp 58 KB

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