fgl.pp 44 KB

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