fgl.pp 59 KB

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