fgl.pp 59 KB

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