fgl.pp 46 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649
  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 CLASSESINLINE}
  14. { be aware, this unit is a prototype and subject to be changed heavily }
  15. unit fgl;
  16. interface
  17. uses
  18. types, sysutils;
  19. {$IF defined(VER2_4)}
  20. {$DEFINE OldSyntax}
  21. {$IFEND}
  22. const
  23. MaxListSize = Maxint div 16;
  24. type
  25. EListError = class(Exception);
  26. TFPSList = class;
  27. TFPSListCompareFunc = function(Key1, Key2: Pointer): Integer of object;
  28. TFPSList = class(TObject)
  29. protected
  30. FList: PByte;
  31. FCount: Integer;
  32. FCapacity: Integer; { list is one longer sgthan capacity, for temp }
  33. FItemSize: Integer;
  34. procedure CopyItem(Src, Dest: Pointer); virtual;
  35. procedure Deref(Item: Pointer); virtual; overload;
  36. procedure Deref(FromIndex, ToIndex: Integer); overload;
  37. function Get(Index: Integer): Pointer;
  38. procedure InternalExchange(Index1, Index2: Integer);
  39. function InternalGet(Index: Integer): Pointer; {$ifdef CLASSESINLINE} inline; {$endif}
  40. procedure InternalPut(Index: Integer; NewItem: Pointer);
  41. procedure Put(Index: Integer; Item: Pointer);
  42. procedure QuickSort(L, R: Integer; Compare: TFPSListCompareFunc);
  43. procedure SetCapacity(NewCapacity: Integer);
  44. procedure SetCount(NewCount: Integer);
  45. procedure RaiseIndexError(Index : Integer);
  46. property InternalItems[Index: Integer]: Pointer read InternalGet write InternalPut;
  47. function GetLast: Pointer;
  48. procedure SetLast(const Value: Pointer);
  49. function GetFirst: Pointer;
  50. procedure SetFirst(const Value: Pointer);
  51. public
  52. constructor Create(AItemSize: Integer = sizeof(Pointer));
  53. destructor Destroy; override;
  54. function Add(Item: Pointer): Integer;
  55. procedure Clear;
  56. procedure Delete(Index: Integer);
  57. class procedure Error(const Msg: string; Data: PtrInt);
  58. procedure Exchange(Index1, Index2: Integer);
  59. function Expand: TFPSList;
  60. procedure Extract(Item: Pointer; ResultPtr: Pointer);
  61. function IndexOf(Item: Pointer): Integer;
  62. procedure Insert(Index: Integer; Item: Pointer);
  63. function Insert(Index: Integer): Pointer;
  64. procedure Move(CurIndex, NewIndex: Integer);
  65. procedure Assign(Obj: TFPSList);
  66. function Remove(Item: Pointer): Integer;
  67. procedure Pack;
  68. procedure Sort(Compare: TFPSListCompareFunc);
  69. property Capacity: Integer read FCapacity write SetCapacity;
  70. property Count: Integer read FCount write SetCount;
  71. property Items[Index: Integer]: Pointer read Get write Put; default;
  72. property ItemSize: Integer read FItemSize;
  73. property List: PByte read FList;
  74. property First: Pointer read GetFirst write SetFirst;
  75. property Last: Pointer read GetLast write SetLast;
  76. end;
  77. const
  78. MaxGListSize = MaxInt div 1024;
  79. type
  80. generic TFPGListEnumerator<T> = class(TObject)
  81. protected
  82. FList: TFPSList;
  83. FPosition: Integer;
  84. function GetCurrent: T;
  85. public
  86. constructor Create(AList: TFPSList);
  87. function MoveNext: Boolean;
  88. property Current: T read GetCurrent;
  89. end;
  90. generic TFPGList<T> = class(TFPSList)
  91. private
  92. type
  93. TCompareFunc = function(const Item1, Item2: T): Integer;
  94. TTypeList = array[0..MaxGListSize] of T;
  95. PTypeList = ^TTypeList;
  96. PT = ^T;
  97. TFPGListEnumeratorSpec = specialize TFPGListEnumerator<T>;
  98. {$ifndef OldSyntax}protected var{$else}var protected{$endif}
  99. FOnCompare: TCompareFunc;
  100. procedure CopyItem(Src, Dest: Pointer); override;
  101. procedure Deref(Item: Pointer); override;
  102. function Get(Index: Integer): T; {$ifdef CLASSESINLINE} inline; {$endif}
  103. function GetList: PTypeList; {$ifdef CLASSESINLINE} inline; {$endif}
  104. function ItemPtrCompare(Item1, Item2: Pointer): Integer;
  105. procedure Put(Index: Integer; const Item: T); {$ifdef CLASSESINLINE} inline; {$endif}
  106. function GetLast: T; {$ifdef CLASSESINLINE} inline; {$endif}
  107. procedure SetLast(const Value: T); {$ifdef CLASSESINLINE} inline; {$endif}
  108. function GetFirst: T; {$ifdef CLASSESINLINE} inline; {$endif}
  109. procedure SetFirst(const Value: T); {$ifdef CLASSESINLINE} inline; {$endif}
  110. public
  111. constructor Create;
  112. function Add(const Item: T): Integer; {$ifdef CLASSESINLINE} inline; {$endif}
  113. function Extract(const Item: T): T; {$ifdef CLASSESINLINE} inline; {$endif}
  114. property First: T read GetFirst write SetFirst;
  115. function GetEnumerator: TFPGListEnumeratorSpec; {$ifdef CLASSESINLINE} inline; {$endif}
  116. function IndexOf(const Item: T): Integer;
  117. procedure Insert(Index: Integer; const Item: T); {$ifdef CLASSESINLINE} inline; {$endif}
  118. property Last: T read GetLast write SetLast;
  119. {$ifndef VER2_4}
  120. procedure Assign(Source: TFPGList);
  121. {$endif VER2_4}
  122. function Remove(const Item: T): Integer; {$ifdef CLASSESINLINE} inline; {$endif}
  123. procedure Sort(Compare: TCompareFunc);
  124. property Items[Index: Integer]: T read Get write Put; default;
  125. property List: PTypeList read GetList;
  126. end;
  127. generic TFPGObjectList<T> = class(TFPSList)
  128. private
  129. type
  130. TCompareFunc = function(const Item1, Item2: T): Integer;
  131. TTypeList = array[0..MaxGListSize] of T;
  132. PTypeList = ^TTypeList;
  133. PT = ^T;
  134. TFPGListEnumeratorSpec = specialize TFPGListEnumerator<T>;
  135. {$ifndef OldSyntax}protected var{$else}var protected{$endif}
  136. FOnCompare: TCompareFunc;
  137. FFreeObjects: Boolean;
  138. procedure CopyItem(Src, Dest: Pointer); override;
  139. procedure Deref(Item: Pointer); override;
  140. function Get(Index: Integer): T; {$ifdef CLASSESINLINE} inline; {$endif}
  141. function GetList: PTypeList; {$ifdef CLASSESINLINE} inline; {$endif}
  142. function ItemPtrCompare(Item1, Item2: Pointer): Integer;
  143. procedure Put(Index: Integer; const Item: T); {$ifdef CLASSESINLINE} inline; {$endif}
  144. function GetLast: T; {$ifdef CLASSESINLINE} inline; {$endif}
  145. procedure SetLast(const Value: T); {$ifdef CLASSESINLINE} inline; {$endif}
  146. function GetFirst: T; {$ifdef CLASSESINLINE} inline; {$endif}
  147. procedure SetFirst(const Value: T); {$ifdef CLASSESINLINE} inline; {$endif}
  148. public
  149. constructor Create(FreeObjects: Boolean = True);
  150. function Add(const Item: T): Integer; {$ifdef CLASSESINLINE} inline; {$endif}
  151. function Extract(const Item: T): T; {$ifdef CLASSESINLINE} inline; {$endif}
  152. property First: T read GetFirst write SetFirst;
  153. function GetEnumerator: TFPGListEnumeratorSpec; {$ifdef CLASSESINLINE} inline; {$endif}
  154. function IndexOf(const Item: T): Integer;
  155. procedure Insert(Index: Integer; const Item: T); {$ifdef CLASSESINLINE} inline; {$endif}
  156. property Last: T read GetLast write SetLast;
  157. {$ifndef VER2_4}
  158. procedure Assign(Source: TFPGObjectList);
  159. {$endif VER2_4}
  160. function Remove(const Item: T): Integer; {$ifdef CLASSESINLINE} inline; {$endif}
  161. procedure Sort(Compare: TCompareFunc);
  162. property Items[Index: Integer]: T read Get write Put; default;
  163. property List: PTypeList read GetList;
  164. property FreeObjects: Boolean read FFreeObjects write FFreeObjects;
  165. end;
  166. generic TFPGInterfacedObjectList<T> = class(TFPSList)
  167. private
  168. type
  169. TCompareFunc = function(const Item1, Item2: T): Integer;
  170. TTypeList = array[0..MaxGListSize] of T;
  171. PTypeList = ^TTypeList;
  172. PT = ^T;
  173. TFPGListEnumeratorSpec = specialize TFPGListEnumerator<T>;
  174. {$ifndef OldSyntax}protected var{$else}var protected{$endif}
  175. FOnCompare: TCompareFunc;
  176. procedure CopyItem(Src, Dest: Pointer); override;
  177. procedure Deref(Item: Pointer); override;
  178. function Get(Index: Integer): T; {$ifdef CLASSESINLINE} inline; {$endif}
  179. function GetList: PTypeList; {$ifdef CLASSESINLINE} inline; {$endif}
  180. function ItemPtrCompare(Item1, Item2: Pointer): Integer;
  181. procedure Put(Index: Integer; const Item: T); {$ifdef CLASSESINLINE} inline; {$endif}
  182. function GetLast: T; {$ifdef CLASSESINLINE} inline; {$endif}
  183. procedure SetLast(const Value: T); {$ifdef CLASSESINLINE} inline; {$endif}
  184. function GetFirst: T; {$ifdef CLASSESINLINE} inline; {$endif}
  185. procedure SetFirst(const Value: T); {$ifdef CLASSESINLINE} inline; {$endif}
  186. public
  187. constructor Create;
  188. function Add(const Item: T): Integer; {$ifdef CLASSESINLINE} inline; {$endif}
  189. function Extract(const Item: T): T; {$ifdef CLASSESINLINE} inline; {$endif}
  190. property First: T read GetFirst write SetFirst;
  191. function GetEnumerator: TFPGListEnumeratorSpec; {$ifdef CLASSESINLINE} inline; {$endif}
  192. function IndexOf(const Item: T): Integer;
  193. procedure Insert(Index: Integer; const Item: T); {$ifdef CLASSESINLINE} inline; {$endif}
  194. property Last: T read GetLast write SetLast;
  195. {$ifndef VER2_4}
  196. procedure Assign(Source: TFPGInterfacedObjectList);
  197. {$endif VER2_4}
  198. function Remove(const Item: T): Integer; {$ifdef CLASSESINLINE} inline; {$endif}
  199. procedure Sort(Compare: TCompareFunc);
  200. property Items[Index: Integer]: T read Get write Put; default;
  201. property List: PTypeList read GetList;
  202. end;
  203. TFPSMap = class(TFPSList)
  204. private
  205. FKeySize: Integer;
  206. FDataSize: Integer;
  207. FDuplicates: TDuplicates;
  208. FSorted: Boolean;
  209. FOnKeyPtrCompare: TFPSListCompareFunc;
  210. FOnDataPtrCompare: TFPSListCompareFunc;
  211. procedure SetSorted(Value: Boolean);
  212. protected
  213. function BinaryCompareKey(Key1, Key2: Pointer): Integer;
  214. function BinaryCompareData(Data1, Data2: Pointer): Integer;
  215. procedure SetOnKeyPtrCompare(Proc: TFPSListCompareFunc);
  216. procedure SetOnDataPtrCompare(Proc: TFPSListCompareFunc);
  217. procedure InitOnPtrCompare; virtual;
  218. procedure CopyKey(Src, Dest: Pointer); virtual;
  219. procedure CopyData(Src, Dest: Pointer); virtual;
  220. function GetKey(Index: Integer): Pointer;
  221. function GetKeyData(AKey: Pointer): Pointer;
  222. function GetData(Index: Integer): Pointer;
  223. function LinearIndexOf(AKey: Pointer): Integer;
  224. procedure PutKey(Index: Integer; AKey: Pointer);
  225. procedure PutKeyData(AKey: Pointer; NewData: Pointer);
  226. procedure PutData(Index: Integer; AData: Pointer);
  227. public
  228. constructor Create(AKeySize: Integer = sizeof(Pointer);
  229. ADataSize: integer = sizeof(Pointer));
  230. function Add(AKey, AData: Pointer): Integer;
  231. function Add(AKey: Pointer): Integer;
  232. function Find(AKey: Pointer; out Index: Integer): Boolean;
  233. function IndexOf(AKey: Pointer): Integer;
  234. function IndexOfData(AData: Pointer): Integer;
  235. function Insert(Index: Integer): Pointer;
  236. procedure Insert(Index: Integer; out AKey, AData: Pointer);
  237. procedure InsertKey(Index: Integer; AKey: Pointer);
  238. procedure InsertKeyData(Index: Integer; AKey, AData: Pointer);
  239. function Remove(AKey: Pointer): Integer;
  240. procedure Sort;
  241. property Duplicates: TDuplicates read FDuplicates write FDuplicates;
  242. property KeySize: Integer read FKeySize;
  243. property DataSize: Integer read FDataSize;
  244. property Keys[Index: Integer]: Pointer read GetKey write PutKey;
  245. property Data[Index: Integer]: Pointer read GetData write PutData;
  246. property KeyData[Key: Pointer]: Pointer read GetKeyData write PutKeyData; default;
  247. property Sorted: Boolean read FSorted write SetSorted;
  248. property OnPtrCompare: TFPSListCompareFunc read FOnKeyPtrCompare write SetOnKeyPtrCompare; //deprecated;
  249. property OnKeyPtrCompare: TFPSListCompareFunc read FOnKeyPtrCompare write SetOnKeyPtrCompare;
  250. property OnDataPtrCompare: TFPSListCompareFunc read FOnDataPtrCompare write SetOnDataPtrCompare;
  251. end;
  252. generic TFPGMap<TKey, TData> = class(TFPSMap)
  253. private
  254. type
  255. TKeyCompareFunc = function(const Key1, Key2: TKey): Integer;
  256. TDataCompareFunc = function(const Data1, Data2: TData): Integer;
  257. PKey = ^TKey;
  258. // unsed PData = ^TData;
  259. {$ifndef OldSyntax}protected var{$else}var protected{$endif}
  260. FOnKeyCompare: TKeyCompareFunc;
  261. FOnDataCompare: TDataCompareFunc;
  262. procedure CopyItem(Src, Dest: Pointer); override;
  263. procedure CopyKey(Src, Dest: Pointer); override;
  264. procedure CopyData(Src, Dest: Pointer); override;
  265. procedure Deref(Item: Pointer); override;
  266. procedure InitOnPtrCompare; override;
  267. function GetKey(Index: Integer): TKey; {$ifdef CLASSESINLINE} inline; {$endif}
  268. function GetKeyData(const AKey: TKey): TData; {$ifdef CLASSESINLINE} inline; {$endif}
  269. function GetData(Index: Integer): TData; {$ifdef CLASSESINLINE} inline; {$endif}
  270. function KeyCompare(Key1, Key2: Pointer): Integer;
  271. function KeyCustomCompare(Key1, Key2: Pointer): Integer;
  272. //function DataCompare(Data1, Data2: Pointer): Integer;
  273. function DataCustomCompare(Data1, Data2: Pointer): Integer;
  274. procedure PutKey(Index: Integer; const NewKey: TKey); {$ifdef CLASSESINLINE} inline; {$endif}
  275. procedure PutKeyData(const AKey: TKey; const NewData: TData); {$ifdef CLASSESINLINE} inline; {$endif}
  276. procedure PutData(Index: Integer; const NewData: TData); {$ifdef CLASSESINLINE} inline; {$endif}
  277. procedure SetOnKeyCompare(NewCompare: TKeyCompareFunc);
  278. procedure SetOnDataCompare(NewCompare: TDataCompareFunc);
  279. public
  280. constructor Create;
  281. function Add(const AKey: TKey; const AData: TData): Integer; {$ifdef CLASSESINLINE} inline; {$endif}
  282. function Add(const AKey: TKey): Integer; {$ifdef CLASSESINLINE} inline; {$endif}
  283. function Find(const AKey: TKey; out Index: Integer): Boolean; {$ifdef CLASSESINLINE} inline; {$endif}
  284. function IndexOf(const AKey: TKey): Integer; {$ifdef CLASSESINLINE} inline; {$endif}
  285. function IndexOfData(const AData: TData): Integer;
  286. procedure InsertKey(Index: Integer; const AKey: TKey);
  287. procedure InsertKeyData(Index: Integer; const AKey: TKey; const AData: TData);
  288. function Remove(const AKey: TKey): Integer;
  289. property Keys[Index: Integer]: TKey read GetKey write PutKey;
  290. property Data[Index: Integer]: TData read GetData write PutData;
  291. property KeyData[const AKey: TKey]: TData read GetKeyData write PutKeyData; default;
  292. property OnCompare: TKeyCompareFunc read FOnKeyCompare write SetOnKeyCompare; //deprecated;
  293. property OnKeyCompare: TKeyCompareFunc read FOnKeyCompare write SetOnKeyCompare;
  294. property OnDataCompare: TDataCompareFunc read FOnDataCompare write SetOnDataCompare;
  295. end;
  296. generic TFPGMapInterfacedObjectData<TKey, TData> = class(TFPSMap)
  297. private
  298. type
  299. TKeyCompareFunc = function(const Key1, Key2: TKey): Integer;
  300. TDataCompareFunc = function(const Data1, Data2: TData): Integer;
  301. PKey = ^TKey;
  302. // unsed PData = ^TData;
  303. {$ifndef OldSyntax}protected var{$else}var protected{$endif}
  304. FOnKeyCompare: TKeyCompareFunc;
  305. FOnDataCompare: TDataCompareFunc;
  306. procedure CopyItem(Src, Dest: Pointer); override;
  307. procedure CopyKey(Src, Dest: Pointer); override;
  308. procedure CopyData(Src, Dest: Pointer); override;
  309. procedure Deref(Item: Pointer); override;
  310. procedure InitOnPtrCompare; override;
  311. function GetKey(Index: Integer): TKey; {$ifdef CLASSESINLINE} inline; {$endif}
  312. function GetKeyData(const AKey: TKey): TData; {$ifdef CLASSESINLINE} inline; {$endif}
  313. function GetData(Index: Integer): TData; {$ifdef CLASSESINLINE} inline; {$endif}
  314. function KeyCompare(Key1, Key2: Pointer): Integer;
  315. function KeyCustomCompare(Key1, Key2: Pointer): Integer;
  316. //function DataCompare(Data1, Data2: Pointer): Integer;
  317. function DataCustomCompare(Data1, Data2: Pointer): Integer;
  318. procedure PutKey(Index: Integer; const NewKey: TKey); {$ifdef CLASSESINLINE} inline; {$endif}
  319. procedure PutKeyData(const AKey: TKey; const NewData: TData); {$ifdef CLASSESINLINE} inline; {$endif}
  320. procedure PutData(Index: Integer; const NewData: TData); {$ifdef CLASSESINLINE} inline; {$endif}
  321. procedure SetOnKeyCompare(NewCompare: TKeyCompareFunc);
  322. procedure SetOnDataCompare(NewCompare: TDataCompareFunc);
  323. public
  324. constructor Create;
  325. function Add(const AKey: TKey; const AData: TData): Integer; {$ifdef CLASSESINLINE} inline; {$endif}
  326. function Add(const AKey: TKey): Integer; {$ifdef CLASSESINLINE} inline; {$endif}
  327. function Find(const AKey: TKey; out Index: Integer): Boolean; {$ifdef CLASSESINLINE} inline; {$endif}
  328. function IndexOf(const AKey: TKey): Integer; {$ifdef CLASSESINLINE} inline; {$endif}
  329. function IndexOfData(const AData: TData): Integer;
  330. procedure InsertKey(Index: Integer; const AKey: TKey);
  331. procedure InsertKeyData(Index: Integer; const AKey: TKey; const AData: TData);
  332. function Remove(const AKey: TKey): Integer;
  333. property Keys[Index: Integer]: TKey read GetKey write PutKey;
  334. property Data[Index: Integer]: TData read GetData write PutData;
  335. property KeyData[const AKey: TKey]: TData read GetKeyData write PutKeyData; default;
  336. property OnCompare: TKeyCompareFunc read FOnKeyCompare write SetOnKeyCompare; //deprecated;
  337. property OnKeyCompare: TKeyCompareFunc read FOnKeyCompare write SetOnKeyCompare;
  338. property OnDataCompare: TDataCompareFunc read FOnDataCompare write SetOnDataCompare;
  339. end;
  340. implementation
  341. uses
  342. rtlconsts;
  343. {****************************************************************************
  344. TFPSList
  345. ****************************************************************************}
  346. constructor TFPSList.Create(AItemSize: integer);
  347. begin
  348. inherited Create;
  349. FItemSize := AItemSize;
  350. end;
  351. destructor TFPSList.Destroy;
  352. begin
  353. Clear;
  354. // Clear() does not clear the whole list; there is always a single temp entry
  355. // at the end which is never freed. Take care of that one here.
  356. FreeMem(FList);
  357. inherited Destroy;
  358. end;
  359. procedure TFPSList.CopyItem(Src, Dest: Pointer);
  360. begin
  361. System.Move(Src^, Dest^, FItemSize);
  362. end;
  363. procedure TFPSList.RaiseIndexError(Index : Integer);
  364. begin
  365. Error(SListIndexError, Index);
  366. end;
  367. function TFPSList.InternalGet(Index: Integer): Pointer;
  368. begin
  369. Result:=FList+Index*ItemSize;
  370. end;
  371. procedure TFPSList.InternalPut(Index: Integer; NewItem: Pointer);
  372. var
  373. ListItem: Pointer;
  374. begin
  375. ListItem := InternalItems[Index];
  376. CopyItem(NewItem, ListItem);
  377. end;
  378. function TFPSList.Get(Index: Integer): Pointer;
  379. begin
  380. if (Index < 0) or (Index >= FCount) then
  381. RaiseIndexError(Index);
  382. Result := InternalItems[Index];
  383. end;
  384. procedure TFPSList.Put(Index: Integer; Item: Pointer);
  385. var p : Pointer;
  386. begin
  387. if (Index < 0) or (Index >= FCount) then
  388. RaiseIndexError(Index);
  389. p:=InternalItems[Index];
  390. if assigned(p) then
  391. DeRef(p);
  392. InternalItems[Index] := Item;
  393. end;
  394. procedure TFPSList.SetCapacity(NewCapacity: Integer);
  395. begin
  396. if (NewCapacity < FCount) or (NewCapacity > MaxListSize) then
  397. Error(SListCapacityError, NewCapacity);
  398. if NewCapacity = FCapacity then
  399. exit;
  400. ReallocMem(FList, (NewCapacity+1) * FItemSize);
  401. FillChar(InternalItems[FCapacity]^, (NewCapacity+1-FCapacity) * FItemSize, #0);
  402. FCapacity := NewCapacity;
  403. end;
  404. procedure TFPSList.Deref(Item: Pointer);
  405. begin
  406. end;
  407. procedure TFPSList.Deref(FromIndex, ToIndex: Integer);
  408. var
  409. ListItem, ListItemLast: Pointer;
  410. begin
  411. ListItem := InternalItems[FromIndex];
  412. ListItemLast := InternalItems[ToIndex];
  413. repeat
  414. Deref(ListItem);
  415. if ListItem = ListItemLast then
  416. break;
  417. ListItem := PByte(ListItem) + ItemSize;
  418. until false;
  419. end;
  420. procedure TFPSList.SetCount(NewCount: Integer);
  421. begin
  422. if (NewCount < 0) or (NewCount > MaxListSize) then
  423. Error(SListCountError, NewCount);
  424. if NewCount > FCapacity then
  425. SetCapacity(NewCount);
  426. if NewCount > FCount then
  427. FillByte(InternalItems[FCount]^, (NewCount-FCount) * FItemSize, 0)
  428. else if NewCount < FCount then
  429. Deref(NewCount, FCount-1);
  430. FCount := NewCount;
  431. end;
  432. function TFPSList.Add(Item: Pointer): Integer;
  433. begin
  434. if FCount = FCapacity then
  435. Self.Expand;
  436. CopyItem(Item, InternalItems[FCount]);
  437. Result := FCount;
  438. Inc(FCount);
  439. end;
  440. procedure TFPSList.Clear;
  441. begin
  442. if Assigned(FList) then
  443. begin
  444. SetCount(0);
  445. SetCapacity(0);
  446. end;
  447. end;
  448. procedure TFPSList.Delete(Index: Integer);
  449. var
  450. ListItem: Pointer;
  451. begin
  452. if (Index < 0) or (Index >= FCount) then
  453. Error(SListIndexError, Index);
  454. Dec(FCount);
  455. ListItem := InternalItems[Index];
  456. Deref(ListItem);
  457. System.Move(InternalItems[Index+1]^, ListItem^, (FCount - Index) * FItemSize);
  458. // Shrink the list if appropriate
  459. if (FCapacity > 256) and (FCount < FCapacity shr 2) then
  460. begin
  461. FCapacity := FCapacity shr 1;
  462. ReallocMem(FList, (FCapacity+1) * FItemSize);
  463. end;
  464. { Keep the ending of the list filled with zeros, don't leave garbage data
  465. there. Otherwise, we could accidentally have there a copy of some item
  466. on the list, and accidentally Deref it too soon.
  467. See http://bugs.freepascal.org/view.php?id=20005. }
  468. FillChar(InternalItems[FCount]^, (FCapacity+1-FCount) * FItemSize, #0);
  469. end;
  470. procedure TFPSList.Extract(Item: Pointer; ResultPtr: Pointer);
  471. var
  472. i : Integer;
  473. ListItemPtr : Pointer;
  474. begin
  475. i := IndexOf(Item);
  476. if i >= 0 then
  477. begin
  478. ListItemPtr := InternalItems[i];
  479. System.Move(ListItemPtr^, ResultPtr^, FItemSize);
  480. { fill with zeros, to avoid freeing/decreasing reference on following Delete }
  481. System.FillByte(ListItemPtr^, FItemSize, 0);
  482. Delete(i);
  483. end else
  484. System.FillByte(ResultPtr^, FItemSize, 0);
  485. end;
  486. class procedure TFPSList.Error(const Msg: string; Data: PtrInt);
  487. begin
  488. raise EListError.CreateFmt(Msg,[Data]) at get_caller_addr(get_frame);
  489. end;
  490. procedure TFPSList.Exchange(Index1, Index2: Integer);
  491. begin
  492. if ((Index1 >= FCount) or (Index1 < 0)) then
  493. Error(SListIndexError, Index1);
  494. if ((Index2 >= FCount) or (Index2 < 0)) then
  495. Error(SListIndexError, Index2);
  496. InternalExchange(Index1, Index2);
  497. end;
  498. procedure TFPSList.InternalExchange(Index1, Index2: Integer);
  499. begin
  500. System.Move(InternalItems[Index1]^, InternalItems[FCapacity]^, FItemSize);
  501. System.Move(InternalItems[Index2]^, InternalItems[Index1]^, FItemSize);
  502. System.Move(InternalItems[FCapacity]^, InternalItems[Index2]^, FItemSize);
  503. end;
  504. function TFPSList.Expand: TFPSList;
  505. var
  506. IncSize : Longint;
  507. begin
  508. if FCount < FCapacity then exit;
  509. IncSize := 4;
  510. if FCapacity > 3 then IncSize := IncSize + 4;
  511. if FCapacity > 8 then IncSize := IncSize + 8;
  512. if FCapacity > 127 then Inc(IncSize, FCapacity shr 2);
  513. SetCapacity(FCapacity + IncSize);
  514. Result := Self;
  515. end;
  516. function TFPSList.GetFirst: Pointer;
  517. begin
  518. If FCount = 0 then
  519. Result := Nil
  520. else
  521. Result := InternalItems[0];
  522. end;
  523. procedure TFPSList.SetFirst(const Value: Pointer);
  524. begin
  525. Put(0, Value);
  526. end;
  527. function TFPSList.IndexOf(Item: Pointer): Integer;
  528. var
  529. ListItem: Pointer;
  530. begin
  531. Result := 0;
  532. ListItem := First;
  533. while (Result < FCount) and (CompareByte(ListItem^, Item^, FItemSize) <> 0) do
  534. begin
  535. Inc(Result);
  536. ListItem := PByte(ListItem)+FItemSize;
  537. end;
  538. if Result = FCount then Result := -1;
  539. end;
  540. function TFPSList.Insert(Index: Integer): Pointer;
  541. begin
  542. if (Index < 0) or (Index > FCount) then
  543. Error(SListIndexError, Index);
  544. if FCount = FCapacity then Self.Expand;
  545. Result := InternalItems[Index];
  546. if Index<FCount then
  547. begin
  548. System.Move(Result^, (Result+FItemSize)^, (FCount - Index) * FItemSize);
  549. { clear for compiler assisted types }
  550. System.FillByte(Result^, FItemSize, 0);
  551. end;
  552. Inc(FCount);
  553. end;
  554. procedure TFPSList.Insert(Index: Integer; Item: Pointer);
  555. begin
  556. CopyItem(Item, Insert(Index));
  557. end;
  558. function TFPSList.GetLast: Pointer;
  559. begin
  560. if FCount = 0 then
  561. Result := nil
  562. else
  563. Result := InternalItems[FCount - 1];
  564. end;
  565. procedure TFPSList.SetLast(const Value: Pointer);
  566. begin
  567. Put(FCount - 1, Value);
  568. end;
  569. procedure TFPSList.Move(CurIndex, NewIndex: Integer);
  570. var
  571. CurItem, NewItem, TmpItem, Src, Dest: Pointer;
  572. MoveCount: Integer;
  573. begin
  574. if (CurIndex < 0) or (CurIndex >= Count) then
  575. Error(SListIndexError, CurIndex);
  576. if (NewIndex < 0) or (NewIndex >= Count) then
  577. Error(SListIndexError, NewIndex);
  578. if CurIndex = NewIndex then
  579. exit;
  580. CurItem := InternalItems[CurIndex];
  581. NewItem := InternalItems[NewIndex];
  582. TmpItem := InternalItems[FCapacity];
  583. System.Move(CurItem^, TmpItem^, FItemSize);
  584. if NewIndex > CurIndex then
  585. begin
  586. Src := InternalItems[CurIndex+1];
  587. Dest := CurItem;
  588. MoveCount := NewIndex - CurIndex;
  589. end else begin
  590. Src := NewItem;
  591. Dest := InternalItems[NewIndex+1];
  592. MoveCount := CurIndex - NewIndex;
  593. end;
  594. System.Move(Src^, Dest^, MoveCount * FItemSize);
  595. System.Move(TmpItem^, NewItem^, FItemSize);
  596. end;
  597. function TFPSList.Remove(Item: Pointer): Integer;
  598. begin
  599. Result := IndexOf(Item);
  600. if Result <> -1 then
  601. Delete(Result);
  602. end;
  603. procedure TFPSList.Pack;
  604. var
  605. NewCount,
  606. i : integer;
  607. pdest,
  608. psrc : Pointer;
  609. begin
  610. NewCount:=0;
  611. psrc:=First;
  612. pdest:=psrc;
  613. For I:=0 To FCount-1 Do
  614. begin
  615. if assigned(pointer(psrc^)) then
  616. begin
  617. System.Move(psrc^, pdest^, FItemSize);
  618. inc(pdest);
  619. inc(NewCount);
  620. end;
  621. inc(psrc);
  622. end;
  623. FCount:=NewCount;
  624. end;
  625. // Needed by Sort method.
  626. procedure TFPSList.QuickSort(L, R: Integer; Compare: TFPSListCompareFunc);
  627. var
  628. I, J, P: Integer;
  629. PivotItem: Pointer;
  630. begin
  631. repeat
  632. I := L;
  633. J := R;
  634. P := (L + R) div 2;
  635. repeat
  636. PivotItem := InternalItems[P];
  637. while Compare(PivotItem, InternalItems[I]) > 0 do
  638. Inc(I);
  639. while Compare(PivotItem, InternalItems[J]) < 0 do
  640. Dec(J);
  641. if I <= J then
  642. begin
  643. InternalExchange(I, J);
  644. if P = I then
  645. P := J
  646. else if P = J then
  647. P := I;
  648. Inc(I);
  649. Dec(J);
  650. end;
  651. until I > J;
  652. if L < J then
  653. QuickSort(L, J, Compare);
  654. L := I;
  655. until I >= R;
  656. end;
  657. procedure TFPSList.Sort(Compare: TFPSListCompareFunc);
  658. begin
  659. if not Assigned(FList) or (FCount < 2) then exit;
  660. QuickSort(0, FCount-1, Compare);
  661. end;
  662. procedure TFPSList.Assign(Obj: TFPSList);
  663. var
  664. i: Integer;
  665. begin
  666. if Obj.ItemSize <> FItemSize then
  667. Error(SListItemSizeError, 0);
  668. Clear;
  669. for I := 0 to Obj.Count - 1 do
  670. Add(Obj[i]);
  671. end;
  672. {****************************************************************************}
  673. {* TFPGListEnumerator *}
  674. {****************************************************************************}
  675. function TFPGListEnumerator.GetCurrent: T;
  676. begin
  677. Result := T(FList.Items[FPosition]^);
  678. end;
  679. constructor TFPGListEnumerator.Create(AList: TFPSList);
  680. begin
  681. inherited Create;
  682. FList := AList;
  683. FPosition := -1;
  684. end;
  685. function TFPGListEnumerator.MoveNext: Boolean;
  686. begin
  687. inc(FPosition);
  688. Result := FPosition < FList.Count;
  689. end;
  690. {****************************************************************************}
  691. {* TFPGList *}
  692. {****************************************************************************}
  693. constructor TFPGList.Create;
  694. begin
  695. inherited Create(sizeof(T));
  696. end;
  697. procedure TFPGList.CopyItem(Src, Dest: Pointer);
  698. begin
  699. T(Dest^) := T(Src^);
  700. end;
  701. procedure TFPGList.Deref(Item: Pointer);
  702. begin
  703. Finalize(T(Item^));
  704. end;
  705. function TFPGList.Get(Index: Integer): T;
  706. begin
  707. Result := T(inherited Get(Index)^);
  708. end;
  709. function TFPGList.GetList: PTypeList;
  710. begin
  711. Result := PTypeList(FList);
  712. end;
  713. function TFPGList.ItemPtrCompare(Item1, Item2: Pointer): Integer;
  714. begin
  715. Result := FOnCompare(T(Item1^), T(Item2^));
  716. end;
  717. procedure TFPGList.Put(Index: Integer; const Item: T);
  718. begin
  719. inherited Put(Index, @Item);
  720. end;
  721. function TFPGList.Add(const Item: T): Integer;
  722. begin
  723. Result := inherited Add(@Item);
  724. end;
  725. function TFPGList.Extract(const Item: T): T;
  726. begin
  727. inherited Extract(@Item, @Result);
  728. end;
  729. function TFPGList.GetFirst: T;
  730. begin
  731. Result := T(inherited GetFirst^);
  732. end;
  733. procedure TFPGList.SetFirst(const Value: T);
  734. begin
  735. inherited SetFirst(@Value);
  736. end;
  737. function TFPGList.GetEnumerator: TFPGListEnumeratorSpec;
  738. begin
  739. Result := TFPGListEnumeratorSpec.Create(Self);
  740. end;
  741. function TFPGList.IndexOf(const Item: T): Integer;
  742. begin
  743. Result := 0;
  744. {$info TODO: fix inlining to work! InternalItems[Result]^}
  745. while (Result < FCount) and (PT(FList)[Result] <> Item) do
  746. Inc(Result);
  747. if Result = FCount then
  748. Result := -1;
  749. end;
  750. procedure TFPGList.Insert(Index: Integer; const Item: T);
  751. begin
  752. T(inherited Insert(Index)^) := Item;
  753. end;
  754. function TFPGList.GetLast: T;
  755. begin
  756. Result := T(inherited GetLast^);
  757. end;
  758. procedure TFPGList.SetLast(const Value: T);
  759. begin
  760. inherited SetLast(@Value);
  761. end;
  762. {$ifndef VER2_4}
  763. procedure TFPGList.Assign(Source: TFPGList);
  764. var
  765. i: Integer;
  766. begin
  767. Clear;
  768. for I := 0 to Source.Count - 1 do
  769. Add(Source[i]);
  770. end;
  771. {$endif VER2_4}
  772. function TFPGList.Remove(const Item: T): Integer;
  773. begin
  774. Result := IndexOf(Item);
  775. if Result >= 0 then
  776. Delete(Result);
  777. end;
  778. procedure TFPGList.Sort(Compare: TCompareFunc);
  779. begin
  780. FOnCompare := Compare;
  781. inherited Sort(@ItemPtrCompare);
  782. end;
  783. {****************************************************************************}
  784. {* TFPGObjectList *}
  785. {****************************************************************************}
  786. constructor TFPGObjectList.Create(FreeObjects: Boolean);
  787. begin
  788. inherited Create;
  789. FFreeObjects := FreeObjects;
  790. end;
  791. procedure TFPGObjectList.CopyItem(Src, Dest: Pointer);
  792. begin
  793. T(Dest^) := T(Src^);
  794. end;
  795. procedure TFPGObjectList.Deref(Item: Pointer);
  796. begin
  797. if FFreeObjects then
  798. T(Item^).Free;
  799. end;
  800. function TFPGObjectList.Get(Index: Integer): T;
  801. begin
  802. Result := T(inherited Get(Index)^);
  803. end;
  804. function TFPGObjectList.GetList: PTypeList;
  805. begin
  806. Result := PTypeList(FList);
  807. end;
  808. function TFPGObjectList.ItemPtrCompare(Item1, Item2: Pointer): Integer;
  809. begin
  810. Result := FOnCompare(T(Item1^), T(Item2^));
  811. end;
  812. procedure TFPGObjectList.Put(Index: Integer; const Item: T);
  813. begin
  814. inherited Put(Index, @Item);
  815. end;
  816. function TFPGObjectList.Add(const Item: T): Integer;
  817. begin
  818. Result := inherited Add(@Item);
  819. end;
  820. function TFPGObjectList.Extract(const Item: T): T;
  821. begin
  822. inherited Extract(@Item, @Result);
  823. end;
  824. function TFPGObjectList.GetFirst: T;
  825. begin
  826. Result := T(inherited GetFirst^);
  827. end;
  828. procedure TFPGObjectList.SetFirst(const Value: T);
  829. begin
  830. inherited SetFirst(@Value);
  831. end;
  832. function TFPGObjectList.GetEnumerator: TFPGListEnumeratorSpec;
  833. begin
  834. Result := TFPGListEnumeratorSpec.Create(Self);
  835. end;
  836. function TFPGObjectList.IndexOf(const Item: T): Integer;
  837. begin
  838. Result := 0;
  839. {$info TODO: fix inlining to work! InternalItems[Result]^}
  840. while (Result < FCount) and (PT(FList)[Result] <> Item) do
  841. Inc(Result);
  842. if Result = FCount then
  843. Result := -1;
  844. end;
  845. procedure TFPGObjectList.Insert(Index: Integer; const Item: T);
  846. begin
  847. T(inherited Insert(Index)^) := Item;
  848. end;
  849. function TFPGObjectList.GetLast: T;
  850. begin
  851. Result := T(inherited GetLast^);
  852. end;
  853. procedure TFPGObjectList.SetLast(const Value: T);
  854. begin
  855. inherited SetLast(@Value);
  856. end;
  857. {$ifndef VER2_4}
  858. procedure TFPGObjectList.Assign(Source: TFPGObjectList);
  859. var
  860. i: Integer;
  861. begin
  862. Clear;
  863. for I := 0 to Source.Count - 1 do
  864. Add(Source[i]);
  865. end;
  866. {$endif VER2_4}
  867. function TFPGObjectList.Remove(const Item: T): Integer;
  868. begin
  869. Result := IndexOf(Item);
  870. if Result >= 0 then
  871. Delete(Result);
  872. end;
  873. procedure TFPGObjectList.Sort(Compare: TCompareFunc);
  874. begin
  875. FOnCompare := Compare;
  876. inherited Sort(@ItemPtrCompare);
  877. end;
  878. {****************************************************************************}
  879. {* TFPGInterfacedObjectList *}
  880. {****************************************************************************}
  881. constructor TFPGInterfacedObjectList.Create;
  882. begin
  883. inherited Create;
  884. end;
  885. procedure TFPGInterfacedObjectList.CopyItem(Src, Dest: Pointer);
  886. begin
  887. if Assigned(Pointer(Dest^)) then
  888. T(Dest^)._Release;
  889. T(Dest^) := T(Src^);
  890. if Assigned(Pointer(Dest^)) then
  891. T(Dest^)._AddRef;
  892. end;
  893. procedure TFPGInterfacedObjectList.Deref(Item: Pointer);
  894. begin
  895. if Assigned(Pointer(Item^)) then
  896. T(Item^)._Release;
  897. end;
  898. function TFPGInterfacedObjectList.Get(Index: Integer): T;
  899. begin
  900. Result := T(inherited Get(Index)^);
  901. end;
  902. function TFPGInterfacedObjectList.GetList: PTypeList;
  903. begin
  904. Result := PTypeList(FList);
  905. end;
  906. function TFPGInterfacedObjectList.ItemPtrCompare(Item1, Item2: Pointer): Integer;
  907. begin
  908. Result := FOnCompare(T(Item1^), T(Item2^));
  909. end;
  910. procedure TFPGInterfacedObjectList.Put(Index: Integer; const Item: T);
  911. begin
  912. inherited Put(Index, @Item);
  913. end;
  914. function TFPGInterfacedObjectList.Add(const Item: T): Integer;
  915. begin
  916. Result := inherited Add(@Item);
  917. end;
  918. function TFPGInterfacedObjectList.Extract(const Item: T): T;
  919. begin
  920. inherited Extract(@Item, @Result);
  921. end;
  922. function TFPGInterfacedObjectList.GetFirst: T;
  923. begin
  924. Result := T(inherited GetFirst^);
  925. end;
  926. procedure TFPGInterfacedObjectList.SetFirst(const Value: T);
  927. begin
  928. inherited SetFirst(@Value);
  929. end;
  930. function TFPGInterfacedObjectList.GetEnumerator: TFPGListEnumeratorSpec;
  931. begin
  932. Result := TFPGListEnumeratorSpec.Create(Self);
  933. end;
  934. function TFPGInterfacedObjectList.IndexOf(const Item: T): Integer;
  935. begin
  936. Result := 0;
  937. {$info TODO: fix inlining to work! InternalItems[Result]^}
  938. while (Result < FCount) and (PT(FList)[Result] <> Item) do
  939. Inc(Result);
  940. if Result = FCount then
  941. Result := -1;
  942. end;
  943. procedure TFPGInterfacedObjectList.Insert(Index: Integer; const Item: T);
  944. begin
  945. T(inherited Insert(Index)^) := Item;
  946. end;
  947. function TFPGInterfacedObjectList.GetLast: T;
  948. begin
  949. Result := T(inherited GetLast^);
  950. end;
  951. procedure TFPGInterfacedObjectList.SetLast(const Value: T);
  952. begin
  953. inherited SetLast(@Value);
  954. end;
  955. {$ifndef VER2_4}
  956. procedure TFPGInterfacedObjectList.Assign(Source: TFPGInterfacedObjectList);
  957. var
  958. i: Integer;
  959. begin
  960. Clear;
  961. for I := 0 to Source.Count - 1 do
  962. Add(Source[i]);
  963. end;
  964. {$endif VER2_4}
  965. function TFPGInterfacedObjectList.Remove(const Item: T): Integer;
  966. begin
  967. Result := IndexOf(Item);
  968. if Result >= 0 then
  969. Delete(Result);
  970. end;
  971. procedure TFPGInterfacedObjectList.Sort(Compare: TCompareFunc);
  972. begin
  973. FOnCompare := Compare;
  974. inherited Sort(@ItemPtrCompare);
  975. end;
  976. {****************************************************************************
  977. TFPSMap
  978. ****************************************************************************}
  979. constructor TFPSMap.Create(AKeySize: Integer; ADataSize: integer);
  980. begin
  981. inherited Create(AKeySize+ADataSize);
  982. FKeySize := AKeySize;
  983. FDataSize := ADataSize;
  984. InitOnPtrCompare;
  985. end;
  986. procedure TFPSMap.CopyKey(Src, Dest: Pointer);
  987. begin
  988. System.Move(Src^, Dest^, FKeySize);
  989. end;
  990. procedure TFPSMap.CopyData(Src, Dest: Pointer);
  991. begin
  992. System.Move(Src^, Dest^, FDataSize);
  993. end;
  994. function TFPSMap.GetKey(Index: Integer): Pointer;
  995. begin
  996. Result := Items[Index];
  997. end;
  998. function TFPSMap.GetData(Index: Integer): Pointer;
  999. begin
  1000. Result := PByte(Items[Index])+FKeySize;
  1001. end;
  1002. function TFPSMap.GetKeyData(AKey: Pointer): Pointer;
  1003. var
  1004. I: Integer;
  1005. begin
  1006. I := IndexOf(AKey);
  1007. if I >= 0 then
  1008. Result := InternalItems[I]+FKeySize
  1009. else
  1010. Error(SMapKeyError, PtrUInt(AKey));
  1011. end;
  1012. function TFPSMap.BinaryCompareKey(Key1, Key2: Pointer): Integer;
  1013. begin
  1014. Result := CompareByte(Key1^, Key2^, FKeySize);
  1015. end;
  1016. function TFPSMap.BinaryCompareData(Data1, Data2: Pointer): Integer;
  1017. begin
  1018. Result := CompareByte(Data1^, Data1^, FDataSize);
  1019. end;
  1020. procedure TFPSMap.SetOnKeyPtrCompare(Proc: TFPSListCompareFunc);
  1021. begin
  1022. if Proc <> nil then
  1023. FOnKeyPtrCompare := Proc
  1024. else
  1025. FOnKeyPtrCompare := @BinaryCompareKey;
  1026. end;
  1027. procedure TFPSMap.SetOnDataPtrCompare(Proc: TFPSListCompareFunc);
  1028. begin
  1029. if Proc <> nil then
  1030. FOnDataPtrCompare := Proc
  1031. else
  1032. FOnDataPtrCompare := @BinaryCompareData;
  1033. end;
  1034. procedure TFPSMap.InitOnPtrCompare;
  1035. begin
  1036. SetOnKeyPtrCompare(nil);
  1037. SetOnDataPtrCompare(nil);
  1038. end;
  1039. procedure TFPSMap.PutKey(Index: Integer; AKey: Pointer);
  1040. begin
  1041. if FSorted then
  1042. Error(SSortedListError, 0);
  1043. CopyKey(AKey, Items[Index]);
  1044. end;
  1045. procedure TFPSMap.PutData(Index: Integer; AData: Pointer);
  1046. begin
  1047. CopyData(AData, PByte(Items[Index])+FKeySize);
  1048. end;
  1049. procedure TFPSMap.PutKeyData(AKey: Pointer; NewData: Pointer);
  1050. var
  1051. I: Integer;
  1052. begin
  1053. I := IndexOf(AKey);
  1054. if I >= 0 then
  1055. Data[I] := NewData
  1056. else
  1057. Add(AKey, NewData);
  1058. end;
  1059. procedure TFPSMap.SetSorted(Value: Boolean);
  1060. begin
  1061. if Value = FSorted then exit;
  1062. FSorted := Value;
  1063. if Value then Sort;
  1064. end;
  1065. function TFPSMap.Add(AKey: Pointer): Integer;
  1066. begin
  1067. if Sorted then
  1068. begin
  1069. if Find(AKey, Result) then
  1070. case Duplicates of
  1071. dupIgnore: exit;
  1072. dupError: Error(SDuplicateItem, 0)
  1073. end;
  1074. end else
  1075. Result := Count;
  1076. CopyKey(AKey, inherited Insert(Result));
  1077. end;
  1078. function TFPSMap.Add(AKey, AData: Pointer): Integer;
  1079. begin
  1080. Result := Add(AKey);
  1081. Data[Result] := AData;
  1082. end;
  1083. function TFPSMap.Find(AKey: Pointer; out Index: Integer): Boolean;
  1084. { Searches for the first item <= Key, returns True if exact match,
  1085. sets index to the index f the found string. }
  1086. var
  1087. I,L,R,Dir: Integer;
  1088. begin
  1089. Result := false;
  1090. // Use binary search.
  1091. L := 0;
  1092. R := FCount-1;
  1093. while L<=R do
  1094. begin
  1095. I := (L+R) div 2;
  1096. Dir := FOnKeyPtrCompare(Items[I], AKey);
  1097. if Dir < 0 then
  1098. L := I+1
  1099. else begin
  1100. R := I-1;
  1101. if Dir = 0 then
  1102. begin
  1103. Result := true;
  1104. if Duplicates <> dupAccept then
  1105. L := I;
  1106. end;
  1107. end;
  1108. end;
  1109. Index := L;
  1110. end;
  1111. function TFPSMap.LinearIndexOf(AKey: Pointer): Integer;
  1112. var
  1113. ListItem: Pointer;
  1114. begin
  1115. Result := 0;
  1116. ListItem := First;
  1117. while (Result < FCount) and (FOnKeyPtrCompare(ListItem, AKey) <> 0) do
  1118. begin
  1119. Inc(Result);
  1120. ListItem := PByte(ListItem)+FItemSize;
  1121. end;
  1122. if Result = FCount then Result := -1;
  1123. end;
  1124. function TFPSMap.IndexOf(AKey: Pointer): Integer;
  1125. begin
  1126. if Sorted then
  1127. begin
  1128. if not Find(AKey, Result) then
  1129. Result := -1;
  1130. end else
  1131. Result := LinearIndexOf(AKey);
  1132. end;
  1133. function TFPSMap.IndexOfData(AData: Pointer): Integer;
  1134. var
  1135. ListItem: Pointer;
  1136. begin
  1137. Result := 0;
  1138. ListItem := First+FKeySize;
  1139. while (Result < FCount) and (FOnDataPtrCompare(ListItem, AData) <> 0) do
  1140. begin
  1141. Inc(Result);
  1142. ListItem := PByte(ListItem)+FItemSize;
  1143. end;
  1144. if Result = FCount then Result := -1;
  1145. end;
  1146. function TFPSMap.Insert(Index: Integer): Pointer;
  1147. begin
  1148. if FSorted then
  1149. Error(SSortedListError, 0);
  1150. Result := inherited Insert(Index);
  1151. end;
  1152. procedure TFPSMap.Insert(Index: Integer; out AKey, AData: Pointer);
  1153. begin
  1154. AKey := Insert(Index);
  1155. AData := PByte(AKey) + FKeySize;
  1156. end;
  1157. procedure TFPSMap.InsertKey(Index: Integer; AKey: Pointer);
  1158. begin
  1159. CopyKey(AKey, Insert(Index));
  1160. end;
  1161. procedure TFPSMap.InsertKeyData(Index: Integer; AKey, AData: Pointer);
  1162. var
  1163. ListItem: Pointer;
  1164. begin
  1165. ListItem := Insert(Index);
  1166. CopyKey(AKey, ListItem);
  1167. CopyData(AData, PByte(ListItem)+FKeySize);
  1168. end;
  1169. function TFPSMap.Remove(AKey: Pointer): Integer;
  1170. begin
  1171. Result := IndexOf(AKey);
  1172. if Result >= 0 then
  1173. Delete(Result);
  1174. end;
  1175. procedure TFPSMap.Sort;
  1176. begin
  1177. inherited Sort(FOnKeyPtrCompare);
  1178. end;
  1179. {****************************************************************************
  1180. TFPGMap
  1181. ****************************************************************************}
  1182. constructor TFPGMap.Create;
  1183. begin
  1184. inherited Create(SizeOf(TKey), SizeOf(TData));
  1185. end;
  1186. procedure TFPGMap.CopyItem(Src, Dest: Pointer);
  1187. begin
  1188. CopyKey(Src, Dest);
  1189. CopyData(PByte(Src)+KeySize, PByte(Dest)+KeySize);
  1190. end;
  1191. procedure TFPGMap.CopyKey(Src, Dest: Pointer);
  1192. begin
  1193. TKey(Dest^) := TKey(Src^);
  1194. end;
  1195. procedure TFPGMap.CopyData(Src, Dest: Pointer);
  1196. begin
  1197. TData(Dest^) := TData(Src^);
  1198. end;
  1199. procedure TFPGMap.Deref(Item: Pointer);
  1200. begin
  1201. Finalize(TKey(Item^));
  1202. Finalize(TData(Pointer(PByte(Item)+KeySize)^));
  1203. end;
  1204. function TFPGMap.GetKey(Index: Integer): TKey;
  1205. begin
  1206. Result := TKey(inherited GetKey(Index)^);
  1207. end;
  1208. function TFPGMap.GetData(Index: Integer): TData;
  1209. begin
  1210. Result := TData(inherited GetData(Index)^);
  1211. end;
  1212. function TFPGMap.GetKeyData(const AKey: TKey): TData;
  1213. begin
  1214. Result := TData(inherited GetKeyData(@AKey)^);
  1215. end;
  1216. function TFPGMap.KeyCompare(Key1, Key2: Pointer): Integer;
  1217. begin
  1218. if PKey(Key1)^ < PKey(Key2)^ then
  1219. Result := -1
  1220. else if PKey(Key1)^ > PKey(Key2)^ then
  1221. Result := 1
  1222. else
  1223. Result := 0;
  1224. end;
  1225. {function TFPGMap.DataCompare(Data1, Data2: Pointer): Integer;
  1226. begin
  1227. if PData(Data1)^ < PData(Data2)^ then
  1228. Result := -1
  1229. else if PData(Data1)^ > PData(Data2)^ then
  1230. Result := 1
  1231. else
  1232. Result := 0;
  1233. end;}
  1234. function TFPGMap.KeyCustomCompare(Key1, Key2: Pointer): Integer;
  1235. begin
  1236. Result := FOnKeyCompare(TKey(Key1^), TKey(Key2^));
  1237. end;
  1238. function TFPGMap.DataCustomCompare(Data1, Data2: Pointer): Integer;
  1239. begin
  1240. Result := FOnDataCompare(TData(Data1^), TData(Data2^));
  1241. end;
  1242. procedure TFPGMap.SetOnKeyCompare(NewCompare: TKeyCompareFunc);
  1243. begin
  1244. FOnKeyCompare := NewCompare;
  1245. if NewCompare <> nil then
  1246. OnKeyPtrCompare := @KeyCustomCompare
  1247. else
  1248. OnKeyPtrCompare := @KeyCompare;
  1249. end;
  1250. procedure TFPGMap.SetOnDataCompare(NewCompare: TDataCompareFunc);
  1251. begin
  1252. FOnDataCompare := NewCompare;
  1253. if NewCompare <> nil then
  1254. OnDataPtrCompare := @DataCustomCompare
  1255. else
  1256. OnDataPtrCompare := nil;
  1257. end;
  1258. procedure TFPGMap.InitOnPtrCompare;
  1259. begin
  1260. SetOnKeyCompare(nil);
  1261. SetOnDataCompare(nil);
  1262. end;
  1263. procedure TFPGMap.PutKey(Index: Integer; const NewKey: TKey);
  1264. begin
  1265. inherited PutKey(Index, @NewKey);
  1266. end;
  1267. procedure TFPGMap.PutData(Index: Integer; const NewData: TData);
  1268. begin
  1269. inherited PutData(Index, @NewData);
  1270. end;
  1271. procedure TFPGMap.PutKeyData(const AKey: TKey; const NewData: TData);
  1272. begin
  1273. inherited PutKeyData(@AKey, @NewData);
  1274. end;
  1275. function TFPGMap.Add(const AKey: TKey): Integer;
  1276. begin
  1277. Result := inherited Add(@AKey);
  1278. end;
  1279. function TFPGMap.Add(const AKey: TKey; const AData: TData): Integer;
  1280. begin
  1281. Result := inherited Add(@AKey, @AData);
  1282. end;
  1283. function TFPGMap.Find(const AKey: TKey; out Index: Integer): Boolean;
  1284. begin
  1285. Result := inherited Find(@AKey, Index);
  1286. end;
  1287. function TFPGMap.IndexOf(const AKey: TKey): Integer;
  1288. begin
  1289. Result := inherited IndexOf(@AKey);
  1290. end;
  1291. function TFPGMap.IndexOfData(const AData: TData): Integer;
  1292. begin
  1293. { TODO: loop ? }
  1294. Result := inherited IndexOfData(@AData);
  1295. end;
  1296. procedure TFPGMap.InsertKey(Index: Integer; const AKey: TKey);
  1297. begin
  1298. inherited InsertKey(Index, @AKey);
  1299. end;
  1300. procedure TFPGMap.InsertKeyData(Index: Integer; const AKey: TKey; const AData: TData);
  1301. begin
  1302. inherited InsertKeyData(Index, @AKey, @AData);
  1303. end;
  1304. function TFPGMap.Remove(const AKey: TKey): Integer;
  1305. begin
  1306. Result := inherited Remove(@AKey);
  1307. end;
  1308. {****************************************************************************
  1309. TFPGMapInterfacedObjectData
  1310. ****************************************************************************}
  1311. constructor TFPGMapInterfacedObjectData.Create;
  1312. begin
  1313. inherited Create(SizeOf(TKey), SizeOf(TData));
  1314. end;
  1315. procedure TFPGMapInterfacedObjectData.CopyItem(Src, Dest: Pointer);
  1316. begin
  1317. CopyKey(Src, Dest);
  1318. CopyData(PByte(Src)+KeySize, PByte(Dest)+KeySize);
  1319. end;
  1320. procedure TFPGMapInterfacedObjectData.CopyKey(Src, Dest: Pointer);
  1321. begin
  1322. TKey(Dest^) := TKey(Src^);
  1323. end;
  1324. procedure TFPGMapInterfacedObjectData.CopyData(Src, Dest: Pointer);
  1325. begin
  1326. if Assigned(Pointer(Dest^)) then
  1327. TData(Dest^)._Release;
  1328. TData(Dest^) := TData(Src^);
  1329. if Assigned(Pointer(Dest^)) then
  1330. TData(Dest^)._AddRef;
  1331. end;
  1332. procedure TFPGMapInterfacedObjectData.Deref(Item: Pointer);
  1333. begin
  1334. Finalize(TKey(Item^));
  1335. if Assigned(PPointer(PByte(Item)+KeySize)^) then
  1336. TData(Pointer(PByte(Item)+KeySize)^)._Release;
  1337. end;
  1338. function TFPGMapInterfacedObjectData.GetKey(Index: Integer): TKey;
  1339. begin
  1340. Result := TKey(inherited GetKey(Index)^);
  1341. end;
  1342. function TFPGMapInterfacedObjectData.GetData(Index: Integer): TData;
  1343. begin
  1344. Result := TData(inherited GetData(Index)^);
  1345. end;
  1346. function TFPGMapInterfacedObjectData.GetKeyData(const AKey: TKey): TData;
  1347. begin
  1348. Result := TData(inherited GetKeyData(@AKey)^);
  1349. end;
  1350. function TFPGMapInterfacedObjectData.KeyCompare(Key1, Key2: Pointer): Integer;
  1351. begin
  1352. if PKey(Key1)^ < PKey(Key2)^ then
  1353. Result := -1
  1354. else if PKey(Key1)^ > PKey(Key2)^ then
  1355. Result := 1
  1356. else
  1357. Result := 0;
  1358. end;
  1359. {function TFPGMapInterfacedObjectData.DataCompare(Data1, Data2: Pointer): Integer;
  1360. begin
  1361. if PData(Data1)^ < PData(Data2)^ then
  1362. Result := -1
  1363. else if PData(Data1)^ > PData(Data2)^ then
  1364. Result := 1
  1365. else
  1366. Result := 0;
  1367. end;}
  1368. function TFPGMapInterfacedObjectData.KeyCustomCompare(Key1, Key2: Pointer): Integer;
  1369. begin
  1370. Result := FOnKeyCompare(TKey(Key1^), TKey(Key2^));
  1371. end;
  1372. function TFPGMapInterfacedObjectData.DataCustomCompare(Data1, Data2: Pointer): Integer;
  1373. begin
  1374. Result := FOnDataCompare(TData(Data1^), TData(Data2^));
  1375. end;
  1376. procedure TFPGMapInterfacedObjectData.SetOnKeyCompare(NewCompare: TKeyCompareFunc);
  1377. begin
  1378. FOnKeyCompare := NewCompare;
  1379. if NewCompare <> nil then
  1380. OnKeyPtrCompare := @KeyCustomCompare
  1381. else
  1382. OnKeyPtrCompare := @KeyCompare;
  1383. end;
  1384. procedure TFPGMapInterfacedObjectData.SetOnDataCompare(NewCompare: TDataCompareFunc);
  1385. begin
  1386. FOnDataCompare := NewCompare;
  1387. if NewCompare <> nil then
  1388. OnDataPtrCompare := @DataCustomCompare
  1389. else
  1390. OnDataPtrCompare := nil;
  1391. end;
  1392. procedure TFPGMapInterfacedObjectData.InitOnPtrCompare;
  1393. begin
  1394. SetOnKeyCompare(nil);
  1395. SetOnDataCompare(nil);
  1396. end;
  1397. procedure TFPGMapInterfacedObjectData.PutKey(Index: Integer; const NewKey: TKey);
  1398. begin
  1399. inherited PutKey(Index, @NewKey);
  1400. end;
  1401. procedure TFPGMapInterfacedObjectData.PutData(Index: Integer; const NewData: TData);
  1402. begin
  1403. inherited PutData(Index, @NewData);
  1404. end;
  1405. procedure TFPGMapInterfacedObjectData.PutKeyData(const AKey: TKey; const NewData: TData);
  1406. begin
  1407. inherited PutKeyData(@AKey, @NewData);
  1408. end;
  1409. function TFPGMapInterfacedObjectData.Add(const AKey: TKey): Integer;
  1410. begin
  1411. Result := inherited Add(@AKey);
  1412. end;
  1413. function TFPGMapInterfacedObjectData.Add(const AKey: TKey; const AData: TData): Integer;
  1414. begin
  1415. Result := inherited Add(@AKey, @AData);
  1416. end;
  1417. function TFPGMapInterfacedObjectData.Find(const AKey: TKey; out Index: Integer): Boolean;
  1418. begin
  1419. Result := inherited Find(@AKey, Index);
  1420. end;
  1421. function TFPGMapInterfacedObjectData.IndexOf(const AKey: TKey): Integer;
  1422. begin
  1423. Result := inherited IndexOf(@AKey);
  1424. end;
  1425. function TFPGMapInterfacedObjectData.IndexOfData(const AData: TData): Integer;
  1426. begin
  1427. { TODO: loop ? }
  1428. Result := inherited IndexOfData(@AData);
  1429. end;
  1430. procedure TFPGMapInterfacedObjectData.InsertKey(Index: Integer; const AKey: TKey);
  1431. begin
  1432. inherited InsertKey(Index, @AKey);
  1433. end;
  1434. procedure TFPGMapInterfacedObjectData.InsertKeyData(Index: Integer; const AKey: TKey; const AData: TData);
  1435. begin
  1436. inherited InsertKeyData(Index, @AKey, @AData);
  1437. end;
  1438. function TFPGMapInterfacedObjectData.Remove(const AKey: TKey): Integer;
  1439. begin
  1440. Result := inherited Remove(@AKey);
  1441. end;
  1442. end.