fgl.pp 47 KB

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