generics.collections.pas 49 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032
  1. unit Generics.Collections;
  2. {$Mode Delphi}
  3. {$COperators On}
  4. interface
  5. uses
  6. Classes, SysUtils, rtlconsts, Types,
  7. {$IFDEF Pas2js}JS,{$ENDIF}
  8. Generics.Strings, Generics.Defaults;
  9. type
  10. TCollectionNotification = (cnAdded, cnRemoved, cnExtracted);
  11. TCollectionNotifyEvent<T> = procedure(ASender: TObject; const AItem: T;
  12. AAction: TCollectionNotification) of object;
  13. { TBinarySearchResult }
  14. TBinarySearchResult = record
  15. FoundIndex, CandidateIndex: SizeInt;
  16. CompareResult: SizeInt;
  17. end;
  18. { TCustomArrayHelper }
  19. TCustomArrayHelper<T> = class abstract
  20. protected
  21. class procedure QuickSort(var AValues: array of T; ALeft, ARight: SizeInt;
  22. const AComparer: IComparer<T>); virtual; abstract;
  23. public
  24. //class procedure Sort(var AValues: array of T); overload;
  25. class procedure Sort(var AValues: array of T;
  26. const AComparer: IComparer<T>); overload;
  27. class procedure Sort(var AValues: array of T;
  28. const AComparer: IComparer<T>; AIndex, ACount: SizeInt); overload;
  29. class function BinarySearch(const AValues: array of T; const AItem: T;
  30. out ASearchResult: TBinarySearchResult; const AComparer: IComparer<T>;
  31. AIndex, ACount: SizeInt): Boolean; virtual; abstract; overload;
  32. class function BinarySearch(const AValues: array of T; const AItem: T;
  33. out AFoundIndex: SizeInt; const AComparer: IComparer<T>;
  34. AIndex, ACount: SizeInt): Boolean; virtual; abstract; overload;
  35. class function BinarySearch(const AValues: array of T; const AItem: T;
  36. out AFoundIndex: SizeInt; const AComparer: IComparer<T>): Boolean; overload;
  37. class function BinarySearch(const AValues: array of T; const AItem: T;
  38. out ASearchResult: TBinarySearchResult; const AComparer: IComparer<T>): Boolean; overload;
  39. // No support for automatically creating a comparer.
  40. // class function BinarySearch(const AValues: array of T; const AItem: T;
  41. // out AFoundIndex: SizeInt): Boolean; overload;
  42. // class function BinarySearch(const AValues: array of T; const AItem: T;
  43. // out ASearchResult: TBinarySearchResult): Boolean; overload;
  44. end;
  45. { TArrayHelper }
  46. TArrayHelper<T> = class(TCustomArrayHelper<T>)
  47. protected
  48. class procedure QuickSort(var AValues: array of T; ALeft, ARight: SizeInt;
  49. const AComparer: IComparer<T>); override;
  50. public
  51. class function BinarySearch(const AValues: array of T; const AItem: T;
  52. out ASearchResult: TBinarySearchResult; const AComparer: IComparer<T>;
  53. AIndex, ACount: SizeInt): Boolean; override; overload;
  54. class function BinarySearch(const AValues: array of T; const AItem: T;
  55. out AFoundIndex: SizeInt; const AComparer: IComparer<T>;
  56. AIndex, ACount: SizeInt): Boolean; override; overload;
  57. end;
  58. { TEnumerator }
  59. TEnumerator<T> = class abstract
  60. protected
  61. function DoGetCurrent: T; virtual; abstract;
  62. function DoMoveNext: boolean; virtual; abstract;
  63. public
  64. property Current: T read DoGetCurrent;
  65. function MoveNext: boolean;
  66. end;
  67. { TEnumerable }
  68. TEnumerable<T> = class abstract
  69. protected
  70. type
  71. TMyEnumerator = TEnumerator<T>;
  72. function DoGetEnumerator: TMyEnumerator; virtual; abstract;
  73. public
  74. type
  75. TMyArray = TArray<T>;
  76. function GetEnumerator: TMyEnumerator; inline;
  77. function ToArray: TMyArray; virtual;
  78. end;
  79. { TCustomList }
  80. TCustomList<T> = class abstract(TEnumerable<T>)
  81. private
  82. FOnNotify: TCollectionNotifyEvent<T>;
  83. function GetCapacity: SizeInt; inline;
  84. protected
  85. type TMyArrayHelper = TArrayHelper<T>;
  86. protected
  87. FLength: SizeInt;
  88. FItems: array of T;
  89. function PrepareAddingItem: SizeInt; virtual;
  90. function PrepareAddingRange(ACount: SizeInt): SizeInt; virtual;
  91. procedure Notify(const AValue: T; ACollectionNotification: TCollectionNotification); virtual;
  92. function DoRemove(AIndex: SizeInt; ACollectionNotification: TCollectionNotification): T; virtual;
  93. procedure SetCapacity(AValue: SizeInt); virtual; abstract;
  94. function GetCount: SizeInt; virtual;
  95. public
  96. property Count: SizeInt read GetCount;
  97. property Capacity: SizeInt read GetCapacity write SetCapacity;
  98. property OnNotify: TCollectionNotifyEvent<T> read FOnNotify write FOnNotify;
  99. procedure TrimExcess; virtual; abstract;
  100. end;
  101. { TCustomListEnumerator }
  102. TCustomListEnumerator<T> = class abstract(TEnumerator<T>)
  103. private
  104. FList: TCustomList<T>;
  105. FIndex: SizeInt;
  106. protected
  107. function DoMoveNext: boolean; override;
  108. function DoGetCurrent: T; override;
  109. function GetCurrent: T; virtual;
  110. public
  111. constructor Create(AList: TCustomList<T>);
  112. end;
  113. { TCustomInvertedListEnumerator }
  114. TCustomInvertedListEnumerator<T> = class abstract(TEnumerator<T>)
  115. private
  116. FList: TCustomList<T>;
  117. FIndex: SizeInt;
  118. protected
  119. function DoMoveNext: boolean; override;
  120. function DoGetCurrent: T; override;
  121. function GetCurrent: T; virtual;
  122. public
  123. constructor Create(AList: TCustomList<T>);
  124. end;
  125. { TList }
  126. {$SCOPEDENUMS ON}
  127. TDirection = (FromBeginning,fromEnd);
  128. {$SCOPEDENUMS OFF}
  129. TList<T> = class(TCustomList<T>)
  130. private
  131. FComparer: IComparer<T>;
  132. protected
  133. procedure SetCapacity(AValue: SizeInt); override;
  134. procedure SetCount(AValue: SizeInt);
  135. procedure InitializeList; virtual;
  136. procedure InternalInsert(AIndex: SizeInt; const AValue: T);
  137. function DoGetEnumerator: TEnumerator<T>; override;
  138. private
  139. function GetItem(AIndex: SizeInt): T;
  140. procedure SetItem(AIndex: SizeInt; const AValue: T);
  141. public
  142. type
  143. TEnumerator = class(TCustomListEnumerator<T>);
  144. TMyType = TList<T>;
  145. function GetEnumerator: TEnumerator; reintroduce;
  146. public
  147. constructor Create; overload;
  148. constructor Create(const AComparer: IComparer<T>); overload;
  149. constructor Create(ACollection: TEnumerable<T>); overload;
  150. destructor Destroy; override;
  151. function Add(const AValue: T): SizeInt; virtual;
  152. procedure AddRange(const AValues: array of T); virtual; overload;
  153. procedure AddRange(const AEnumerable: IEnumerable<T>); overload;
  154. procedure AddRange(AEnumerable: TEnumerable<T>); overload;
  155. procedure Insert(AIndex: SizeInt; const AValue: T); virtual;
  156. procedure InsertRange(AIndex: SizeInt; const AValues: array of T); virtual; overload;
  157. procedure InsertRange(AIndex: SizeInt; const AEnumerable: IEnumerable<T>); overload;
  158. procedure InsertRange(AIndex: SizeInt; const AEnumerable: TEnumerable<T>); overload;
  159. function Remove(const AValue: T): SizeInt;
  160. function RemoveItem(const AValue: T; Direction : TDirection): SizeInt;
  161. procedure Delete(AIndex: SizeInt); inline;
  162. procedure DeleteRange(AIndex, ACount: SizeInt);
  163. function ExtractIndex(const AIndex: SizeInt): T; overload;
  164. function Extract(const AValue: T): T; overload;
  165. procedure Exchange(AIndex1, AIndex2: SizeInt); virtual;
  166. procedure Move(AIndex, ANewIndex: SizeInt); virtual;
  167. function First: T; inline;
  168. function Last: T; inline;
  169. procedure Clear;
  170. function Contains(const AValue: T): Boolean; inline;
  171. function IndexOf(const AValue: T): SizeInt; virtual;
  172. function LastIndexOf(const AValue: T): SizeInt; virtual;
  173. procedure Reverse;
  174. procedure TrimExcess; override;
  175. procedure Sort; overload;
  176. procedure Sort(const AComparer: IComparer<T>); overload;
  177. function BinarySearch(const AItem: T; out AIndex: SizeInt): Boolean; overload;
  178. function BinarySearch(const AItem: T; out AIndex: SizeInt; const AComparer: IComparer<T>): Boolean; overload;
  179. property Count: SizeInt read FLength write SetCount;
  180. property Items[Index: SizeInt]: T read GetItem write SetItem; default;
  181. end;
  182. TObjectList<T: class> = class(TList<T>)
  183. private
  184. FObjectsOwner: Boolean;
  185. protected
  186. procedure Notify(const aValue: T; Action: TCollectionNotification); override;
  187. public
  188. constructor Create(aOwnsObjects: Boolean = True); overload;
  189. constructor Create(const AComparer: IComparer<T>; aOwnsObjects: Boolean = True); overload;
  190. constructor Create(const aCollection: TEnumerable<T>; aOwnsObjects: Boolean = True); overload;
  191. property OwnsObjects: Boolean read FObjectsOwner write FObjectsOwner;
  192. end;
  193. { TThreadList }
  194. // This is provided for delphi/FPC compatibility
  195. // No locking is done, since Javascript is single-threaded. We do keep a lock count for debugging purposes.
  196. TThreadList<T> = class
  197. private
  198. FList: TList<T>;
  199. FLock: Integer;
  200. FDuplicates: TDuplicates;
  201. public
  202. constructor Create;
  203. destructor Destroy; override;
  204. procedure Add(const Item: T);
  205. procedure Clear;
  206. function LockList: TList<T>;
  207. procedure Remove(const Item: T); inline;
  208. procedure RemoveItem(const Item: T; Direction: TDirection);
  209. procedure UnlockList; inline;
  210. property Duplicates: TDuplicates read FDuplicates write FDuplicates;
  211. end;
  212. { TQueue }
  213. TQueue<T> = class(TCustomList<T>)
  214. private
  215. FMaxGapLength: Integer;
  216. FLow: SizeInt;
  217. protected
  218. function DoGetEnumerator: TEnumerator<T>; override;
  219. public
  220. type
  221. TMyType = TQueue<T>;
  222. { TEnumerator }
  223. TEnumerator = class(TCustomListEnumerator<T>)
  224. public
  225. constructor Create(AQueue: TMyType);
  226. end;
  227. function GetEnumerator: TEnumerator; reintroduce;
  228. protected
  229. Procedure Rebase; virtual;
  230. procedure SetCapacity(AValue: SizeInt); override;
  231. function DoRemove(AIndex: SizeInt; ACollectionNotification: TCollectionNotification): T; override;
  232. function GetCount: SizeInt; override;
  233. public
  234. Constructor Create; overload;
  235. constructor Create(ACollection: TEnumerable<T>); overload;
  236. destructor Destroy; override;
  237. procedure Enqueue(const AValue: T);
  238. function Dequeue: T;
  239. function Extract: T;
  240. function Peek: T;
  241. procedure Clear;
  242. procedure TrimExcess; override;
  243. // Maximum gap (=amount of empty slots in array before first element)
  244. // before doing a rebase of the list. Defaults to 10.
  245. Property MaxGapLength : Integer Read FMaxGapLength Write FMaxGapLength;
  246. end;
  247. { TObjectQueue }
  248. TObjectQueue<T: class> = class(TQueue<T>)
  249. private
  250. FOwnsObjects: Boolean;
  251. protected
  252. procedure Notify(const Value: T; Action: TCollectionNotification); override;
  253. public
  254. constructor Create(AOwnsObjects: Boolean = True); overload;
  255. constructor Create(const Collection: TEnumerable<T>; AOwnsObjects: Boolean = True); overload;
  256. procedure Dequeue; reintroduce; // Can't use the result, it might have been freed;
  257. property OwnsObjects: Boolean read FOwnsObjects write FOwnsObjects;
  258. end;
  259. { TStack }
  260. TStack<T> = class(TCustomList<T>)
  261. private
  262. protected
  263. function DoRemove(AIndex: SizeInt; ACollectionNotification: TCollectionNotification): T; override;
  264. procedure SetCapacity(AValue: SizeInt); override;
  265. function DoGetEnumerator: TEnumerator<T>; override;
  266. public
  267. type
  268. TMyType = TStack<T>;
  269. { TEnumerator }
  270. TEnumerator = class(TCustomListEnumerator<T>)
  271. public
  272. constructor Create(AStack: TMyType);
  273. end;
  274. function GetEnumerator: TEnumerator; reintroduce;
  275. Public
  276. destructor Destroy; override;
  277. procedure Clear;
  278. procedure Push(const aValue: T);
  279. function Pop: T;
  280. function Peek: T;
  281. function Extract: T;
  282. procedure TrimExcess;
  283. property Count: SizeInt read GetCount;
  284. end;
  285. { TObjectStack }
  286. TObjectStack<T: class> = class(TStack<T>)
  287. private
  288. FOwnsObjects: Boolean;
  289. protected
  290. procedure Notify(const aValue: T; Action: TCollectionNotification); override;
  291. public
  292. constructor Create(AOwnsObjects: Boolean = True); overload;
  293. constructor Create(const Collection: TEnumerable<T>; AOwnsObjects: Boolean = True); overload;
  294. procedure Pop; reintroduce; // Can't use the result, it might have been freed;
  295. property OwnsObjects: Boolean read FOwnsObjects write FOwnsObjects;
  296. end;
  297. { TPair }
  298. TPair<TKey,TValue> = record
  299. Key: TKey;
  300. Value: TValue;
  301. constructor Create(const AKey: TKey; const AValue: TValue);
  302. end;
  303. // Hash table using linear probing
  304. { TDictionary }
  305. EDictionary = Class(Exception);
  306. TDictionary<TKey,TValue> = class(TEnumerable<TPair<TKey,TValue>>)
  307. private
  308. FMap: TJSMap;
  309. function GetItem(const Key: TKey): TValue;
  310. procedure SetItem(const Key: TKey; const Value: TValue);
  311. procedure DoAdd(const Key: TKey; const Value: TValue);
  312. function DoRemove(const Key: TKey; Notification: TCollectionNotification): TValue;
  313. Function GetCount : Integer;
  314. protected
  315. Function CanClearMap : Boolean; virtual;
  316. function DoGetEnumerator: TEnumerator<TPair<TKey,TValue>>; override;
  317. procedure PairNotify(const Key: TKey; Value : TValue; Action: TCollectionNotification); virtual;
  318. procedure KeyNotify(const Key: TKey; Action: TCollectionNotification); virtual;
  319. procedure ValueNotify(const Value: TValue; Action: TCollectionNotification); virtual;
  320. public
  321. Type
  322. TMyType = TDictionary<TKey,TValue>;
  323. TMyPair = TPair<TKey,TValue>;
  324. constructor Create(ACapacity: Integer=0); overload;
  325. constructor Create(const Collection: TEnumerable<TMyPair>); overload;
  326. destructor Destroy; override;
  327. procedure Add(const Key: TKey; const Value: TValue);
  328. procedure Remove(const Key: TKey);
  329. function ExtractPair(const Key: TKey): TMyPair;
  330. procedure Clear;
  331. function TryGetValue(const Key: TKey; out Value: TValue): Boolean;
  332. procedure AddOrSetValue(const Key: TKey; const Value: TValue);
  333. function ContainsKey(const Key: TKey): Boolean;
  334. function ContainsValue(const Value: TValue): Boolean;
  335. function ToArray: TArray<TMyPair>; override;
  336. property Items[const Key: TKey]: TValue read GetItem write SetItem; default;
  337. property Count: Integer read GetCount;
  338. type
  339. { TPairEnumerator }
  340. TPairEnumerator = class(TEnumerator<TMyPair>)
  341. private
  342. FIter: TJSIterator;
  343. FVal : TJSIteratorValue;
  344. function GetCurrent: TMyPair;
  345. protected
  346. function DoGetCurrent: TMyPair; override;
  347. function DoMoveNext: Boolean; override;
  348. public
  349. constructor Create(const ADictionary: TMyType);
  350. function MoveNext: Boolean; reintroduce;
  351. property Current: TMyPair read GetCurrent;
  352. end;
  353. { TKeyEnumerator }
  354. TKeyEnumerator = class(TEnumerator<TKey>)
  355. private
  356. FIter: TJSIterator;
  357. FVal : TJSIteratorValue;
  358. function GetCurrent: TKey;
  359. protected
  360. function DoGetCurrent: TKey; override;
  361. function DoMoveNext: Boolean; override;
  362. public
  363. constructor Create(const AIter: TJSIterator); overload;
  364. constructor Create(const ADictionary: TMyType); overload;
  365. function MoveNext: Boolean; reintroduce;
  366. property Current: TKey read GetCurrent;
  367. end;
  368. { TValueEnumerator }
  369. TValueEnumerator = class(TEnumerator<TValue>)
  370. private
  371. FIter: TJSIterator;
  372. FVal : TJSIteratorValue;
  373. function GetCurrent: TValue;
  374. protected
  375. function DoGetCurrent: TValue; override;
  376. function DoMoveNext: Boolean; override;
  377. public
  378. constructor Create(const AIter: TJSIterator); overload;
  379. constructor Create(const ADictionary: TMyType); overload;
  380. function MoveNext: Boolean; reintroduce;
  381. property Current: TValue read GetCurrent;
  382. end;
  383. { TValueCollection }
  384. TValueCollection = class(TEnumerable<TValue>)
  385. private
  386. FMap: TJSMap;
  387. function GetCount: Integer;
  388. protected
  389. function DoGetEnumerator: TEnumerator<TValue>; override;
  390. public
  391. constructor Create(const ADictionary: TMyType);
  392. function GetEnumerator: TValueEnumerator; reintroduce;
  393. function ToArray: TArray<TValue>; override;
  394. property Count: Integer read GetCount;
  395. end;
  396. { TKeyCollection }
  397. TKeyCollection = class(TEnumerable<TKey>)
  398. private
  399. FMap: TJSMap;
  400. function GetCount: Integer;
  401. protected
  402. function DoGetEnumerator: TEnumerator<TKey>; override;
  403. public
  404. constructor Create(const ADictionary: TMyType);
  405. function GetEnumerator: TKeyEnumerator; reintroduce;
  406. function ToArray: TArray<TKey>; override;
  407. property Count: Integer read GetCount;
  408. end;
  409. private
  410. FOnKeyNotify: TCollectionNotifyEvent<TKey>;
  411. FOnValueNotify: TCollectionNotifyEvent<TValue>;
  412. FKeyCollection: TKeyCollection;
  413. FValueCollection: TValueCollection;
  414. function GetKeys: TKeyCollection;
  415. function GetValues: TValueCollection;
  416. public
  417. function GetEnumerator: TPairEnumerator; reintroduce;
  418. property Keys: TKeyCollection read GetKeys;
  419. property Values: TValueCollection read GetValues;
  420. property OnKeyNotify: TCollectionNotifyEvent<TKey> read FOnKeyNotify write FOnKeyNotify;
  421. property OnValueNotify: TCollectionNotifyEvent<TValue> read FOnValueNotify write FOnValueNotify;
  422. end;
  423. TDictionaryOwnership = (doOwnsKeys, doOwnsValues);
  424. TDictionaryOwnerships = set of TDictionaryOwnership;
  425. { TObjectDictionary }
  426. TObjectDictionary<TKey,TValue> = class(TDictionary<TKey,TValue>)
  427. private
  428. FOwnerships: TDictionaryOwnerships;
  429. protected
  430. Function CanClearMap : Boolean; override;
  431. procedure KeyNotify(const Key: TKey; Action: TCollectionNotification); override;
  432. procedure ValueNotify(const Value: TValue; Action: TCollectionNotification); override;
  433. public
  434. constructor Create(aOwnerships: TDictionaryOwnerships; ACapacity: Integer); overload;
  435. constructor Create(aOwnerships: TDictionaryOwnerships); overload;
  436. Property OwnerShips : TDictionaryOwnerships Read FOwnerships Write FOwnerShips;
  437. end;
  438. implementation
  439. { TCustomArrayHelper }
  440. class procedure TCustomArrayHelper<T>.Sort(var AValues: array of T;
  441. const AComparer: IComparer<T>);
  442. begin
  443. QuickSort(AValues, 0, Length(AValues), AComparer);
  444. end;
  445. class procedure TCustomArrayHelper<T>.Sort(var AValues: array of T;
  446. const AComparer: IComparer<T>; AIndex, ACount: SizeInt);
  447. begin
  448. if ACount <= 1 then
  449. Exit;
  450. QuickSort(AValues, AIndex, Pred(AIndex + ACount), AComparer);
  451. end;
  452. class function TCustomArrayHelper<T>.BinarySearch(const AValues: array of T;
  453. const AItem: T; out AFoundIndex: SizeInt; const AComparer: IComparer<T>
  454. ): Boolean;
  455. begin
  456. Writeln('Here too',Length(aValues));
  457. Result := BinarySearch(AValues, AItem, AFoundIndex, AComparer,
  458. 0, Length(AValues));
  459. end;
  460. class function TCustomArrayHelper<T>.BinarySearch(const AValues: array of T;
  461. const AItem: T; out ASearchResult: TBinarySearchResult;
  462. const AComparer: IComparer<T>): Boolean;
  463. begin
  464. Writeln('Here',Length(aValues));
  465. Result := BinarySearch(AValues, AItem, ASearchResult, AComparer,
  466. 0, Length(AValues));
  467. end;
  468. { TArrayHelper }
  469. class procedure TArrayHelper<T>.QuickSort(var AValues: array of T; ALeft,
  470. ARight: SizeInt; const AComparer: IComparer<T>);
  471. var
  472. I, J: SizeInt;
  473. P, Q: T;
  474. begin
  475. if ((ARight - ALeft) <= 0) or (Length(AValues) = 0) then
  476. Exit;
  477. repeat
  478. I := ALeft;
  479. J := ARight;
  480. P := AValues[ALeft + (ARight - ALeft) shr 1];
  481. repeat
  482. while AComparer.Compare(AValues[I], P) < 0 do
  483. Inc(I);
  484. while AComparer.Compare(AValues[J], P) > 0 do
  485. Dec(J);
  486. if I <= J then
  487. begin
  488. if I <> J then
  489. begin
  490. Q := AValues[I];
  491. AValues[I] := AValues[J];
  492. AValues[J] := Q;
  493. end;
  494. Inc(I);
  495. Dec(J);
  496. end;
  497. until I > J;
  498. // sort the smaller range recursively
  499. // sort the bigger range via the loop
  500. // Reasons: memory usage is O(log(n)) instead of O(n) and loop is faster than recursion
  501. if J - ALeft < ARight - I then
  502. begin
  503. if ALeft < J then
  504. QuickSort(AValues, ALeft, J, AComparer);
  505. ALeft := I;
  506. end
  507. else
  508. begin
  509. if I < ARight then
  510. QuickSort(AValues, I, ARight, AComparer);
  511. ARight := J;
  512. end;
  513. until ALeft >= ARight;
  514. end;
  515. class function TArrayHelper<T>.BinarySearch(const AValues: array of T;
  516. const AItem: T; out ASearchResult: TBinarySearchResult;
  517. const AComparer: IComparer<T>; AIndex, ACount: SizeInt): Boolean;
  518. var
  519. imin, imax, imid, ilo: Int32;
  520. begin
  521. Writeln('Enter ',Length(aValues),' Idx ',aIndex,' acount: ',aCount);
  522. // continually narrow search until just one element remains
  523. imin := AIndex;
  524. imax := Pred(AIndex + ACount);
  525. Writeln('Start Imax, imin : ',Imax, ' - ', imin);
  526. ilo:=imid * imid;
  527. imid:=ilo*imid;
  528. while (imin < imax) do
  529. begin
  530. imid := (imax+imin) div 2;
  531. writeln('imid',imid);
  532. ASearchResult.CompareResult := AComparer.Compare(AValues[imid], AItem);
  533. // reduce the search
  534. if (ASearchResult.CompareResult < 0) then
  535. imin := imid + 1
  536. else
  537. begin
  538. if ASearchResult.CompareResult = 0 then
  539. begin
  540. ASearchResult.FoundIndex := imid;
  541. ASearchResult.CandidateIndex := imid;
  542. Exit(True);
  543. end;
  544. imax := imid;
  545. end;
  546. end;
  547. // At exit of while:
  548. // if A[] is empty, then imax < imin
  549. // otherwise imax == imin
  550. // deferred test for equality
  551. Writeln('End Imax, imin : ',Imax, ' - ', imin);
  552. if (imax = imin) then
  553. begin
  554. ASearchResult.CompareResult := AComparer.Compare(AValues[imin], AItem);
  555. ASearchResult.CandidateIndex := imin;
  556. if (ASearchResult.CompareResult = 0) then
  557. begin
  558. ASearchResult.FoundIndex := imin;
  559. Exit(True);
  560. end else
  561. begin
  562. ASearchResult.FoundIndex := -1;
  563. Exit(False);
  564. end;
  565. end
  566. else
  567. begin
  568. ASearchResult.CompareResult := 0;
  569. ASearchResult.FoundIndex := -1;
  570. ASearchResult.CandidateIndex := -1;
  571. Exit(False);
  572. end;
  573. end;
  574. class function TArrayHelper<T>.BinarySearch(const AValues: array of T;
  575. const AItem: T; out AFoundIndex: SizeInt; const AComparer: IComparer<T>;
  576. AIndex, ACount: SizeInt): Boolean;
  577. var
  578. imin, imax, imid: Int32;
  579. LCompare: SizeInt;
  580. begin
  581. // continually narrow search until just one element remains
  582. imin := AIndex;
  583. imax := Pred(AIndex + ACount);
  584. // http://en.wikipedia.org/wiki/Binary_search_algorithm
  585. while (imin < imax) do
  586. begin
  587. imid := (imin + imax) div 2;
  588. // code must guarantee the interval is reduced at each iteration
  589. // assert(imid < imax);
  590. // note: 0 <= imin < imax implies imid will always be less than imax
  591. LCompare := AComparer.Compare(AValues[imid], AItem);
  592. // reduce the search
  593. if (LCompare < 0) then
  594. imin := imid + 1
  595. else
  596. begin
  597. if LCompare = 0 then
  598. begin
  599. AFoundIndex := imid;
  600. Exit(True);
  601. end;
  602. imax := imid;
  603. end;
  604. end;
  605. // At exit of while:
  606. // if A[] is empty, then imax < imin
  607. // otherwise imax == imin
  608. // deferred test for equality
  609. LCompare := AComparer.Compare(AValues[imin], AItem);
  610. if (imax = imin) and (LCompare = 0) then
  611. begin
  612. AFoundIndex := imin;
  613. Exit(True);
  614. end
  615. else
  616. begin
  617. AFoundIndex := -1;
  618. Exit(False);
  619. end;
  620. end;
  621. { TEnumerator }
  622. function TEnumerator<T>.MoveNext: boolean;
  623. begin
  624. Exit(DoMoveNext);
  625. end;
  626. { TEnumerable }
  627. function TEnumerable<T>.GetEnumerator: TMyEnumerator;
  628. begin
  629. Exit(DoGetEnumerator);
  630. end;
  631. function TEnumerable<T>.ToArray: TMyArray;
  632. var
  633. LEnumerator: TMyEnumerator;
  634. begin
  635. Result:=[];
  636. LEnumerator := GetEnumerator;
  637. try
  638. while LEnumerator.MoveNext do
  639. TJSArray(Result).push(LEnumerator.Current);
  640. finally
  641. LEnumerator.Free;
  642. end;
  643. end;
  644. { TCustomList }
  645. function TCustomList<T>.GetCapacity: SizeInt;
  646. begin
  647. Result:=length(FItems);
  648. end;
  649. function TCustomList<T>.PrepareAddingItem: SizeInt;
  650. begin
  651. if FLength=length(FItems) then
  652. TJSArray(FItems).push(Default(T));
  653. Result := FLength;
  654. Inc(FLength);
  655. end;
  656. function TCustomList<T>.PrepareAddingRange(ACount: SizeInt): SizeInt;
  657. var
  658. l: SizeInt;
  659. begin
  660. if ACount < 0 then
  661. raise EArgumentOutOfRangeException.Create(SArgumentOutOfRange);
  662. if ACount = 0 then
  663. Exit(FLength - 1);
  664. for l:=length(FItems)+1 to FLength+ACount do
  665. TJSArray(FItems).push(Default(T));
  666. Result := FLength;
  667. Inc(FLength, ACount);
  668. end;
  669. procedure TCustomList<T>.Notify(const AValue: T;
  670. ACollectionNotification: TCollectionNotification);
  671. begin
  672. if Assigned(FOnNotify) then
  673. FOnNotify(Self, AValue, ACollectionNotification);
  674. end;
  675. function TCustomList<T>.DoRemove(AIndex: SizeInt;
  676. ACollectionNotification: TCollectionNotification): T;
  677. begin
  678. if (AIndex < 0) or (AIndex >= FLength) then
  679. raise EArgumentOutOfRangeException.Create(SArgumentOutOfRange);
  680. Result := FItems[AIndex];
  681. Dec(FLength);
  682. FItems[AIndex] := Default(T); // needed for refcounted types
  683. TJSArray(FItems).splice(AIndex,1);
  684. Notify(Result, ACollectionNotification);
  685. end;
  686. function TCustomList<T>.GetCount: SizeInt;
  687. begin
  688. Result := FLength;
  689. end;
  690. { TCustomListEnumerator }
  691. function TCustomListEnumerator<T>.DoMoveNext: boolean;
  692. begin
  693. Inc(FIndex);
  694. Result := (FList.FLength > 0) and (FIndex < FList.FLength)
  695. end;
  696. function TCustomListEnumerator<T>.DoGetCurrent: T;
  697. begin
  698. Result := GetCurrent;
  699. end;
  700. function TCustomListEnumerator<T>.GetCurrent: T;
  701. begin
  702. Result := FList.FItems[FIndex];
  703. end;
  704. constructor TCustomListEnumerator<T>.Create(AList: TCustomList<T>);
  705. begin
  706. inherited Create;
  707. FIndex := -1;
  708. FList := AList;
  709. end;
  710. { TList }
  711. procedure TList<T>.SetCapacity(AValue: SizeInt);
  712. begin
  713. if AValue < Count then
  714. Count := AValue;
  715. SetLength(FItems, AValue);
  716. end;
  717. procedure TList<T>.SetCount(AValue: SizeInt);
  718. begin
  719. if AValue < 0 then
  720. raise EArgumentOutOfRangeException.Create(SArgumentOutOfRange);
  721. if AValue > Capacity then
  722. Capacity := AValue
  723. else if AValue < Count then
  724. DeleteRange(AValue, Count - AValue);
  725. FLength := AValue;
  726. end;
  727. procedure TList<T>.InitializeList;
  728. begin
  729. end;
  730. procedure TList<T>.InternalInsert(AIndex: SizeInt; const AValue: T);
  731. begin
  732. if (AIndex < 0) or (AIndex > Count) then
  733. raise EArgumentOutOfRangeException.Create(SArgumentOutOfRange);
  734. TJSArray(FItems).splice(AIndex,0,AValue);
  735. inc(FLength);
  736. FItems[AIndex] := AValue;
  737. Notify(AValue, cnAdded);
  738. end;
  739. function TList<T>.DoGetEnumerator: TEnumerator<T>;
  740. begin
  741. Result := GetEnumerator;
  742. end;
  743. function TList<T>.GetItem(AIndex: SizeInt): T;
  744. begin
  745. if (AIndex < 0) or (AIndex >= Count) then
  746. raise EArgumentOutOfRangeException.Create(SArgumentOutOfRange);
  747. Result := FItems[AIndex];
  748. end;
  749. procedure TList<T>.SetItem(AIndex: SizeInt; const AValue: T);
  750. begin
  751. if (AIndex < 0) or (AIndex >= Count) then
  752. raise EArgumentOutOfRangeException.Create(SArgumentOutOfRange);
  753. Notify(FItems[AIndex], cnRemoved);
  754. FItems[AIndex] := AValue;
  755. Notify(AValue, cnAdded);
  756. end;
  757. function TList<T>.GetEnumerator: TEnumerator;
  758. begin
  759. Result := TEnumerator.Create(Self);
  760. end;
  761. constructor TList<T>.Create;
  762. begin
  763. InitializeList;
  764. FComparer := TComparer<T>.Default;
  765. end;
  766. constructor TList<T>.Create(const AComparer: IComparer<T>);
  767. begin
  768. InitializeList;
  769. FComparer := AComparer;
  770. end;
  771. constructor TList<T>.Create(ACollection: TEnumerable<T>);
  772. var
  773. LItem: T;
  774. begin
  775. Create;
  776. for LItem in ACollection do
  777. Add(LItem);
  778. end;
  779. destructor TList<T>.Destroy;
  780. begin
  781. SetCapacity(0);
  782. end;
  783. function TList<T>.Add(const AValue: T): SizeInt;
  784. begin
  785. Result := PrepareAddingItem;
  786. FItems[Result] := AValue;
  787. Notify(AValue, cnAdded);
  788. end;
  789. procedure TList<T>.AddRange(const AValues: array of T);
  790. begin
  791. InsertRange(Count, AValues);
  792. end;
  793. procedure TList<T>.AddRange(const AEnumerable: IEnumerable<T>);
  794. var
  795. LValue: T;
  796. begin
  797. for LValue in AEnumerable do
  798. Add(LValue);
  799. end;
  800. procedure TList<T>.AddRange(AEnumerable: TEnumerable<T>);
  801. var
  802. LValue: T;
  803. begin
  804. for LValue in AEnumerable do
  805. Add(LValue);
  806. end;
  807. procedure TList<T>.Insert(AIndex: SizeInt; const AValue: T);
  808. begin
  809. if (AIndex < 0) or (AIndex > Count) then
  810. raise EArgumentOutOfRangeException.Create(SArgumentOutOfRange);
  811. InternalInsert(AIndex, AValue);
  812. end;
  813. procedure TList<T>.InsertRange(AIndex: SizeInt; const AValues: array of T);
  814. var
  815. LLength, i: sizeint;
  816. LValue: T;
  817. begin
  818. if (AIndex < 0) or (AIndex > Count) then
  819. raise EArgumentOutOfRangeException.Create(SArgumentOutOfRange);
  820. LLength := Length(AValues);
  821. if LLength = 0 then
  822. Exit;
  823. if AIndex <> PrepareAddingRange(LLength) then
  824. begin
  825. for i := AIndex to Count - LLength -1 do
  826. FItems[i+LLength] := FItems[i];
  827. for i := 0 to LLength -1 do
  828. FItems[AIndex+i] := Default(T);
  829. end;
  830. for i := 0 to Pred(LLength) do
  831. begin
  832. LValue:=AValues[i];
  833. FItems[i+AIndex] := LValue;
  834. Notify(LValue, cnAdded);
  835. end;
  836. end;
  837. procedure TList<T>.InsertRange(AIndex: SizeInt; const AEnumerable: IEnumerable<T>);
  838. var
  839. LValue: T;
  840. i: SizeInt;
  841. begin
  842. if (AIndex < 0) or (AIndex > Count) then
  843. raise EArgumentOutOfRangeException.Create(SArgumentOutOfRange);
  844. i := 0;
  845. for LValue in AEnumerable do
  846. begin
  847. InternalInsert(AIndex + i, LValue);
  848. Inc(i);
  849. end;
  850. end;
  851. procedure TList<T>.InsertRange(AIndex: SizeInt; const AEnumerable: TEnumerable<T>);
  852. var
  853. LValue: T;
  854. i: SizeInt;
  855. begin
  856. if (AIndex < 0) or (AIndex > Count) then
  857. raise EArgumentOutOfRangeException.Create(SArgumentOutOfRange);
  858. i := 0;
  859. for LValue in AEnumerable do
  860. begin
  861. InternalInsert(Aindex + i, LValue);
  862. Inc(i);
  863. end;
  864. end;
  865. function TList<T>.RemoveItem(const AValue: T; Direction : TDirection): SizeInt;
  866. begin
  867. if Direction=TDirection.FromEnd then
  868. Result := LastIndexOf(AValue)
  869. else
  870. Result := IndexOf(AValue);
  871. if Result >= 0 then
  872. DoRemove(Result, cnRemoved);
  873. end;
  874. function TList<T>.Remove(const AValue: T): SizeInt;
  875. begin
  876. Result := IndexOf(AValue);
  877. if Result >= 0 then
  878. DoRemove(Result, cnRemoved);
  879. end;
  880. procedure TList<T>.Delete(AIndex: SizeInt);
  881. begin
  882. DoRemove(AIndex, cnRemoved);
  883. end;
  884. procedure TList<T>.DeleteRange(AIndex, ACount: SizeInt);
  885. var
  886. LDeleted: TMyArray;
  887. i: SizeInt;
  888. begin
  889. if ACount = 0 then
  890. Exit;
  891. if (ACount < 0) or (AIndex < 0) or (AIndex + ACount > Count) then
  892. raise EArgumentOutOfRangeException.Create(SArgumentOutOfRange);
  893. LDeleted:=TMyArray(TJSArray(FItems).splice(AIndex,Count));
  894. Dec(FLength, ACount);
  895. for i := 0 to High(LDeleted) do
  896. Notify(LDeleted[i], cnRemoved);
  897. end;
  898. function TList<T>.ExtractIndex(const AIndex: SizeInt): T;
  899. begin
  900. Result := DoRemove(AIndex, cnExtracted);
  901. end;
  902. function TList<T>.Extract(const AValue: T): T;
  903. var
  904. LIndex: SizeInt;
  905. begin
  906. LIndex := IndexOf(AValue);
  907. if LIndex < 0 then
  908. Exit(Default(T));
  909. Result := DoRemove(LIndex, cnExtracted);
  910. end;
  911. procedure TList<T>.Exchange(AIndex1, AIndex2: SizeInt);
  912. var
  913. LTemp: T;
  914. begin
  915. LTemp := FItems[AIndex1];
  916. FItems[AIndex1] := FItems[AIndex2];
  917. FItems[AIndex2] := LTemp;
  918. end;
  919. procedure TList<T>.Move(AIndex, ANewIndex: SizeInt);
  920. var
  921. Arr: TJSArray;
  922. LTemp: JSValue;
  923. i: SizeInt;
  924. begin
  925. if ANewIndex = AIndex then
  926. Exit;
  927. if (ANewIndex < 0) or (ANewIndex >= Count) then
  928. raise EArgumentOutOfRangeException.Create(SArgumentOutOfRange);
  929. Arr := TJSArray(FItems);
  930. LTemp := Arr[AIndex];
  931. if AIndex < ANewIndex then
  932. for i := AIndex to ANewIndex-1 do
  933. Arr[i] := Arr[i+1]
  934. else
  935. for i := ANewIndex downto AIndex+1 do
  936. Arr[i] := Arr[i-1];
  937. Arr[ANewIndex] := LTemp;
  938. end;
  939. function TList<T>.First: T;
  940. begin
  941. Result := Items[0];
  942. end;
  943. function TList<T>.Last: T;
  944. begin
  945. Result := Items[Pred(Count)];
  946. end;
  947. procedure TList<T>.Clear;
  948. begin
  949. SetCount(0);
  950. SetCapacity(0);
  951. end;
  952. function TList<T>.Contains(const AValue: T): Boolean;
  953. begin
  954. Result := IndexOf(AValue) >= 0;
  955. end;
  956. function TList<T>.IndexOf(const AValue: T): SizeInt;
  957. var
  958. i: SizeInt;
  959. begin
  960. for i := 0 to Count - 1 do
  961. if FComparer.Compare(AValue, FItems[i]) = 0 then
  962. Exit(i);
  963. Result := -1;
  964. end;
  965. function TList<T>.LastIndexOf(const AValue: T): SizeInt;
  966. var
  967. i: SizeInt;
  968. begin
  969. for i := Count - 1 downto 0 do
  970. if FComparer.Compare(AValue, FItems[i]) = 0 then
  971. Exit(i);
  972. Result := -1;
  973. end;
  974. procedure TList<T>.Reverse;
  975. var
  976. a, b: SizeInt;
  977. LTemp: T;
  978. begin
  979. a := 0;
  980. b := Count - 1;
  981. while a < b do
  982. begin
  983. LTemp := FItems[a];
  984. FItems[a] := FItems[b];
  985. FItems[b] := LTemp;
  986. Inc(a);
  987. Dec(b);
  988. end;
  989. end;
  990. procedure TList<T>.TrimExcess;
  991. begin
  992. SetCapacity(Count);
  993. end;
  994. procedure TList<T>.Sort;
  995. begin
  996. TMyArrayHelper.Sort(FItems, FComparer, 0, Count);
  997. end;
  998. procedure TList<T>.Sort(const AComparer: IComparer<T>);
  999. begin
  1000. TMyArrayHelper.Sort(FItems, AComparer, 0, Count);
  1001. end;
  1002. function TList<T>.BinarySearch(const AItem: T; out AIndex: SizeInt): Boolean;
  1003. begin
  1004. Result := TMyArrayHelper.BinarySearch(FItems, AItem, AIndex, FComparer, 0, Count);
  1005. end;
  1006. function TList<T>.BinarySearch(const AItem: T; out AIndex: SizeInt;
  1007. const AComparer: IComparer<T>): Boolean;
  1008. begin
  1009. Result := TMyArrayHelper.BinarySearch(FItems, AItem, AIndex, AComparer, 0, Count);
  1010. end;
  1011. { TPair }
  1012. constructor TPair<TKey,TValue>.Create(const AKey: TKey; const AValue: TValue);
  1013. begin
  1014. Key:=aKey;
  1015. Value:=aValue;
  1016. end;
  1017. { TDictionary }
  1018. ResourceString
  1019. SErrDictKeyNotFound = 'Key value not found';
  1020. SErrDictDuplicateKey = 'Duplicate key value';
  1021. function TDictionary<TKey, TValue>.GetItem(const Key: TKey): TValue;
  1022. Var
  1023. V : JSValue;
  1024. begin
  1025. V:=FMap.Get(Key);
  1026. if isUndefined(v) then
  1027. Raise EDictionary.Create(SErrDictKeyNotFound);
  1028. Result:=TValue(V);
  1029. end;
  1030. procedure TDictionary<TKey, TValue>.SetItem(const Key: TKey; const Value: TValue);
  1031. Var
  1032. V : JSValue;
  1033. begin
  1034. V:=FMap.Get(Key);
  1035. if Not isUndefined(v) then
  1036. ValueNotify(TValue(V),cnRemoved);
  1037. FMap.&Set(Key,Value);
  1038. ValueNotify(Value, cnAdded);
  1039. end;
  1040. procedure TDictionary<TKey, TValue>.DoAdd(const Key: TKey; const Value: TValue);
  1041. begin
  1042. FMap.&Set(Key,Value);
  1043. KeyNotify(Key,cnAdded);
  1044. ValueNotify(Value,cnAdded);
  1045. end;
  1046. function TDictionary<TKey, TValue>.DoRemove(const Key: TKey; Notification: TCollectionNotification): TValue;
  1047. Var
  1048. V : JSValue;
  1049. begin
  1050. V:=FMap.Get(Key);
  1051. if Not isUndefined(v) then
  1052. begin
  1053. FMap.Delete(Key);
  1054. Result:=TValue(v);
  1055. KeyNotify(Key,Notification);
  1056. ValueNotify(Result,Notification);
  1057. end;
  1058. end;
  1059. function TDictionary<TKey, TValue>.GetCount: Integer;
  1060. begin
  1061. Result:=FMap.Size;
  1062. end;
  1063. function TDictionary<TKey, TValue>.DoGetEnumerator: TEnumerator<TMyPair>;
  1064. begin
  1065. Result:=TPairEnumerator.Create(Self);
  1066. end;
  1067. procedure TDictionary<TKey, TValue>.PairNotify(const Key: TKey; Value : TValue; Action: TCollectionNotification);
  1068. begin
  1069. KeyNotify(Key,action);
  1070. ValueNotify(Value,action);
  1071. end;
  1072. procedure TDictionary<TKey, TValue>.KeyNotify(const Key: TKey; Action: TCollectionNotification);
  1073. begin
  1074. if Assigned(FOnKeyNotify) then
  1075. FOnKeyNotify(Self,Key,Action);
  1076. end;
  1077. procedure TDictionary<TKey, TValue>.ValueNotify(const Value: TValue; Action: TCollectionNotification);
  1078. begin
  1079. if Assigned(FOnValueNotify) then
  1080. FOnValueNotify(Self,Value,Action);
  1081. end;
  1082. constructor TDictionary<TKey, TValue>.Create(ACapacity: Integer = 0);
  1083. begin
  1084. FMap:=TJSMap.New;
  1085. end;
  1086. constructor TDictionary<TKey, TValue>.Create(const Collection: TEnumerable<TMyPair>);
  1087. Var
  1088. aPair : TMyPair;
  1089. begin
  1090. Create(0);
  1091. For aPair in Collection do
  1092. Add(aPair.Key,aPair.Value);
  1093. end;
  1094. destructor TDictionary<TKey, TValue>.Destroy;
  1095. begin
  1096. FreeAndNil(FKeyCollection);
  1097. FreeAndNil(FValueCollection);
  1098. Clear;
  1099. FMap:=Nil;
  1100. inherited Destroy;
  1101. end;
  1102. procedure TDictionary<TKey, TValue>.Add(const Key: TKey; const Value: TValue);
  1103. begin
  1104. if FMap.Has(Key) then
  1105. Raise EDictionary.Create(SErrDictDuplicateKey);
  1106. DoAdd(Key,Value);
  1107. end;
  1108. procedure TDictionary<TKey, TValue>.Remove(const Key: TKey);
  1109. begin
  1110. doRemove(Key,cnRemoved);
  1111. end;
  1112. function TDictionary<TKey, TValue>.ExtractPair(const Key: TKey): TMyPair;
  1113. begin
  1114. if FMap.Has(Key) then
  1115. begin
  1116. Result.Create(Key,TValue(FMap.get(key)));
  1117. FMap.Delete(Key);
  1118. end
  1119. else
  1120. Result.Create(Key,Default(TValue));
  1121. end;
  1122. Function TDictionary<TKey, TValue>.CanClearMap : Boolean;
  1123. begin
  1124. Result:=(FOnKeyNotify=Nil) and (FOnValueNotify=Nil);
  1125. end;
  1126. procedure TDictionary<TKey, TValue>.Clear;
  1127. Var
  1128. Iter : TJSIterator;
  1129. IVal : TJSIteratorValue;
  1130. A : TJSValueDynArray;
  1131. K : TKey;
  1132. V : TValue;
  1133. begin
  1134. if CanClearMap then
  1135. Fmap.Clear
  1136. else
  1137. begin
  1138. Iter:=FMap.Entries;
  1139. Repeat
  1140. IVal:=Iter.next;
  1141. if not ival.Done then
  1142. begin
  1143. A:=TJSValueDynArray(IVal.Value);
  1144. K:=TKey(A[0]);
  1145. V:=TValue(A[1]);
  1146. FMap.delete(k);
  1147. PairNotify(K,V,cnRemoved);
  1148. end;
  1149. Until Ival.Done;
  1150. end;
  1151. end;
  1152. function TDictionary<TKey, TValue>.TryGetValue(const Key: TKey; out Value: TValue): Boolean;
  1153. begin
  1154. Result:=FMap.Has(Key);
  1155. If Result then
  1156. Value:=TValue(FMap.get(Key));
  1157. end;
  1158. procedure TDictionary<TKey, TValue>.AddOrSetValue(const Key: TKey; const Value: TValue);
  1159. begin
  1160. if Not FMap.Has(Key) then
  1161. DoAdd(Key,Value)
  1162. else
  1163. SetItem(Key,Value);
  1164. end;
  1165. function TDictionary<TKey, TValue>.ContainsKey(const Key: TKey): Boolean;
  1166. begin
  1167. Result:=FMap.Has(Key);
  1168. end;
  1169. function TDictionary<TKey, TValue>.ContainsValue(const Value: TValue): Boolean;
  1170. Var
  1171. It : TJSIterator;
  1172. Res : TJSIteratorValue;
  1173. begin
  1174. Result:=False;
  1175. It:=FMap.Values;
  1176. Repeat
  1177. Res:=It.next;
  1178. if not Res.done then
  1179. Result:=(Value=TValue(Res.value));
  1180. Until (Result or Res.done);
  1181. end;
  1182. function TDictionary<TKey, TValue>.ToArray: TArray<TMyPair>;
  1183. begin
  1184. Result:=inherited ToArray;
  1185. end;
  1186. function TDictionary<TKey, TValue>.GetKeys: TKeyCollection;
  1187. begin
  1188. if FKeyCollection=Nil then
  1189. FKeyCollection:=TKeyCollection.Create(Self);
  1190. Result:=FKeyCollection;
  1191. end;
  1192. function TDictionary<TKey, TValue>.GetValues: TValueCollection;
  1193. begin
  1194. if FValueCollection=Nil then
  1195. FValueCollection:=TValueCollection.Create(Self);
  1196. Result:=FValueCollection;
  1197. end;
  1198. function TDictionary<TKey, TValue>.GetEnumerator: TPairEnumerator;
  1199. begin
  1200. Result:=TPairEnumerator.Create(Self);
  1201. end;
  1202. { TDictionary.TPairEnumerator }
  1203. function TDictionary<TKey, TValue>.TPairEnumerator.GetCurrent: TMyPair;
  1204. begin
  1205. Result:=DoGetCurrent;
  1206. end;
  1207. function TDictionary<TKey, TValue>.TPairEnumerator.DoGetCurrent: TMyPair;
  1208. Var
  1209. A : TJSValueDynArray;
  1210. begin
  1211. A:=TJSValueDynArray(FVal.Value);
  1212. Result.Create(TKey(A[0]),TValue(A[1]));
  1213. end;
  1214. function TDictionary<TKey, TValue>.TPairEnumerator.DoMoveNext: Boolean;
  1215. begin
  1216. FVal:=FIter.Next;
  1217. Result:=Not FVal.Done;
  1218. end;
  1219. constructor TDictionary<TKey, TValue>.TPairEnumerator.Create(const ADictionary: TMyType);
  1220. begin
  1221. FIter:=ADictionary.FMap.Entries;
  1222. end;
  1223. function TDictionary<TKey, TValue>.TPairEnumerator.MoveNext: Boolean;
  1224. begin
  1225. Result:=DoMoveNext;
  1226. end;
  1227. { TDictionary.TKeyEnumerator }
  1228. function TDictionary<TKey, TValue>.TKeyEnumerator.GetCurrent: TKey;
  1229. begin
  1230. Result:=DoGetCurrent;
  1231. end;
  1232. function TDictionary<TKey, TValue>.TKeyEnumerator.DoGetCurrent: TKey;
  1233. begin
  1234. Result:=TKey(FVal.Value);
  1235. end;
  1236. function TDictionary<TKey, TValue>.TKeyEnumerator.DoMoveNext: Boolean;
  1237. begin
  1238. FVal:=FIter.Next;
  1239. Result:=Not FVal.Done;
  1240. end;
  1241. constructor TDictionary<TKey, TValue>.TKeyEnumerator.Create(const ADictionary: TMyType);
  1242. begin
  1243. Create(ADictionary.FMap.Keys);
  1244. end;
  1245. constructor TDictionary<TKey, TValue>.TKeyEnumerator.Create(const AIter : TJSIterator);
  1246. begin
  1247. FIter:=aIter;
  1248. end;
  1249. function TDictionary<TKey, TValue>.TKeyEnumerator.MoveNext: Boolean;
  1250. begin
  1251. Result:=DoMoveNext;
  1252. end;
  1253. { TDictionary.TValueEnumerator }
  1254. function TDictionary<TKey, TValue>.TValueEnumerator.GetCurrent: TValue;
  1255. begin
  1256. Result:=DoGetCurrent;
  1257. end;
  1258. function TDictionary<TKey, TValue>.TValueEnumerator.DoGetCurrent: TValue;
  1259. begin
  1260. Result:=TValue(FVal.Value);
  1261. end;
  1262. function TDictionary<TKey, TValue>.TValueEnumerator.DoMoveNext: Boolean;
  1263. begin
  1264. FVal:=FIter.Next;
  1265. Result:=Not FVal.Done;
  1266. end;
  1267. constructor TDictionary<TKey, TValue>.TValueEnumerator.Create(const ADictionary: TMyType);
  1268. begin
  1269. Create(aDictionary.FMap.Values);
  1270. end;
  1271. constructor TDictionary<TKey, TValue>.TValueEnumerator.Create(const AIter: TJSIterator);
  1272. begin
  1273. FIter:=AIter;
  1274. end;
  1275. function TDictionary<TKey, TValue>.TValueEnumerator.MoveNext: Boolean;
  1276. begin
  1277. Result:=DoMoveNext;
  1278. end;
  1279. { TDictionary.TValueCollection }
  1280. function TDictionary<TKey, TValue>.TValueCollection.GetCount: Integer;
  1281. begin
  1282. Result:=FMap.Size;
  1283. end;
  1284. function TDictionary<TKey, TValue>.TValueCollection.DoGetEnumerator: TEnumerator<TValue>;
  1285. begin
  1286. Result:=TValueEnumerator.Create(FMap.Values);
  1287. end;
  1288. constructor TDictionary<TKey, TValue>.TValueCollection.Create(const ADictionary: TMyType);
  1289. begin
  1290. FMap:=ADictionary.FMap;
  1291. end;
  1292. function TDictionary<TKey, TValue>.TValueCollection.GetEnumerator: TValueEnumerator;
  1293. begin
  1294. Result:=TValueEnumerator(DoGetEnumerator);
  1295. end;
  1296. function TDictionary<TKey, TValue>.TValueCollection.ToArray: TArray<TValue>;
  1297. Var
  1298. I : Integer;
  1299. P : TValue;
  1300. begin
  1301. SetLength(Result,FMap.Size);
  1302. For P in Self do
  1303. begin
  1304. Result[i]:=P;
  1305. Inc(I);
  1306. End;
  1307. end;
  1308. { TDictionary.TKeyCollection }
  1309. function TDictionary<TKey, TValue>.TKeyCollection.GetCount: Integer;
  1310. begin
  1311. Result:=FMap.Size;
  1312. end;
  1313. function TDictionary<TKey, TValue>.TKeyCollection.DoGetEnumerator: TEnumerator<TKey>;
  1314. begin
  1315. Result:=GetEnumerator;
  1316. end;
  1317. constructor TDictionary<TKey, TValue>.TKeyCollection.Create(const ADictionary: TMyType);
  1318. begin
  1319. FMap:=aDictionary.FMap;
  1320. end;
  1321. function TDictionary<TKey, TValue>.TKeyCollection.GetEnumerator: TKeyEnumerator;
  1322. begin
  1323. Result:=TKeyEnumerator.Create(FMap.Keys);
  1324. end;
  1325. function TDictionary<TKey, TValue>.TKeyCollection.ToArray: TArray<TKey>;
  1326. begin
  1327. Result:=inherited ToArray;
  1328. end;
  1329. { TObjectList<T> }
  1330. procedure TObjectList<T>.Notify(const aValue: T; Action: TCollectionNotification);
  1331. Var
  1332. A : TObject absolute aValue; // needed to fool compiler
  1333. begin
  1334. inherited Notify(aValue, Action);
  1335. if FObjectsOwner and (action = cnRemoved) then
  1336. a.Free;
  1337. end;
  1338. constructor TObjectList<T>.Create(AOwnsObjects: Boolean);
  1339. begin
  1340. inherited Create;
  1341. FObjectsOwner := AOwnsObjects;
  1342. end;
  1343. constructor TObjectList<T>.Create(const AComparer: IComparer<T>; AOwnsObjects: Boolean);
  1344. begin
  1345. inherited Create(AComparer);
  1346. FObjectsOwner := AOwnsObjects;
  1347. end;
  1348. constructor TObjectList<T>.Create(const ACollection: TEnumerable<T>; aOwnsObjects: Boolean);
  1349. begin
  1350. inherited Create(ACollection);
  1351. FObjectsOwner := AOwnsObjects;
  1352. end;
  1353. { TThreadList }
  1354. constructor TThreadList<T>.Create;
  1355. begin
  1356. inherited Create;
  1357. FLock:=0;
  1358. FList := TList<T>.Create;
  1359. FDuplicates := dupIgnore;
  1360. end;
  1361. destructor TThreadList<T>.Destroy;
  1362. begin
  1363. // No need to unlock.
  1364. FList.Free;
  1365. inherited Destroy;
  1366. end;
  1367. procedure TThreadList<T>.Add(const Item: T);
  1368. begin
  1369. LockList;
  1370. try
  1371. if (Duplicates = dupAccept) or (FList.IndexOf(Item) = -1) then
  1372. FList.Add(Item)
  1373. else if Duplicates = dupError then
  1374. raise EListError.Create(SDuplicateItem);
  1375. finally
  1376. UnlockList;
  1377. end;
  1378. end;
  1379. procedure TThreadList<T>.Clear;
  1380. begin
  1381. LockList;
  1382. try
  1383. FList.Clear;
  1384. finally
  1385. UnlockList;
  1386. end;
  1387. end;
  1388. function TThreadList<T>.LockList: TList<T>;
  1389. begin
  1390. Inc(FLock);
  1391. if (FLock>1) then
  1392. Writeln('Locking already locked list, lockcount : ',FLock);
  1393. Result:=FList;
  1394. end;
  1395. procedure TThreadList<T>.Remove(const Item: T);
  1396. begin
  1397. RemoveItem(T,TDirection.FromBeginning);
  1398. end;
  1399. procedure TThreadList<T>.RemoveItem(const Item: T; Direction: TDirection);
  1400. begin
  1401. LockList;
  1402. try
  1403. FList.RemoveItem(T,Direction);
  1404. finally
  1405. UnlockList;
  1406. end;
  1407. end;
  1408. procedure TThreadList<T>.UnlockList;
  1409. begin
  1410. Dec(FLock);
  1411. if (FLock<0) then
  1412. Writeln('Unlocking already unlocked list, lockcount : ',FLock);
  1413. end;
  1414. { TObjectDictionary }
  1415. function TObjectDictionary<TKey, TValue>.CanClearMap: Boolean;
  1416. begin
  1417. Result:=(Inherited CanClearMap) and (FOwnerships=[]);
  1418. end;
  1419. procedure TObjectDictionary<TKey, TValue>.KeyNotify(const Key: TKey; Action: TCollectionNotification);
  1420. Var
  1421. A : TObject absolute key; // Avoid typecast, refused by compiler
  1422. begin
  1423. inherited KeyNotify(Key, Action);
  1424. if (doOwnsKeys in FOwnerships) and (Action = cnRemoved) then
  1425. A.Free;
  1426. end;
  1427. procedure TObjectDictionary<TKey, TValue>.ValueNotify(const Value: TValue; Action: TCollectionNotification);
  1428. Var
  1429. A : TObject absolute Value; // Avoid typecast, refused by compiler
  1430. begin
  1431. inherited ValueNotify(Value, Action);
  1432. if (doOwnsValues in FOwnerships) and (Action = cnRemoved) then
  1433. A.Free;
  1434. end;
  1435. constructor TObjectDictionary<TKey, TValue>.Create(aOwnerships: TDictionaryOwnerships; ACapacity: Integer);
  1436. begin
  1437. Create(aOwnerShips);
  1438. end;
  1439. constructor TObjectDictionary<TKey, TValue>.Create(aOwnerships: TDictionaryOwnerships);
  1440. begin
  1441. Inherited Create;
  1442. FOwnerShips:=aOwnerships;
  1443. end;
  1444. { TQueue }
  1445. function TQueue<T>.DoGetEnumerator: TEnumerator<T>;
  1446. begin
  1447. Result:=GetEnumerator;
  1448. end;
  1449. function TQueue<T>.GetEnumerator: TEnumerator;
  1450. begin
  1451. Result := TEnumerator.Create(Self);
  1452. end;
  1453. procedure TQueue<T>.SetCapacity(AValue: SizeInt);
  1454. begin
  1455. if AValue < Count then
  1456. raise EArgumentOutOfRangeException.Create(SArgumentOutOfRange);
  1457. if FLow>0 then
  1458. Rebase;
  1459. SetLength(FItems,aValue);
  1460. end;
  1461. function TQueue<T>.DoRemove(AIndex: SizeInt; ACollectionNotification: TCollectionNotification): T;
  1462. begin
  1463. if (FLow>=FLength) then
  1464. raise EArgumentOutOfRangeException.Create(SArgumentOutOfRange);
  1465. Result := FItems[AIndex];
  1466. FItems[AIndex] := Default(T);
  1467. Inc(FLow);
  1468. if FLow >= FLength then
  1469. begin
  1470. FLow:=0;
  1471. FLength:=0;
  1472. end;
  1473. Notify(Result, ACollectionNotification);
  1474. end;
  1475. function TQueue<T>.GetCount: SizeInt;
  1476. begin
  1477. Result:=FLength-FLow;
  1478. end;
  1479. constructor TQueue<T>.Create;
  1480. begin
  1481. FMaxGapLength:=10;
  1482. end;
  1483. constructor TQueue<T>.Create(ACollection: TEnumerable<T>);
  1484. var
  1485. Itm: T;
  1486. begin
  1487. Create;
  1488. for Itm in ACollection do
  1489. Enqueue(Itm);
  1490. end;
  1491. destructor TQueue<T>.Destroy;
  1492. begin
  1493. Clear;
  1494. inherited Destroy;
  1495. end;
  1496. procedure TQueue<T>.Enqueue(const AValue: T);
  1497. begin
  1498. if Capacity<=FLength then
  1499. SetCapacity(FLength+10);
  1500. FItems[FLength]:=aValue;
  1501. Inc(FLength);
  1502. Notify(aValue,cnAdded);
  1503. end;
  1504. function TQueue<T>.Dequeue: T;
  1505. begin
  1506. Result := DoRemove(FLow, cnRemoved);
  1507. if FLow>FMaxGapLength then
  1508. Rebase;
  1509. end;
  1510. function TQueue<T>.Extract: T;
  1511. begin
  1512. Result := DoRemove(FLow, cnExtracted);
  1513. if FLow>FMaxGapLength then
  1514. Rebase;
  1515. end;
  1516. function TQueue<T>.Peek: T;
  1517. begin
  1518. if (Count=0) then
  1519. raise EArgumentOutOfRangeException.Create(SArgumentOutOfRange);
  1520. Result:=FItems[FLow];
  1521. end;
  1522. procedure TQueue<T>.Clear;
  1523. begin
  1524. while Count <> 0 do
  1525. Dequeue;
  1526. end;
  1527. procedure TQueue<T>.Rebase;
  1528. Var
  1529. I,Spare : integer;
  1530. begin
  1531. Spare:=Capacity-Count;
  1532. if FLow>0 then
  1533. begin
  1534. For I:=Flow to FLength do
  1535. FItems[I-FLow]:=FItems[I];
  1536. SetLength(FItems,FLength+Spare);
  1537. FLength:=FLength-Flow+1;
  1538. Flow:=0;
  1539. end;
  1540. end;
  1541. procedure TQueue<T>.TrimExcess;
  1542. begin
  1543. Rebase;
  1544. SetCapacity(Count);
  1545. end;
  1546. { TQueue.TEnumerator }
  1547. constructor TQueue<T>.TEnumerator.Create(AQueue: TMyType);
  1548. begin
  1549. aQueue.Rebase;
  1550. Inherited Create(aQueue);
  1551. end;
  1552. { TObjectQueue }
  1553. procedure TObjectQueue<T>.Notify(const Value: T; Action: TCollectionNotification);
  1554. Var
  1555. A : TObject absolute Value;
  1556. begin
  1557. inherited Notify(Value, Action);
  1558. if OwnsObjects and (Action = cnRemoved) then
  1559. A.Free;
  1560. end;
  1561. constructor TObjectQueue<T>.Create(AOwnsObjects: Boolean);
  1562. begin
  1563. Inherited create;
  1564. FOwnsObjects:=aOwnsObjects;
  1565. end;
  1566. constructor TObjectQueue<T>.Create(const Collection: TEnumerable<T>; AOwnsObjects: Boolean);
  1567. Var
  1568. A : T;
  1569. begin
  1570. Create(aOwnsObjects);
  1571. For A in Collection do
  1572. EnQueue(A);
  1573. end;
  1574. procedure TObjectQueue<T>.Dequeue;
  1575. begin
  1576. Inherited DeQueue;
  1577. end;
  1578. { TStack }
  1579. function TStack<T>.DoRemove(aIndex : SizeInt; ACollectionNotification: TCollectionNotification): T;
  1580. begin
  1581. if (FLength=0) or (aIndex<>FLength-1) then
  1582. raise EArgumentOutOfRangeException.Create(SArgumentOutOfRange);
  1583. Result:=FItems[AIndex];
  1584. FItems[AIndex] := Default(T);
  1585. Dec(FLength);
  1586. Notify(Result, ACollectionNotification);
  1587. end;
  1588. procedure TStack<T>.SetCapacity(aValue: SizeInt);
  1589. begin
  1590. if AValue < Count then
  1591. raise EArgumentOutOfRangeException.Create(SArgumentOutOfRange);
  1592. SetLength(FItems,aValue);
  1593. end;
  1594. function TStack<T>.DoGetEnumerator: TEnumerator<T>;
  1595. begin
  1596. Result:=GetEnumerator;
  1597. end;
  1598. function TStack<T>.GetEnumerator: TEnumerator;
  1599. begin
  1600. Result:=TEnumerator.Create(Self);
  1601. end;
  1602. destructor TStack<T>.Destroy;
  1603. begin
  1604. Clear;
  1605. inherited Destroy;
  1606. end;
  1607. procedure TStack<T>.Clear;
  1608. begin
  1609. While Count>0 do Pop;
  1610. end;
  1611. procedure TStack<T>.Push(const aValue: T);
  1612. begin
  1613. if Capacity<=FLength then
  1614. SetCapacity(FLength+10);
  1615. FItems[FLength]:=aValue;
  1616. Inc(FLength);
  1617. Notify(aValue,cnAdded);
  1618. end;
  1619. function TStack<T>.Pop: T;
  1620. begin
  1621. Result:=DoRemove(FLength-1,cnRemoved);
  1622. end;
  1623. function TStack<T>.Peek: T;
  1624. begin
  1625. if Count<1 then
  1626. raise EArgumentOutOfRangeException.Create(SArgumentOutOfRange);
  1627. Result:=FItems[FLength-1];
  1628. end;
  1629. function TStack<T>.Extract: T;
  1630. begin
  1631. Result:=DoRemove(FLength-1,cnExtracted);
  1632. end;
  1633. procedure TStack<T>.TrimExcess;
  1634. begin
  1635. SetCapacity(FLength);
  1636. end;
  1637. { TCustomInvertedListEnumerator }
  1638. function TCustomInvertedListEnumerator<T>.DoMoveNext: boolean;
  1639. begin
  1640. Result:=FIndex>0;
  1641. If Result then
  1642. Dec(FIndex);
  1643. end;
  1644. function TCustomInvertedListEnumerator<T>.DoGetCurrent: T;
  1645. begin
  1646. Result:=FList.FItems[FIndex];
  1647. end;
  1648. function TCustomInvertedListEnumerator<T>.GetCurrent: T;
  1649. begin
  1650. Result:=DoGetCurrent;
  1651. end;
  1652. constructor TCustomInvertedListEnumerator<T>.Create(AList: TCustomList<T>);
  1653. begin
  1654. inherited Create;
  1655. FList:=AList;
  1656. FIndex:=AList.FLength;
  1657. end;
  1658. { TStack.TEnumerator }
  1659. constructor TStack<T>.TEnumerator.Create(AStack: TMyType);
  1660. begin
  1661. Inherited Create(aStack);
  1662. end;
  1663. { TObjectStack }
  1664. procedure TObjectStack<T>.Notify(const aValue: T; Action: TCollectionNotification);
  1665. Var
  1666. A : T absolute aValue;
  1667. begin
  1668. inherited Notify(aValue, Action);
  1669. if (Action=cnRemoved) and FOwnsObjects then
  1670. a.Free;
  1671. end;
  1672. constructor TObjectStack<T>.Create(AOwnsObjects: Boolean);
  1673. begin
  1674. Inherited Create;
  1675. FOwnsObjects:=aOwnsObjects;
  1676. end;
  1677. constructor TObjectStack<T>.Create(const Collection: TEnumerable<T>; AOwnsObjects: Boolean);
  1678. Var
  1679. A : T;
  1680. begin
  1681. Create(aOwnsObjects);
  1682. For A in Collection do
  1683. Push(A);
  1684. end;
  1685. procedure TObjectStack<T>.Pop;
  1686. begin
  1687. Inherited Pop;
  1688. end;
  1689. end.