Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

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