fgl.pp 47 KB

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