fgl.pp 59 KB

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