fgl.pp 47 KB

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