fgl.pp 46 KB

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