fgl.pp 47 KB

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