You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1722 regels
69 KiB

  1. unit uutlGenerics;
  2. {$mode objfpc}{$H+}
  3. interface
  4. uses
  5. Classes, SysUtils, typinfo,
  6. uutlCommon, uutlArrayContainer, uutlListBase, uutlComparer, uutlAlgorithm, uutlInterfaces,
  7. uutlEnumerator;
  8. type
  9. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  10. generic TutlQueue<T> = class(
  11. specialize TutlArrayContainer<T>
  12. , specialize IEnumerable<T>
  13. , specialize IutlEnumerable<T>
  14. , specialize IutlReadOnlyArray<T>)
  15. private type
  16. TEnumerator = class(
  17. specialize TutlEnumerator<T>
  18. , specialize IEnumerator<T>
  19. , specialize IutlEnumerator<T>)
  20. strict private
  21. fOwner: TutlQueue;
  22. fCurrent: Integer;
  23. protected { TutlEnumerator }
  24. function InternalMoveNext: Boolean; override;
  25. procedure InternalReset; override;
  26. public { IEnumerator }
  27. function GetCurrent: T; override;
  28. public
  29. constructor Create(const aOwner: TutlQueue);
  30. end;
  31. public type
  32. IEnumerator = specialize IEnumerator<T>;
  33. IutlEnumerator = specialize IutlEnumerator<T>;
  34. strict private
  35. fCount: Integer;
  36. fReadPos: Integer;
  37. fWritePos: Integer;
  38. function GetItem(const aIndex: Integer): T;
  39. procedure SetItem(const aIndex: Integer; aItem: T);
  40. protected
  41. function GetCount: Integer; override;
  42. procedure SetCount(const aValue: Integer); override;
  43. procedure SetCapacity(const aValue: integer); override;
  44. public { IEnumerable }
  45. function GetEnumerator: IEnumerator;
  46. public { IutlEnumerable }
  47. function GetUtlEnumerator: IutlEnumerator;
  48. public
  49. property Count: Integer read GetCount;
  50. property IsEmpty;
  51. property Capacity;
  52. property CanExpand;
  53. property CanShrink;
  54. property OwnsItems;
  55. property Items[const aIndex: Integer]: T read GetItem write SetItem; default;
  56. procedure Enqueue(constref aItem: T);
  57. function Dequeue: T;
  58. function Dequeue(const aFreeItem: Boolean): T;
  59. function Peek: T;
  60. procedure ShrinkToFit;
  61. procedure Clear;
  62. constructor Create(const aOwnsItems: Boolean);
  63. destructor Destroy; override;
  64. end;
  65. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  66. generic TutlStack<T> = class(
  67. specialize TutlArrayContainer<T>
  68. , specialize IEnumerable<T>
  69. , specialize IutlEnumerable<T>
  70. , specialize IutlReadOnlyArray<T>)
  71. private type
  72. TEnumerator = class(
  73. specialize TutlMemoryEnumerator<T>
  74. , specialize IEnumerator<T>
  75. , specialize IutlEnumerator<T>)
  76. private
  77. fOwner: TutlStack;
  78. public { IEnumerator }
  79. procedure InternalReset; override;
  80. public
  81. constructor Create(const aOwner: TutlStack); reintroduce;
  82. end;
  83. public type
  84. IEnumerator = specialize IEnumerator<T>;
  85. IutlEnumerator = specialize IutlEnumerator<T>;
  86. strict private
  87. fCount: Integer;
  88. function GetItem(const aIndex: Integer): T;
  89. procedure SetItem(const aIndex: Integer; aValue: T);
  90. protected
  91. function GetCount: Integer; override;
  92. procedure SetCount(const aValue: Integer); override;
  93. public { IEnumerable }
  94. function GetEnumerator: IEnumerator;
  95. public { IutlEnumerable }
  96. function GetUtlEnumerator: IutlEnumerator;
  97. public
  98. property Count: Integer read GetCount;
  99. property IsEmpty;
  100. property Capacity;
  101. property CanExpand;
  102. property CanShrink;
  103. property OwnsItems;
  104. property Items[const aIndex: Integer]: T read GetItem write SetItem; default;
  105. procedure Push(constref aItem: T);
  106. function Pop: T;
  107. function Pop(const aFreeItem: Boolean): T;
  108. function Peek: T;
  109. procedure ShrinkToFit;
  110. procedure Clear;
  111. constructor Create(const aOwnsItems: Boolean);
  112. destructor Destroy; override;
  113. end;
  114. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  115. generic TutlSimpleList<T> = class(
  116. specialize TutlListBase<T>
  117. , specialize IutlReadOnlyArray<T>
  118. , specialize IutlArray<T>)
  119. strict private
  120. function GetFirst: T;
  121. function GetLast: T;
  122. public
  123. property First: T read GetFirst;
  124. property Last: T read GetLast;
  125. property Items[const aIndex: Integer]: T read GetItem write SetItem; default;
  126. function Add (constref aItem: T): Integer;
  127. procedure Insert (const aIndex: Integer; constref aItem: T);
  128. procedure Exchange (const aIndex1, aIndex2: Integer);
  129. procedure Move (const aCurrentIndex, aNewIndex: Integer);
  130. procedure Delete (const aIndex: Integer);
  131. function Extract (const aIndex: Integer): T;
  132. procedure PushFirst (constref aItem: T);
  133. function PopFirst (const aFreeItem: Boolean): T;
  134. procedure PushLast (constref aItem: T);
  135. function PopLast (const aFreeItem: Boolean): T;
  136. end;
  137. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  138. generic TutlCustomList<T> = class(
  139. specialize TutlSimpleList<T>)
  140. public type
  141. IEqualityComparer = specialize IutlEqualityComparer<T>;
  142. strict private
  143. fEqualityComparer: IEqualityComparer;
  144. public
  145. function IndexOf (const aItem: T): Integer;
  146. function Extract (const aItem: T; const aDefault: T): T; overload;
  147. function Remove (const aItem: T): Integer;
  148. constructor Create (const aEqualityComparer: IEqualityComparer; const aOwnsItems: Boolean);
  149. destructor Destroy; override;
  150. end;
  151. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  152. generic TutlList<T> = class(
  153. specialize TutlCustomList<T>)
  154. public type
  155. TEqualityComparer = specialize TutlEqualityComparer<T>;
  156. public
  157. constructor Create(const aOwnsItems: Boolean);
  158. end;
  159. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  160. generic TutlCustomHashSet<T> = class(
  161. specialize TutlListBase<T>
  162. , specialize IutlReadOnlyArray<T>)
  163. private type
  164. TBinarySearch = specialize TutlBinarySearch<T>;
  165. public type
  166. IComparer = specialize IutlComparer<T>;
  167. strict private
  168. fComparer: IComparer;
  169. protected
  170. procedure SetCount (const aValue: Integer); override;
  171. procedure SetItem (const aIndex: Integer; aValue: T); override;
  172. public
  173. property Count: Integer read GetCount;
  174. property Items[const aIndex: Integer]: T read GetItem write SetItem; default;
  175. function Add (constref aItem: T): Boolean;
  176. function Contains (constref aItem: T): Boolean;
  177. function IndexOf (constref aItem: T): Integer;
  178. function Remove (constref aItem: T): Boolean;
  179. procedure Delete (const aIndex: Integer);
  180. constructor Create (const aComparer: IComparer; const aOwnsItems: Boolean);
  181. destructor Destroy; override;
  182. end;
  183. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  184. generic TutlHashSet<T> = class(
  185. specialize TutlCustomHashSet<T>)
  186. public type
  187. TComparer = specialize TutlComparer<T>;
  188. public
  189. constructor Create(const aOwnsItems: Boolean);
  190. end;
  191. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  192. generic TutlCustomMap<TKey, TValue> = class(
  193. TutlInterfaceNoRefCount
  194. , specialize IutlEnumerable<TValue>)
  195. public type
  196. ////////////////////////////////////////////////////////////////////////////////////////////////
  197. TKeyValuePair = packed record
  198. Key: TKey;
  199. Value: TValue;
  200. end;
  201. ////////////////////////////////////////////////////////////////////////////////////////////////
  202. IValueEnumerator = specialize IEnumerator<TValue>;
  203. IutlValueEnumerator = specialize IutlEnumerator<TValue>;
  204. IKeyEnumerator = specialize IEnumerator<TKey>;
  205. IutlKeyEnumerator = specialize IutlEnumerator<TKey>;
  206. IKeyValuePairEnumerator = specialize IEnumerator<TKeyValuePair>;
  207. IutlKeyValuePairEnumerator = specialize IutlEnumerator<TKeyValuePair>;
  208. ////////////////////////////////////////////////////////////////////////////////////////////////
  209. THashSet = class(
  210. specialize TutlCustomHashSet<TKeyValuePair>)
  211. strict private
  212. fOwner: TutlCustomMap;
  213. protected
  214. procedure Release(var aItem: TKeyValuePair; const aFreeItem: Boolean); override;
  215. public
  216. constructor Create(const aOwner: TutlCustomMap; const aComparer: IComparer);
  217. end;
  218. ////////////////////////////////////////////////////////////////////////////////////////////////
  219. IComparer = specialize IutlComparer<TKey>;
  220. TKeyValuePairComparer = class(
  221. TInterfacedObject
  222. , THashSet.IComparer)
  223. strict private
  224. fComparer: IComparer;
  225. public { IutlEqualityComparer }
  226. function EqualityCompare(constref i1, i2: TKeyValuePair): Boolean;
  227. public { IutlComparer }
  228. function Compare(constref i1, i2: TKeyValuePair): Integer;
  229. public
  230. constructor Create(aComparer: IComparer);
  231. destructor Destroy; override;
  232. end;
  233. ////////////////////////////////////////////////////////////////////////////////////////////////
  234. TKeyEnumerator = class(
  235. specialize TutlEnumerator<TKey>
  236. , IKeyEnumerator
  237. , IutlKeyEnumerator)
  238. strict private
  239. fEnumerator: IutlKeyValuePairEnumerator;
  240. protected { TutlEnumerator }
  241. function InternalMoveNext: Boolean; override;
  242. procedure InternalReset; override;
  243. public { IEnumerator }
  244. function GetCurrent: TKey; override;
  245. public
  246. constructor Create(aEnumerator: IutlKeyValuePairEnumerator);
  247. end;
  248. ////////////////////////////////////////////////////////////////////////////////////////////////
  249. TValueEnumerator = class(
  250. specialize TutlEnumerator<TValue>
  251. , IValueEnumerator
  252. , IutlValueEnumerator)
  253. strict private
  254. fEnumerator: IutlKeyValuePairEnumerator;
  255. protected { TutlEnumerator }
  256. function InternalMoveNext: Boolean; override;
  257. procedure InternalReset; override;
  258. public { IEnumerator }
  259. function GetCurrent: TValue; override;
  260. public
  261. constructor Create(aEnumerator: IutlKeyValuePairEnumerator);
  262. end;
  263. ////////////////////////////////////////////////////////////////////////////////////////////////
  264. TKeyCollection = class(
  265. TutlInterfaceNoRefCount
  266. , specialize IutlReadOnlyArray<TKey>
  267. , specialize IutlEnumerable<TKey>)
  268. strict private
  269. fHashSet: THashSet;
  270. public { IEnumerable }
  271. function GetEnumerator: IKeyEnumerator;
  272. public { IutlEnumerable }
  273. function GetUtlEnumerator: IutlKeyEnumerator;
  274. public { IutlReadOnlyArray }
  275. function GetCount: Integer;
  276. function GetItem(const aIndex: Integer): TKey;
  277. property Count: Integer read GetCount;
  278. property Items[const aIndex: Integer]: TKey read GetItem; default;
  279. public
  280. constructor Create(const aHashSet: THashSet);
  281. end;
  282. ////////////////////////////////////////////////////////////////////////////////////////////////
  283. TKeyValuePairCollection = class(
  284. TutlInterfaceNoRefCount
  285. , specialize IutlReadOnlyArray<TKeyValuePair>
  286. , specialize IutlEnumerable<TKeyValuePair>)
  287. strict private
  288. fHashSet: THashSet;
  289. public { IEnumerable }
  290. function GetEnumerator: IKeyValuePairEnumerator;
  291. public { IutlEnumerable }
  292. function GetUtlEnumerator: IutlKeyValuePairEnumerator;
  293. public { IutlReadOnlyArray }
  294. function GetCount: Integer;
  295. function GetItem(const aIndex: Integer): TKeyValuePair;
  296. property Count: Integer read GetCount;
  297. property Items[const aIndex: Integer]: TKeyValuePair read GetItem; default;
  298. public
  299. constructor Create(const aHashSet: THashSet);
  300. end;
  301. strict private
  302. fAutoCreate: Boolean;
  303. fOwnsKeys: Boolean;
  304. fOwnsValues: Boolean;
  305. fHashSetRef: THashSet;
  306. fKeyCollection: TKeyCollection;
  307. fKeyValuePairCollection: TKeyValuePairCollection;
  308. function GetValue (aKey: TKey): TValue; inline;
  309. function GetValueAt (const aIndex: Integer): TValue; inline;
  310. function GetCount: Integer; inline;
  311. function GetIsEmpty: Boolean; inline;
  312. function GetCapacity: Integer; inline;
  313. function GetCanShrink: Boolean; inline;
  314. function GetCanExpand: Boolean; inline;
  315. procedure SetCapacity (const aValue: Integer); inline;
  316. procedure SetCanShrink (const aValue: Boolean); inline;
  317. procedure SetCanExpand (const aValue: Boolean); inline;
  318. protected
  319. procedure SetValue (aKey: TKey; const aValue: TValue); virtual;
  320. procedure SetValueAt (const aIndex: Integer; const aValue: TValue); virtual;
  321. public { IEnumerable }
  322. function GetEnumerator: IValueEnumerator;
  323. public { IutlEnumerable }
  324. function GetUtlEnumerator: IutlValueEnumerator;
  325. public
  326. property Values [aKey: TKey]: TValue read GetValue write SetValue; default;
  327. property ValueAt[const aIndex: Integer]: TValue read GetValueAt write SetValueAt;
  328. property Keys: TKeyCollection read fKeyCollection;
  329. property KeyValuePairs: TKeyValuePairCollection read fKeyValuePairCollection;
  330. property Count: Integer read GetCount;
  331. property IsEmpty: Boolean read GetIsEmpty;
  332. property Capacity: Integer read GetCapacity write SetCapacity;
  333. property CanShrink: Boolean read GetCanShrink write SetCanShrink;
  334. property CanExpand: Boolean read GetCanExpand write SetCanExpand;
  335. property OwnsKeys: Boolean read fOwnsKeys write fOwnsKeys;
  336. property OwnsValues: Boolean read fOwnsValues write fOwnsValues;
  337. property AutoCreate: Boolean read fAutoCreate write fAutoCreate;
  338. procedure Add (constref aKey: TKey; constref aValue: TValue);
  339. function TryAdd (constref aKey: TKey; constref aValue: TValue): Boolean;
  340. function TryGetValue (constref aKey: TKey; out aValue: TValue): Boolean;
  341. function IndexOf (constref aKey: TKey): Integer;
  342. function Contains (constref aKey: TKey): Boolean;
  343. procedure Delete (constref aKey: TKey);
  344. procedure DeleteAt (const aIndex: Integer);
  345. procedure Clear;
  346. constructor Create(const aHashSet: THashSet; const aOwnsKeys: Boolean; const aOwnsValues: Boolean);
  347. destructor Destroy; override;
  348. end;
  349. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  350. generic TutlMap<TKey, TValue> = class(
  351. specialize TutlCustomMap<TKey, TValue>)
  352. public type
  353. TComparer = specialize TutlComparer<TKey>;
  354. strict private
  355. fHashSetImpl: THashSet;
  356. public
  357. constructor Create(const aOwnsKeys: Boolean; const aOwnsValues: Boolean);
  358. destructor Destroy; override;
  359. end;
  360. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  361. EEnumConvertException = class(EConvertError)
  362. public
  363. constructor Create(const aValue, aExpectedType: String);
  364. end;
  365. generic TutlEnumHelper<T> = class
  366. public type
  367. TEnumType = T;
  368. TValueArray = array of T;
  369. TStringArray = array of String;
  370. private class var
  371. fTypeInfo: PTypeInfo;
  372. fValues: TValueArray;
  373. fNames: TStringArray;
  374. public
  375. class function ToString (aValue: T): String; reintroduce;
  376. class function TryToEnum (aStr: String; out aValue: T): Boolean;
  377. class function ToEnum (aStr: String): T; overload;
  378. class function ToEnum (aStr: String; const aDefault: T): T; overload;
  379. class function Values: TValueArray; inline;
  380. class function Names: TStringArray; inline;
  381. class function TypeInfo: PTypeInfo; inline;
  382. class constructor Initialize;
  383. end;
  384. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  385. generic TutlSetHelper<TEnum, TSet> = class
  386. public type
  387. TEnumHelper = specialize TutlEnumHelper<TEnum>;
  388. TEnumType = TEnum;
  389. TSetType = TSet;
  390. private
  391. class function IsSet (constref aSet: TSet; aEnum: TEnum): Boolean;
  392. class procedure SetValue (var aSet: TSet; aEnum: TEnum);
  393. class procedure ClearValue(var aSet: TSet; aEnum: TEnum);
  394. public
  395. class function ToString (const aValue: TSet; const aSeperator: String = ', '): String; reintroduce;
  396. class function TryToSet (const aStr: String; out aValue: TSet): Boolean; overload;
  397. class function TryToSet (const aStr: String; const aSeperator: String; out aValue: TSet): Boolean; overload;
  398. class function ToSet (const aStr: String; const aDefault: TSet): TSet; overload;
  399. class function ToSet (const aStr: String): TSet; overload;
  400. class function Compare (const aSet1, aSet2: TSet): Integer;
  401. end;
  402. implementation
  403. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  404. //TutlQueue.TEnumerator/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  405. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  406. function TutlQueue.TEnumerator.InternalMoveNext: Boolean;
  407. begin
  408. inc(fCurrent);
  409. result := (fCurrent < fOwner.Count);
  410. end;
  411. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  412. procedure TutlQueue.TEnumerator.InternalReset;
  413. begin
  414. fCurrent := -1;
  415. end;
  416. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  417. function TutlQueue.TEnumerator.GetCurrent: T;
  418. begin
  419. result := fOwner[fCurrent];
  420. end;
  421. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  422. constructor TutlQueue.TEnumerator.Create(const aOwner: TutlQueue);
  423. begin
  424. if not Assigned(aOwner) then
  425. raise EArgumentNilException.Create('aOwner');
  426. fOwner := aOwner;
  427. inherited Create;
  428. end;
  429. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  430. //TutlQueue/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  431. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  432. function TutlQueue.GetItem(const aIndex: Integer): T;
  433. var
  434. i: Integer;
  435. begin
  436. if (aIndex < 0) or (aIndex >= fCount) then
  437. raise EOutOfRangeException.Create(aIndex, 0, fCount-1);
  438. i := fReadPos + aIndex;
  439. if (i >= Capacity) then
  440. i := i - Capacity;
  441. result := GetInternalItem(i)^;
  442. end;
  443. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  444. procedure TutlQueue.SetItem(const aIndex: Integer; aItem: T);
  445. var
  446. i: Integer;
  447. begin
  448. if (aIndex < 0) or (aIndex >= fCount) then
  449. raise EOutOfRangeException.Create(aIndex, 0, fCount-1);
  450. i := fReadPos + aIndex;
  451. if (i >= Capacity) then
  452. i := i - Capacity;
  453. GetInternalItem(i)^ := aItem;
  454. end;
  455. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  456. function TutlQueue.GetCount: Integer;
  457. begin
  458. result := fCount;
  459. end;
  460. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  461. procedure TutlQueue.SetCount(const aValue: Integer);
  462. begin
  463. raise ENotSupportedException.Create('SetCount not supported');
  464. end;
  465. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  466. procedure TutlQueue.SetCapacity(const aValue: integer);
  467. var
  468. cnt: Integer;
  469. begin
  470. if (aValue < Count) then
  471. raise EArgumentException.Create('can not reduce capacity below count');
  472. if (aValue < Capacity) then begin // is shrinking
  473. if (fReadPos <= fWritePos) then begin // ReadPos Before WritePos -> Move To Begin
  474. System.Move(GetInternalItem(fReadPos)^, GetInternalItem(0)^, SizeOf(T) * Count);
  475. fReadPos := 0;
  476. fWritePos := Count;
  477. end else if (fReadPos > fWritePos) then begin // ReadPos Behind WritePos
  478. cnt := Capacity - aValue;
  479. System.Move(GetInternalItem(fReadPos)^, GetInternalItem(fReadPos - cnt)^, SizeOf(T) * cnt);
  480. dec(fReadPos, cnt);
  481. end;
  482. end;
  483. inherited SetCapacity(aValue);
  484. // ReadPos After WritePos and Expanding
  485. if (fReadPos > fWritePos) and (aValue > Capacity) then begin
  486. cnt := aValue - Capacity;
  487. System.Move(GetInternalItem(fReadPos)^, GetInternalItem(fReadPos - cnt)^, SizeOf(T) * cnt);
  488. inc(fReadPos, cnt);
  489. end;
  490. end;
  491. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  492. function TutlQueue.GetEnumerator: IEnumerator;
  493. begin
  494. result := TEnumerator.Create(self);
  495. result.Reset;
  496. end;
  497. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  498. function TutlQueue.GetUtlEnumerator: IutlEnumerator;
  499. begin
  500. result := TEnumerator.Create(self);
  501. result.Reset;
  502. end;
  503. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  504. procedure TutlQueue.Enqueue(constref aItem: T);
  505. begin
  506. if (Count = Capacity) then
  507. Expand;
  508. fWritePos := fWritePos mod Capacity;
  509. GetInternalItem(fWritePos)^ := aItem;
  510. inc(fCount);
  511. inc(fWritePos);
  512. end;
  513. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  514. function TutlQueue.Dequeue: T;
  515. begin
  516. result := Dequeue(false);
  517. end;
  518. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  519. function TutlQueue.Dequeue(const aFreeItem: Boolean): T;
  520. var
  521. p: PT;
  522. begin
  523. if IsEmpty then
  524. raise EInvalidOperation.Create('queue is empty');
  525. p := GetInternalItem(fReadPos);
  526. if aFreeItem
  527. then FillByte(result{%H-}, SizeOf(result), 0)
  528. else result := p^;
  529. Release(p^, aFreeItem);
  530. dec(fCount);
  531. fReadPos := (fReadPos + 1) mod Capacity;
  532. end;
  533. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  534. function TutlQueue.Peek: T;
  535. begin
  536. if IsEmpty then
  537. raise EInvalidOperation.Create('queue is empty');
  538. result := GetInternalItem(fReadPos)^;
  539. end;
  540. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  541. procedure TutlQueue.ShrinkToFit;
  542. begin
  543. Shrink(true);
  544. end;
  545. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  546. procedure TutlQueue.Clear;
  547. begin
  548. while (fReadPos <> fWritePos) do begin
  549. Release(GetInternalItem(fReadPos)^, true);
  550. fReadPos := (fReadPos + 1) mod Capacity;
  551. end;
  552. fCount := 0;
  553. if CanShrink then
  554. ShrinkToFit;
  555. end;
  556. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  557. constructor TutlQueue.Create(const aOwnsItems: Boolean);
  558. begin
  559. inherited Create(aOwnsItems);
  560. fCount := 0;
  561. fReadPos := 0;
  562. fWritePos := 0;
  563. end;
  564. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  565. destructor TutlQueue.Destroy;
  566. begin
  567. Clear;
  568. inherited Destroy;
  569. end;
  570. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  571. //TutlStack.TEnumerator/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  572. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  573. procedure TutlStack.TEnumerator.InternalReset;
  574. begin
  575. First := 0;
  576. Last := fOwner.Count-1;
  577. if (Last >= First)
  578. then Memory := fOwner.GetInternalItem(0)
  579. else Memory := nil;
  580. inherited InternalReset;
  581. end;
  582. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  583. constructor TutlStack.TEnumerator.Create(const aOwner: TutlStack);
  584. begin
  585. if not Assigned(aOwner) then
  586. raise EArgumentNilException.Create('aOwner');
  587. fOwner := aOwner;
  588. inherited Create(nil, 0);
  589. end;
  590. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  591. //TutlStack/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  592. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  593. function TutlStack.GetItem(const aIndex: Integer): T;
  594. begin
  595. if (aIndex < 0) or (aIndex >= fCount) then
  596. raise EOutOfRangeException.Create(aIndex, 0, fCount-1);
  597. result := GetInternalItem(aIndex)^;
  598. end;
  599. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  600. procedure TutlStack.SetItem(const aIndex: Integer; aValue: T);
  601. begin
  602. if (aIndex < 0) or (aIndex >= fCount) then
  603. raise EOutOfRangeException.Create(aIndex, 0, fCount-1);
  604. GetInternalItem(aIndex)^ := aValue;
  605. end;
  606. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  607. function TutlStack.GetCount: Integer;
  608. begin
  609. result := fCount;
  610. end;
  611. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  612. procedure TutlStack.SetCount(const aValue: Integer);
  613. begin
  614. raise ENotSupportedException.Create('SetCount not supported');
  615. end;
  616. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  617. function TutlStack.GetEnumerator: IEnumerator;
  618. begin
  619. result := TEnumerator.Create(self);
  620. end;
  621. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  622. function TutlStack.GetUtlEnumerator: IutlEnumerator;
  623. begin
  624. result := TEnumerator.Create(self);
  625. end;
  626. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  627. procedure TutlStack.Push(constref aItem: T);
  628. begin
  629. if (Count = Capacity) then
  630. Expand;
  631. GetInternalItem(fCount)^ := aItem;
  632. inc(fCount);
  633. end;
  634. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  635. function TutlStack.Pop: T;
  636. begin
  637. Pop(false);
  638. end;
  639. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  640. function TutlStack.Pop(const aFreeItem: Boolean): T;
  641. var
  642. p: PT;
  643. begin
  644. if IsEmpty then
  645. raise EInvalidOperation.Create('stack is empty');
  646. p := GetInternalItem(fCount-1);
  647. if aFreeItem
  648. then FillByte(result{%H-}, SizeOf(result), 0)
  649. else result := p^;
  650. Release(p^, aFreeItem);
  651. dec(fCount);
  652. end;
  653. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  654. function TutlStack.Peek: T;
  655. begin
  656. if IsEmpty then
  657. raise EInvalidOperation.Create('stack is empty');
  658. result := GetInternalItem(fCount-1)^;
  659. end;
  660. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  661. procedure TutlStack.ShrinkToFit;
  662. begin
  663. Shrink(true);
  664. end;
  665. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  666. procedure TutlStack.Clear;
  667. begin
  668. while (fCount > 0) do begin
  669. dec(fCount);
  670. Release(GetInternalItem(fCount)^, true);
  671. end;
  672. if CanShrink then
  673. ShrinkToFit;
  674. end;
  675. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  676. constructor TutlStack.Create(const aOwnsItems: Boolean);
  677. begin
  678. inherited Create(aOwnsItems);
  679. fCount := 0
  680. end;
  681. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  682. destructor TutlStack.Destroy;
  683. begin
  684. Clear;
  685. inherited Destroy;
  686. end;
  687. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  688. //TutlSimpleList////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  689. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  690. function TutlSimpleList.GetFirst: T;
  691. begin
  692. if IsEmpty then
  693. raise EInvalidOperation.Create('list is empty');
  694. result := GetInternalItem(0)^;
  695. end;
  696. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  697. function TutlSimpleList.GetLast: T;
  698. begin
  699. if IsEmpty then
  700. raise EInvalidOperation.Create('list is empty');
  701. result := GetInternalItem(Count-1)^;
  702. end;
  703. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  704. function TutlSimpleList.Add(constref aItem: T): Integer;
  705. begin
  706. result := Count;
  707. InsertIntern(result, aItem);
  708. end;
  709. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  710. procedure TutlSimpleList.Insert(const aIndex: Integer; constref aItem: T);
  711. begin
  712. InsertIntern(aIndex, aItem);
  713. end;
  714. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  715. procedure TutlSimpleList.Exchange(const aIndex1, aIndex2: Integer);
  716. var
  717. tmp: T;
  718. p1, p2: PT;
  719. begin
  720. if (aIndex1 < 0) or (aIndex1 >= Count) then
  721. raise EOutOfRangeException.Create(aIndex1, 0, Count-1);
  722. if (aIndex2 < 0) or (aIndex2 >= Count) then
  723. raise EOutOfRangeException.Create(aIndex2, 0, Count-1);
  724. p1 := GetInternalItem(aIndex1);
  725. p2 := GetInternalItem(aIndex2);
  726. System.Move(p1^, tmp{%H-}, SizeOf(T));
  727. System.Move(p2^, p1^, SizeOf(T));
  728. System.Move(tmp, p2^, SizeOf(T));
  729. FillByte(tmp, SizeOf(tmp), 0)
  730. end;
  731. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  732. procedure TutlSimpleList.Move(const aCurrentIndex, aNewIndex: Integer);
  733. var
  734. tmp: T;
  735. cur, new: PT;
  736. begin
  737. if (aCurrentIndex < 0) or (aCurrentIndex >= Count) then
  738. raise EOutOfRangeException.Create(aCurrentIndex, 0, Count-1);
  739. if (aNewIndex < 0) or (aNewIndex >= Count) then
  740. raise EOutOfRangeException.Create(aNewIndex, 0, Count-1);
  741. if (aCurrentIndex = aNewIndex) then
  742. exit;
  743. cur := GetInternalItem(aCurrentIndex);
  744. new := GetInternalItem(aNewIndex);
  745. System.Move(cur^, tmp{%H-}, SizeOf(T));
  746. if (aNewIndex > aCurrentIndex) then begin
  747. System.Move((cur+1)^, cur^, SizeOf(T) * (aNewIndex - aCurrentIndex));
  748. end else begin
  749. System.Move(new^, (new+1)^, SizeOf(T) * (aCurrentIndex - aNewIndex));
  750. end;
  751. System.Move(tmp, new^, SizeOf(T));
  752. FillByte(tmp, SizeOf(tmp), 0);
  753. end;
  754. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  755. procedure TutlSimpleList.Delete(const aIndex: Integer);
  756. begin
  757. DeleteIntern(aIndex, true);
  758. end;
  759. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  760. function TutlSimpleList.Extract(const aIndex: Integer): T;
  761. begin
  762. result := GetItem(aIndex);
  763. DeleteIntern(aIndex, false);
  764. end;
  765. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  766. procedure TutlSimpleList.PushFirst(constref aItem: T);
  767. begin
  768. InsertIntern(0, aItem);
  769. end;
  770. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  771. function TutlSimpleList.PopFirst(const aFreeItem: Boolean): T;
  772. begin
  773. if aFreeItem
  774. then FillByte(result{%H-}, SizeOf(result), 0)
  775. else result := GetItem(0);
  776. DeleteIntern(0, aFreeItem);
  777. end;
  778. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  779. procedure TutlSimpleList.PushLast(constref aItem: T);
  780. begin
  781. InsertIntern(Count, aItem);
  782. end;
  783. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  784. function TutlSimpleList.PopLast(const aFreeItem: Boolean): T;
  785. begin
  786. if aFreeItem
  787. then FillByte(result{%H-}, SizeOf(result), 0)
  788. else result := GetItem(Count-1);
  789. DeleteIntern(Count-1, aFreeItem);
  790. end;
  791. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  792. //TutlCustomList////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  793. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  794. function TutlCustomList.IndexOf(const aItem: T): Integer;
  795. begin
  796. result := Count-1;
  797. while (result >= 0)
  798. and not fEqualityComparer.EqualityCompare(Items[result], aItem)
  799. do
  800. dec(result);
  801. end;
  802. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  803. function TutlCustomList.Extract(const aItem: T; const aDefault: T): T;
  804. var
  805. i: Integer;
  806. begin
  807. i := IndexOf(aItem);
  808. if (i >= 0) then begin
  809. result := Items[i];
  810. DeleteIntern(i, false);
  811. end else
  812. result := aDefault;
  813. end;
  814. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  815. function TutlCustomList.Remove(const aItem: T): Integer;
  816. begin
  817. result := IndexOf(aItem);
  818. if (result >= 0) then
  819. DeleteIntern(result, true);
  820. end;
  821. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  822. constructor TutlCustomList.Create(const aEqualityComparer: IEqualityComparer; const aOwnsItems: Boolean);
  823. begin
  824. if not Assigned(aEqualityComparer) then
  825. raise EArgumentNilException.Create('aEqualityComparer');
  826. inherited Create(aOwnsItems);
  827. fEqualityComparer := aEqualityComparer;
  828. end;
  829. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  830. destructor TutlCustomList.Destroy;
  831. begin
  832. fEqualityComparer := nil;
  833. inherited Destroy;
  834. end;
  835. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  836. //TutlList//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  837. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  838. constructor TutlList.Create(const aOwnsItems: Boolean);
  839. begin
  840. inherited Create(TEqualityComparer.Create, aOwnsItems);
  841. end;
  842. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  843. //TutlCustomHashSet/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  844. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  845. procedure TutlCustomHashSet.SetCount(const aValue: Integer);
  846. begin
  847. raise ENotSupportedException.Create('SetCount not supported');
  848. end;
  849. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  850. procedure TutlCustomHashSet.SetItem(const aIndex: Integer; aValue: T);
  851. begin
  852. if not fComparer.EqualityCompare(GetItem(aIndex), aValue) then
  853. EInvalidOperation.Create('values are not equal');
  854. inherited SetItem(aIndex, aValue);
  855. end;
  856. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  857. function TutlCustomHashSet.Add(constref aItem: T): Boolean;
  858. var
  859. i: Integer;
  860. begin
  861. result := not TBinarySearch.Search(self, fComparer, aItem, i);
  862. if result then
  863. InsertIntern(i, aItem);
  864. end;
  865. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  866. function TutlCustomHashSet.Contains(constref aItem: T): Boolean;
  867. var
  868. i: Integer;
  869. begin
  870. result := TBinarySearch.Search(self, fComparer, aItem, i);
  871. end;
  872. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  873. function TutlCustomHashSet.IndexOf(constref aItem: T): Integer;
  874. begin
  875. if not TBinarySearch.Search(self, fComparer, aItem, result) then
  876. result := -1;
  877. end;
  878. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  879. function TutlCustomHashSet.Remove(constref aItem: T): Boolean;
  880. var
  881. i: Integer;
  882. begin
  883. result := TBinarySearch.Search(self, fComparer, aItem, i);
  884. if result then
  885. DeleteIntern(i, true);
  886. end;
  887. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  888. procedure TutlCustomHashSet.Delete(const aIndex: Integer);
  889. begin
  890. DeleteIntern(aIndex, true);
  891. end;
  892. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  893. constructor TutlCustomHashSet.Create(const aComparer: IComparer; const aOwnsItems: Boolean);
  894. begin
  895. inherited Create(aOwnsItems);
  896. fComparer := aComparer;
  897. end;
  898. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  899. destructor TutlCustomHashSet.Destroy;
  900. begin
  901. fComparer := nil;
  902. inherited Destroy;
  903. end;
  904. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  905. //TutlHastSet///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  906. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  907. constructor TutlHashSet.Create(const aOwnsItems: Boolean);
  908. begin
  909. inherited Create(TComparer.Create, aOwnsItems);
  910. end;
  911. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  912. //TutlCustomMap.THashSet////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  913. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  914. procedure TutlCustomMap.THashSet.Release(var aItem: TKeyValuePair; const aFreeItem: Boolean);
  915. begin
  916. utlFinalizeObject(aItem.Key, TypeInfo(aItem.Key), fOwner.OwnsKeys and aFreeItem);
  917. utlFinalizeObject(aItem.Value, TypeInfo(aItem.Value), fOwner.OwnsValues and aFreeItem);
  918. inherited Release(aItem, aFreeItem);
  919. end;
  920. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  921. constructor TutlCustomMap.THashSet.Create(const aOwner: TutlCustomMap; const aComparer: IComparer);
  922. begin
  923. inherited Create(aComparer, true);
  924. fOwner := aOwner;
  925. end;
  926. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  927. //TutlCustomMap.TKeyValuePairComparer///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  928. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  929. function TutlCustomMap.TKeyValuePairComparer.EqualityCompare(constref i1, i2: TKeyValuePair): Boolean;
  930. begin
  931. result := fComparer.EqualityCompare(i1.Key, i2.Key);
  932. end;
  933. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  934. function TutlCustomMap.TKeyValuePairComparer.Compare(constref i1, i2: TKeyValuePair): Integer;
  935. begin
  936. result := fComparer.Compare(i1.Key, i2.Key);
  937. end;
  938. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  939. constructor TutlCustomMap.TKeyValuePairComparer.Create(aComparer: IComparer);
  940. begin
  941. if not Assigned(aComparer) then
  942. raise EArgumentNilException.Create('aComparer');
  943. inherited Create;
  944. fComparer := aComparer;
  945. end;
  946. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  947. destructor TutlCustomMap.TKeyValuePairComparer.Destroy;
  948. begin
  949. fComparer := nil;
  950. inherited Destroy;
  951. end;
  952. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  953. //TutlCustomMap.TKeyEnumerator//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  954. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  955. function TutlCustomMap.TKeyEnumerator.InternalMoveNext: Boolean;
  956. begin
  957. result := fEnumerator.MoveNext;
  958. end;
  959. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  960. procedure TutlCustomMap.TKeyEnumerator.InternalReset;
  961. begin
  962. fEnumerator.Reset;
  963. end;
  964. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  965. function TutlCustomMap.TKeyEnumerator.GetCurrent: TKey;
  966. begin
  967. result := fEnumerator.GetCurrent.Key;
  968. end;
  969. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  970. constructor TutlCustomMap.TKeyEnumerator.Create(aEnumerator: IutlKeyValuePairEnumerator);
  971. begin
  972. if not Assigned(aEnumerator) then
  973. raise EArgumentNilException.Create('aEnumerator');
  974. fEnumerator := aEnumerator;
  975. inherited Create;
  976. end;
  977. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  978. //TutlCustomMap.TValueEnumerator////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  979. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  980. function TutlCustomMap.TValueEnumerator.InternalMoveNext: Boolean;
  981. begin
  982. result := fEnumerator.MoveNext;
  983. end;
  984. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  985. procedure TutlCustomMap.TValueEnumerator.InternalReset;
  986. begin
  987. fEnumerator.Reset;
  988. end;
  989. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  990. function TutlCustomMap.TValueEnumerator.GetCurrent: TValue;
  991. begin
  992. result := fEnumerator.GetCurrent.Value;
  993. end;
  994. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  995. constructor TutlCustomMap.TValueEnumerator.Create(aEnumerator: IutlKeyValuePairEnumerator);
  996. begin
  997. if not Assigned(aEnumerator) then
  998. raise EArgumentNilException.Create('aEnumerator');
  999. fEnumerator := aEnumerator;
  1000. inherited Create;
  1001. end;
  1002. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1003. //TutlCustomMap.TKeyCollection//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1004. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1005. function TutlCustomMap.TKeyCollection.GetEnumerator: IKeyEnumerator;
  1006. begin
  1007. result := TKeyEnumerator.Create(fHashSet.GetUtlEnumerator);
  1008. end;
  1009. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1010. function TutlCustomMap.TKeyCollection.GetUtlEnumerator: IutlKeyEnumerator;
  1011. begin
  1012. result := TKeyEnumerator.Create(fHashSet.GetUtlEnumerator);
  1013. end;
  1014. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1015. function TutlCustomMap.TKeyCollection.GetCount: Integer;
  1016. begin
  1017. result := fHashSet.Count;
  1018. end;
  1019. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1020. function TutlCustomMap.TKeyCollection.GetItem(const aIndex: Integer): TKey;
  1021. begin
  1022. result := fHashSet[aIndex].Key;
  1023. end;
  1024. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1025. constructor TutlCustomMap.TKeyCollection.Create(const aHashSet: THashSet);
  1026. begin
  1027. inherited Create;
  1028. fHashSet := aHashSet;
  1029. end;
  1030. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1031. //TutlCustomMap.TKeyValuePairCollection/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1032. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1033. function TutlCustomMap.TKeyValuePairCollection.GetEnumerator: IKeyValuePairEnumerator;
  1034. begin
  1035. result := fHashSet.GetEnumerator;
  1036. end;
  1037. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1038. function TutlCustomMap.TKeyValuePairCollection.GetUtlEnumerator: IutlKeyValuePairEnumerator;
  1039. begin
  1040. result := fHashSet.GetUtlEnumerator;
  1041. end;
  1042. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1043. function TutlCustomMap.TKeyValuePairCollection.GetCount: Integer;
  1044. begin
  1045. result := fHashSet.Count;
  1046. end;
  1047. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1048. function TutlCustomMap.TKeyValuePairCollection.GetItem(const aIndex: Integer): TKeyValuePair;
  1049. begin
  1050. result := fHashSet[aIndex];
  1051. end;
  1052. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1053. constructor TutlCustomMap.TKeyValuePairCollection.Create(const aHashSet: THashSet);
  1054. begin
  1055. inherited Create;
  1056. fHashSet := aHashSet;
  1057. end;
  1058. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1059. //TutlCustomMap/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1060. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1061. function TutlCustomMap.GetValue(aKey: TKey): TValue;
  1062. var
  1063. i: Integer;
  1064. kvp: TKeyValuePair;
  1065. begin
  1066. kvp.Key := aKey;
  1067. i := fHashSetRef.IndexOf(kvp);
  1068. if (i < 0)
  1069. then FillByte(result{%H-}, SizeOf(result), 0)
  1070. else result := fHashSetRef[i].Value;
  1071. end;
  1072. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1073. function TutlCustomMap.GetValueAt(const aIndex: Integer): TValue;
  1074. begin
  1075. result := fHashSetRef[aIndex].Value;
  1076. end;
  1077. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1078. function TutlCustomMap.GetCount: Integer;
  1079. begin
  1080. result := fHashSetRef.Count;
  1081. end;
  1082. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1083. function TutlCustomMap.GetIsEmpty: Boolean;
  1084. begin
  1085. result := fHashSetRef.IsEmpty;
  1086. end;
  1087. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1088. function TutlCustomMap.GetCapacity: Integer;
  1089. begin
  1090. result := fHashSetRef.Capacity;
  1091. end;
  1092. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1093. function TutlCustomMap.GetCanShrink: Boolean;
  1094. begin
  1095. result := fHashSetRef.CanShrink;
  1096. end;
  1097. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1098. function TutlCustomMap.GetCanExpand: Boolean;
  1099. begin
  1100. result := fHashSetRef.CanExpand;
  1101. end;
  1102. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1103. procedure TutlCustomMap.SetCapacity(const aValue: Integer);
  1104. begin
  1105. fHashSetRef.Capacity := aValue;
  1106. end;
  1107. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1108. procedure TutlCustomMap.SetCanShrink(const aValue: Boolean);
  1109. begin
  1110. fHashSetRef.CanShrink := aValue;
  1111. end;
  1112. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1113. procedure TutlCustomMap.SetCanExpand(const aValue: Boolean);
  1114. begin
  1115. fHashSetRef.CanExpand := aValue;
  1116. end;
  1117. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1118. procedure TutlCustomMap.SetValue(aKey: TKey; const aValue: TValue);
  1119. var
  1120. i: Integer;
  1121. kvp: TKeyValuePair;
  1122. begin
  1123. kvp.Key := aKey;
  1124. kvp.Value := aValue;
  1125. i := fHashSetRef.IndexOf(kvp);
  1126. if (i < 0) then begin
  1127. if not fAutoCreate then
  1128. raise EInvalidOperation.Create('key not found');
  1129. fHashSetRef.Add(kvp);
  1130. end else
  1131. fHashSetRef[i] := kvp;
  1132. end;
  1133. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1134. procedure TutlCustomMap.SetValueAt(const aIndex: Integer; const aValue: TValue);
  1135. var
  1136. kvp: TKeyValuePair;
  1137. begin
  1138. kvp := fHashSetRef[aIndex];
  1139. kvp.Value := aValue;
  1140. fHashSetRef[aIndex] := kvp;
  1141. end;
  1142. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1143. function TutlCustomMap.GetEnumerator: IValueEnumerator;
  1144. begin
  1145. result := TValueEnumerator.Create(fHashSetRef.GetUtlEnumerator);
  1146. end;
  1147. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1148. function TutlCustomMap.GetUtlEnumerator: IutlValueEnumerator;
  1149. begin
  1150. result := TValueEnumerator.Create(fHashSetRef.GetUtlEnumerator);
  1151. end;
  1152. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1153. procedure TutlCustomMap.Add(constref aKey: TKey; constref aValue: TValue);
  1154. begin
  1155. if not TryAdd(aKey, aValue) then
  1156. raise EInvalidOperation.Create('key already exists');
  1157. end;
  1158. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1159. function TutlCustomMap.TryAdd(constref aKey: TKey; constref aValue: TValue): Boolean;
  1160. var
  1161. kvp: TKeyValuePair;
  1162. begin
  1163. kvp.Key := aKey;
  1164. kvp.Value := aValue;
  1165. result := fHashSetRef.Add(kvp);
  1166. end;
  1167. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1168. function TutlCustomMap.TryGetValue(constref aKey: TKey; out aValue: TValue): Boolean;
  1169. var
  1170. i: Integer;
  1171. begin
  1172. i := IndexOf(aKey);
  1173. result := (i >= 0);
  1174. if result
  1175. then aValue := fHashSetRef[i].Value
  1176. else FillByte(result, SizeOf(result), 0);
  1177. end;
  1178. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1179. function TutlCustomMap.IndexOf(constref aKey: TKey): Integer;
  1180. var
  1181. kvp: TKeyValuePair;
  1182. begin
  1183. kvp.Key := aKey;
  1184. result := fHashSetRef.IndexOf(kvp);
  1185. end;
  1186. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1187. function TutlCustomMap.Contains(constref aKey: TKey): Boolean;
  1188. begin
  1189. result := (IndexOf(aKey) >= 0);
  1190. end;
  1191. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1192. procedure TutlCustomMap.Delete(constref aKey: TKey);
  1193. var
  1194. kvp: TKeyValuePair;
  1195. begin
  1196. kvp.Key := aKey;
  1197. if not fHashSetRef.Remove(kvp) then
  1198. raise EInvalidOperation.Create('key not found');
  1199. end;
  1200. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1201. procedure TutlCustomMap.DeleteAt(const aIndex: Integer);
  1202. begin
  1203. fHashSetRef.Delete(aIndex);
  1204. end;
  1205. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1206. procedure TutlCustomMap.Clear;
  1207. begin
  1208. fHashSetRef.Clear;
  1209. end;
  1210. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1211. constructor TutlCustomMap.Create(
  1212. const aHashSet: THashSet;
  1213. const aOwnsKeys: Boolean;
  1214. const aOwnsValues: Boolean);
  1215. begin
  1216. if not Assigned(aHashSet) then
  1217. EArgumentNilException.Create('aHashSet');
  1218. inherited Create;
  1219. fAutoCreate := false;
  1220. fHashSetRef := aHashSet;
  1221. fOwnsKeys := aOwnsKeys;
  1222. fOwnsValues := aOwnsValues;
  1223. fKeyCollection := TKeyCollection.Create(fHashSetRef);
  1224. fKeyValuePairCollection := TKeyValuePairCollection.Create(fHashSetRef);
  1225. end;
  1226. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1227. destructor TutlCustomMap.Destroy;
  1228. begin
  1229. FreeAndNil(fKeyValuePairCollection);
  1230. FreeAndNil(fKeyCollection);
  1231. fHashSetRef := nil;
  1232. inherited Destroy;
  1233. end;
  1234. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1235. //TutlMap///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1236. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1237. constructor TutlMap.Create(const aOwnsKeys: Boolean; const aOwnsValues: Boolean);
  1238. begin
  1239. fHashSetImpl := THashSet.Create(self, TKeyValuePairComparer.Create(TComparer.Create));
  1240. inherited Create(fHashSetImpl, aOwnsKeys, aOwnsValues);
  1241. end;
  1242. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1243. destructor TutlMap.Destroy;
  1244. begin
  1245. Clear;
  1246. inherited Destroy;
  1247. FreeAndNil(fHashSetImpl);
  1248. end;
  1249. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1250. //EutlEnumConvert///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1251. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1252. constructor EEnumConvertException.Create(const aValue, aExpectedType: String);
  1253. begin
  1254. inherited Create(Format('%s is not a %s', [aValue, aExpectedType]));
  1255. end;
  1256. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1257. //TutlEnumHelper////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1258. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1259. class function TutlEnumHelper.ToString(aValue: T): String;
  1260. begin
  1261. {$Push}
  1262. {$IOChecks OFF}
  1263. WriteStr(Result, aValue);
  1264. if IOResult = 107 then
  1265. Result := '';
  1266. {$Pop}
  1267. end;
  1268. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1269. class function TutlEnumHelper.TryToEnum(aStr: String; out aValue: T): Boolean;
  1270. var
  1271. a: T;
  1272. begin
  1273. a := T(0);
  1274. Result := false;
  1275. if Length(aStr) = 0 then
  1276. exit;
  1277. {$Push}
  1278. {$IOChecks OFF}
  1279. ReadStr(aStr, a);
  1280. Result := IOResult <> 106;
  1281. {$Pop}
  1282. if Result then
  1283. aValue := a;
  1284. end;
  1285. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1286. class function TutlEnumHelper.ToEnum(aStr: String): T;
  1287. begin
  1288. if not TryToEnum(aStr, result) then
  1289. raise EEnumConvertException.Create(aStr, TypeInfo^.Name);
  1290. end;
  1291. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1292. class function TutlEnumHelper.ToEnum(aStr: String; const aDefault: T): T;
  1293. begin
  1294. if not TryToEnum(aStr, result) then
  1295. result := aDefault;
  1296. end;
  1297. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1298. class function TutlEnumHelper.Values: TValueArray;
  1299. begin
  1300. result := fValues;
  1301. end;
  1302. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1303. class function TutlEnumHelper.Names: TStringArray;
  1304. begin
  1305. result := fNames;
  1306. end;
  1307. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1308. class function TutlEnumHelper.TypeInfo: PTypeInfo;
  1309. begin
  1310. result := fTypeInfo;
  1311. end;
  1312. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1313. class constructor TutlEnumHelper.Initialize;
  1314. var
  1315. tiArray: PTypeInfo;
  1316. tdArray, tdEnum: PTypeData;
  1317. PName: PShortString;
  1318. i: integer;
  1319. en: T;
  1320. begin
  1321. {
  1322. See FPC Bug http://bugs.freepascal.org/view.php?id=27622
  1323. For Sparse Enums, the compiler won't give us TypeInfo, because it contains some wrong data. This is
  1324. safe, but sadly we don't even get the *correct* fields (TypeName, NameList), even though they are
  1325. generated in any case.
  1326. Fortunately, arrays do know this type info segment as their Element Type (and we declared one anyway).
  1327. }
  1328. tiArray := System.TypeInfo(TValueArray);
  1329. tdArray := GetTypeData(tiArray);
  1330. fTypeInfo := tdArray^.elType2;
  1331. {
  1332. Now that we have the TypeInfo, fill our values from it. This is safe because while the *values* in
  1333. TypeData are wrong for Sparse Enums, the *PName* are always correct.
  1334. }
  1335. tdEnum := GetTypeData(FTypeInfo);
  1336. PName := @tdEnum^.NameList;
  1337. SetLength(fValues, 0);
  1338. SetLength(fNames, 0);
  1339. i:= 0;
  1340. while Length(PName^) > 0 do begin
  1341. SetLength(fValues, i+1);
  1342. SetLength(fNames, i+1);
  1343. {
  1344. Memory layout for TTypeData has the declaring EnumUnitName after the last NameList entry.
  1345. This can normally not be the same as a valid enum value, because it is in the same identifier
  1346. namespace. However, with scoped enums we might have the same name for module and element, because
  1347. the full identifier for the element would be TypeName.ElementName.
  1348. In either case, the next PShortString will point to a zero-length string, and the loop is left
  1349. with the last element being invalid (either empty or whatever value the unit-named element has).
  1350. }
  1351. fNames[i] := PName^;
  1352. if TryToEnum(PName^, en) then
  1353. fValues[i]:= en;
  1354. inc(i);
  1355. inc(PByte(PName), Length(PName^) + 1);
  1356. end;
  1357. // remove the EnumUnitName item
  1358. SetLength(fValues, High(fValues));
  1359. SetLength(fNames, High(fNames));
  1360. end;
  1361. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1362. //TutlSetHelper/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1363. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1364. class function TutlSetHelper.IsSet(constref aSet: TSet; aEnum: TEnum): Boolean;
  1365. begin
  1366. result := ((PByte(@aSet)[Integer(aEnum) shr 3] and (1 shl (Integer(aEnum) and 7))) <> 0);
  1367. end;
  1368. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1369. class procedure TutlSetHelper.SetValue(var aSet: TSet; aEnum: TEnum);
  1370. begin
  1371. PByte(@aSet)[Integer(aEnum) shr 3] := PByte(@aSet)[Integer(aEnum) shr 3] or (1 shl (Integer(aEnum) and 7));
  1372. end;
  1373. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1374. class procedure TutlSetHelper.ClearValue(var aSet: TSet; aEnum: TEnum);
  1375. begin
  1376. PByte(@aSet)[Integer(aEnum) shr 3] := PByte(@aSet)[Integer(aEnum) shr 3] and not (1 shl (Integer(aEnum) and 7));
  1377. end;
  1378. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1379. class function TutlSetHelper.ToString(const aValue: TSet; const aSeperator: String): String;
  1380. var
  1381. e: TEnum;
  1382. begin
  1383. result := '';
  1384. for e in TEnumHelper.Values do begin
  1385. if IsSet(aValue, e) then begin
  1386. if result > '' then
  1387. result := result + aSeperator;
  1388. result := result + TEnumHelper.ToString(e);
  1389. end;
  1390. end;
  1391. end;
  1392. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1393. class function TutlSetHelper.TryToSet(const aStr: String; out aValue: TSet): Boolean;
  1394. begin
  1395. result := TryToSet(aStr, ',', aValue);
  1396. end;
  1397. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1398. class function TutlSetHelper.TryToSet(const aStr: String; const aSeperator: String; out aValue: TSet): Boolean;
  1399. var
  1400. i, j: Integer;
  1401. s: String;
  1402. e: TEnum;
  1403. begin
  1404. if (aSeperator = '') then
  1405. raise EArgumentException.Create('''aSeperator'' can not be empty');
  1406. result := true;
  1407. aValue := [];
  1408. i := 1;
  1409. j := 1;
  1410. while (i <= Length(aStr)) do begin
  1411. if (Copy(aStr, i, Length(aSeperator)) = aSeperator) then begin
  1412. s := Trim(copy(aStr, j, i - j));
  1413. if (s <> '') then begin
  1414. result := result and TEnumHelper.TryToEnum(s, e);
  1415. if not result then
  1416. exit;
  1417. SetValue(aValue, e);
  1418. j := i + Length(aSeperator);
  1419. end;
  1420. end;
  1421. inc(i);
  1422. end;
  1423. s := Trim(copy(aStr, j, i - j));
  1424. if (s <> '') then begin
  1425. result := result and TEnumHelper.TryToEnum(s, e);
  1426. if not result then
  1427. exit;
  1428. SetValue(aValue, e);
  1429. end
  1430. end;
  1431. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1432. class function TutlSetHelper.ToSet(const aStr: String; const aDefault: TSet): TSet;
  1433. begin
  1434. if not TryToSet(aStr, result) then
  1435. result := aDefault;
  1436. end;
  1437. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1438. class function TutlSetHelper.ToSet(const aStr: String): TSet;
  1439. begin
  1440. if not TryToSet(aStr, result) then
  1441. raise EEnumConvertException.CreateFmt('"%s" is an invalid value', [aStr]);
  1442. end;
  1443. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1444. class function TutlSetHelper.Compare(const aSet1, aSet2: TSet): Integer;
  1445. var
  1446. e: TEnum;
  1447. begin
  1448. result := 0;
  1449. for e in TEnumHelper.Values do begin
  1450. if IsSet(aSet1, e) and not IsSet(aSet2, e) then begin
  1451. result := 1;
  1452. break;
  1453. end else if not IsSet(aSet1, e) and IsSet(aSet2, e) then begin
  1454. result := -1;
  1455. break;
  1456. end;
  1457. end;
  1458. end;
  1459. end.