Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

2265 řádky
90 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. function Remove (constref aKey: TKey): Boolean;
  353. procedure Delete (constref aKey: TKey);
  354. procedure DeleteAt (const aIndex: Integer);
  355. procedure Clear;
  356. constructor Create(const aHashSet: THashSet; const aOwnsKeys: Boolean; const aOwnsValues: Boolean);
  357. destructor Destroy; override;
  358. end;
  359. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  360. generic TutlMap<TKey, TValue> = class(
  361. specialize TutlCustomMap<TKey, TValue>)
  362. public type
  363. TComparer = specialize TutlComparer<TKey>;
  364. strict private
  365. fHashSetImpl: THashSet;
  366. public
  367. constructor Create(const aOwnsKeys: Boolean; const aOwnsValues: Boolean);
  368. destructor Destroy; override;
  369. end;
  370. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  371. TutlHandle = QWord;
  372. generic TutlHandleManager<T> = class(TObject)
  373. private type
  374. THandleData = packed record
  375. case Integer of
  376. 0: (
  377. Handle: TutlHandle // 0..63
  378. );
  379. 1: (
  380. Index: Cardinal; // 0..31
  381. Counter: Word; // 32..47
  382. Identifier: Word // 48..63
  383. );
  384. end;
  385. THandleEntry = bitpacked record
  386. Data: T;
  387. NextFreeIndex: Cardinal; // 0..31
  388. Counter: Word; // 32..47
  389. IsActive: Boolean; // 48
  390. __reserved: 0..((1 shl 15)-1); // 49..63
  391. end;
  392. private
  393. fCount: Integer;
  394. fGrowSize: Integer;
  395. fEntries: array of THandleEntry;
  396. fFirstFreeIndex: Cardinal;
  397. fOwnsValues: Boolean;
  398. procedure Grow;
  399. public
  400. function Get (const aHandle: TutlHandle): T;
  401. function TryGet (const aHandle: TutlHandle; out aData: T): Boolean;
  402. function Add (constref aData: T; const aIdentifier: Word): TutlHandle;
  403. function IsValid(const aHandle: TutlHandle): Boolean; inline;
  404. procedure Update (const aHandle: TutlHandle; aData: T);
  405. procedure Remove (const aHandle: TutlHandle);
  406. procedure Clear;
  407. public
  408. property Items[const aHandle: TutlHandle]: T read Get write Update;
  409. property Count: Integer read fCount;
  410. constructor Create(const aOwnsValues: Boolean);
  411. destructor Destroy; override;
  412. public
  413. class function GetIdentifier(const aHandle: TutlHandle): Word; inline;
  414. end;
  415. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  416. EEnumConvertException = class(EConvertError)
  417. public
  418. constructor Create(const aValue, aExpectedType: String);
  419. end;
  420. TutlEnumHelperBaseClass = class of TutlEnumHelperBase;
  421. TutlEnumHelperBase = class
  422. public type
  423. TIntArray = array of Integer;
  424. TStringArray = array of String;
  425. private type
  426. TValuesMap = specialize TutlMap<string, TIntArray>;
  427. TNamesMap = specialize TutlMap<string, TStringArray>;
  428. private class var
  429. fValuesMap: TValuesMap;
  430. fNamesMap: TNamesMap;
  431. protected
  432. class procedure RegisterType (const aValues: TIntArray; const aNames: TStringArray);
  433. class procedure UnregisterType();
  434. public
  435. class function ToString (const aValue: Integer; const aAllowOrd: Boolean = false): String; reintroduce;
  436. class function TryToEnum (const aStr: String; out aValue: Integer; const aAllowOrd: Boolean = false): Boolean;
  437. class function ToEnum (const aStr: String; const aAllowOrd: Boolean = false): Integer; overload;
  438. class function ToEnum (const aStr: String; const aDefault: Integer; const aAllowOrd: Boolean = false): Integer; overload;
  439. class function IntValues: TIntArray;
  440. class function Names: TStringArray;
  441. public
  442. class constructor Initialize;
  443. class destructor Finalize;
  444. end;
  445. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  446. generic TutlEnumHelper<T> = class(TutlEnumHelperBase)
  447. public type
  448. TEnumType = T;
  449. TValueArray = array of T;
  450. private class var
  451. fValues: TValueArray;
  452. fNames: TStringArray;
  453. fIntValues: TIntArray;
  454. fTypeInfo: PTypeInfo;
  455. public
  456. class function ToString (const aValue: T; const aAllowOrd: Boolean = false): String; reintroduce;
  457. class function TryToEnum (const aStr: String; out aValue: T; const aAllowOrd: Boolean = false): Boolean;
  458. class function ToEnum (const aStr: String; const aAllowOrd: Boolean = false): T; overload;
  459. class function ToEnum (const aStr: String; const aDefault: T; const aAllowOrd: Boolean = false): T; overload;
  460. class function Values: TValueArray; inline;
  461. class function IntValues: TIntArray; inline;
  462. class function Names: TStringArray; inline;
  463. class function TypeInfo: PTypeInfo; inline;
  464. class constructor Initialize;
  465. class destructor Finalize;
  466. end;
  467. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  468. TutlSetHelperBase = class
  469. private type
  470. TEnumHelperMap = specialize TutlMap<string, TutlEnumHelperBaseClass>;
  471. private class var
  472. fEnumHelpers: TEnumHelperMap;
  473. private
  474. class function IsSet (const aSet; const aSize: Integer; const aValue: Integer): Boolean;
  475. class procedure SetValue (var aSet; const aSize: Integer; const aValue: Integer);
  476. class procedure ClearValue(var aSet; const aSize: Integer; const aValue: Integer);
  477. protected
  478. class procedure RegisterEnumHelper(const aHelper: TutlEnumHelperBaseClass);
  479. class procedure UnregisterEnumHelper;
  480. public
  481. class function ToString(
  482. const aSet;
  483. const aSize: Integer;
  484. const aSeparator: String = ', ';
  485. const aAllowOrd: Boolean = false): String; reintroduce;
  486. class function TryToSet(
  487. const aStr: String;
  488. out aSet;
  489. const aSize: Integer;
  490. const aAllowOrd: Boolean = false): Boolean;
  491. class function TryToSet(
  492. const aStr: String;
  493. const aSeparator: String;
  494. out aSet;
  495. const aSize: Integer;
  496. const aAllowOrd: Boolean = false): Boolean;
  497. class function Compare(
  498. const aSet1;
  499. const aSet2;
  500. const aSize: Integer): Integer;
  501. class function EnumHelper: TutlEnumHelperBaseClass;
  502. class constructor Initialize;
  503. class destructor Finalize;
  504. end;
  505. TutlSetHelperBaseClass = class of TutlSetHelperBase;
  506. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  507. generic TutlSetHelper<TEnum, TSet> = class(TutlSetHelperBase)
  508. public type
  509. TEnumHelper = specialize TutlEnumHelper<TEnum>;
  510. TEnumType = TEnum;
  511. TSetType = TSet;
  512. public
  513. class function ToString(
  514. const aValue: TSet;
  515. const aSeparator: String = ', ';
  516. const aAllowOrd: Boolean = false): String; overload;
  517. class function TryToSet(
  518. const aStr: String;
  519. out aValue: TSet;
  520. const aAllowOrd: Boolean = false): Boolean; overload;
  521. class function TryToSet(
  522. const aStr: String;
  523. const aSeparator: String;
  524. out aValue: TSet;
  525. const aAllowOrd: Boolean = false): Boolean; overload;
  526. class function ToSet(
  527. const aStr: String;
  528. const aDefault: TSet;
  529. const aAllowOrd: Boolean = false): TSet; overload;
  530. class function ToSet(
  531. const aStr: String;
  532. const aAllowOrd: Boolean = false): TSet; overload;
  533. class function Compare(
  534. const aSet1, aSet2: TSet): Integer; overload;
  535. class constructor Initialize;
  536. class destructor Finalize;
  537. end;
  538. implementation
  539. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  540. //TutlQueue.TEnumerator/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  541. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  542. function TutlQueue.TEnumerator.InternalMoveNext: Boolean;
  543. begin
  544. if fReversed
  545. then dec(fCurrent)
  546. else inc(fCurrent);
  547. result := (0 <= fCurrent) and (fCurrent < fOwner.Count);
  548. end;
  549. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  550. procedure TutlQueue.TEnumerator.InternalReset;
  551. begin
  552. if fReversed
  553. then fCurrent := fOwner.Count
  554. else fCurrent := -1;
  555. end;
  556. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  557. {$IFDEF UTL_ENUMERATORS}
  558. function TutlQueue.TEnumerator.Reverse: IutlEnumerator;
  559. begin
  560. result := TEnumerator.Create(fOwner, not fReversed);
  561. end;
  562. {$ENDIF}
  563. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  564. function TutlQueue.TEnumerator.GetCurrent: T;
  565. begin
  566. result := fOwner[fCurrent];
  567. end;
  568. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  569. constructor TutlQueue.TEnumerator.Create(const aOwner: TutlQueue; const aReversed: Boolean);
  570. begin
  571. if not Assigned(aOwner) then
  572. raise EArgumentNilException.Create('aOwner');
  573. fOwner := aOwner;
  574. fReversed := aReversed;
  575. inherited Create;
  576. end;
  577. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  578. //TutlQueue/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  579. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  580. function TutlQueue.GetItem(const aIndex: Integer): T;
  581. var
  582. i: Integer;
  583. begin
  584. if (aIndex < 0) or (aIndex >= fCount) then
  585. raise EOutOfRangeException.Create(aIndex, 0, fCount-1);
  586. i := fReadPos + aIndex;
  587. if (i >= Capacity) then
  588. i := i - Capacity;
  589. result := GetInternalItem(i)^;
  590. end;
  591. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  592. procedure TutlQueue.SetItem(const aIndex: Integer; aItem: T);
  593. var
  594. i: Integer;
  595. begin
  596. if (aIndex < 0) or (aIndex >= fCount) then
  597. raise EOutOfRangeException.Create(aIndex, 0, fCount-1);
  598. i := fReadPos + aIndex;
  599. if (i >= Capacity) then
  600. i := i - Capacity;
  601. GetInternalItem(i)^ := aItem;
  602. end;
  603. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  604. function TutlQueue.GetCount: Integer;
  605. begin
  606. result := fCount;
  607. end;
  608. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  609. procedure TutlQueue.SetCount(const aValue: Integer);
  610. begin
  611. raise ENotSupportedException.Create('SetCount not supported');
  612. end;
  613. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  614. procedure TutlQueue.SetCapacity(const aValue: integer);
  615. var
  616. cnt: Integer;
  617. begin
  618. if (aValue < Count) then
  619. raise EArgumentException.Create('can not reduce capacity below count');
  620. if (aValue < Capacity) then begin // is shrinking
  621. if (fReadPos <= fWritePos) then begin // ReadPos Before WritePos -> Move To Begin
  622. System.Move(GetInternalItem(fReadPos)^, GetInternalItem(0)^, SizeOf(T) * Count);
  623. fReadPos := 0;
  624. fWritePos := Count;
  625. end else if (fReadPos > fWritePos) then begin // ReadPos Behind WritePos
  626. cnt := Capacity - aValue;
  627. System.Move(GetInternalItem(fReadPos)^, GetInternalItem(fReadPos - cnt)^, SizeOf(T) * cnt);
  628. dec(fReadPos, cnt);
  629. end;
  630. end;
  631. inherited SetCapacity(aValue);
  632. // ReadPos After WritePos and Expanding
  633. if (fReadPos > fWritePos) and (aValue > Capacity) then begin
  634. cnt := aValue - Capacity;
  635. System.Move(GetInternalItem(fReadPos)^, GetInternalItem(fReadPos - cnt)^, SizeOf(T) * cnt);
  636. inc(fReadPos, cnt);
  637. end;
  638. end;
  639. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  640. function TutlQueue.GetEnumerator: IEnumerator;
  641. begin
  642. result := TEnumerator.Create(self, false);
  643. result.Reset;
  644. end;
  645. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  646. function TutlQueue.GetUtlEnumerator: IutlEnumerator;
  647. begin
  648. result := TEnumerator.Create(self, false);
  649. result.Reset;
  650. end;
  651. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  652. procedure TutlQueue.Enqueue(constref aItem: T);
  653. begin
  654. if (Count = Capacity) then
  655. Expand;
  656. fWritePos := fWritePos mod Capacity;
  657. GetInternalItem(fWritePos)^ := aItem;
  658. inc(fCount);
  659. inc(fWritePos);
  660. end;
  661. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  662. function TutlQueue.Dequeue: T;
  663. begin
  664. result := Dequeue(false);
  665. end;
  666. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  667. function TutlQueue.Dequeue(const aFreeItem: Boolean): T;
  668. var
  669. p: PT;
  670. begin
  671. if IsEmpty then
  672. raise EInvalidOperation.Create('queue is empty');
  673. p := GetInternalItem(fReadPos);
  674. if aFreeItem
  675. then FillByte(result{%H-}, SizeOf(result), 0)
  676. else result := p^;
  677. Release(p^, aFreeItem);
  678. dec(fCount);
  679. fReadPos := (fReadPos + 1) mod Capacity;
  680. end;
  681. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  682. function TutlQueue.Peek: T;
  683. begin
  684. if IsEmpty then
  685. raise EInvalidOperation.Create('queue is empty');
  686. result := GetInternalItem(fReadPos)^;
  687. end;
  688. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  689. procedure TutlQueue.ShrinkToFit;
  690. begin
  691. Shrink(true);
  692. end;
  693. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  694. procedure TutlQueue.Clear;
  695. begin
  696. while (fReadPos <> fWritePos) do begin
  697. Release(GetInternalItem(fReadPos)^, true);
  698. fReadPos := (fReadPos + 1) mod Capacity;
  699. end;
  700. fCount := 0;
  701. if CanShrink then
  702. ShrinkToFit;
  703. end;
  704. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  705. constructor TutlQueue.Create(const aOwnsItems: Boolean);
  706. begin
  707. inherited Create(aOwnsItems);
  708. fCount := 0;
  709. fReadPos := 0;
  710. fWritePos := 0;
  711. end;
  712. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  713. destructor TutlQueue.Destroy;
  714. begin
  715. Clear;
  716. inherited Destroy;
  717. end;
  718. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  719. //TutlStack.TEnumerator/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  720. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  721. procedure TutlStack.TEnumerator.InternalReset;
  722. begin
  723. First := 0;
  724. Last := fOwner.Count-1;
  725. if (Last >= First)
  726. then Memory := fOwner.GetInternalItem(0)
  727. else Memory := nil;
  728. inherited InternalReset;
  729. end;
  730. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  731. {$IFDEF UTL_ENUMERATORS}
  732. function TutlStack.TEnumerator.Reverse: IutlEnumerator;
  733. begin
  734. result := TEnumerator.Create(fOwner, not Reversed);
  735. end;
  736. {$ENDIF}
  737. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  738. constructor TutlStack.TEnumerator.Create(const aOwner: TutlStack; const aReversed: Boolean);
  739. begin
  740. if not Assigned(aOwner) then
  741. raise EArgumentNilException.Create('aOwner');
  742. fOwner := aOwner;
  743. inherited Create(nil, aReversed, 0, -1);
  744. end;
  745. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  746. //TutlStack/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  747. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  748. function TutlStack.GetItem(const aIndex: Integer): T;
  749. begin
  750. if (aIndex < 0) or (aIndex >= fCount) then
  751. raise EOutOfRangeException.Create(aIndex, 0, fCount-1);
  752. result := GetInternalItem(aIndex)^;
  753. end;
  754. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  755. procedure TutlStack.SetItem(const aIndex: Integer; aValue: T);
  756. begin
  757. if (aIndex < 0) or (aIndex >= fCount) then
  758. raise EOutOfRangeException.Create(aIndex, 0, fCount-1);
  759. GetInternalItem(aIndex)^ := aValue;
  760. end;
  761. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  762. function TutlStack.GetCount: Integer;
  763. begin
  764. result := fCount;
  765. end;
  766. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  767. procedure TutlStack.SetCount(const aValue: Integer);
  768. begin
  769. raise ENotSupportedException.Create('SetCount not supported');
  770. end;
  771. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  772. function TutlStack.GetEnumerator: IEnumerator;
  773. begin
  774. result := TEnumerator.Create(self, false);
  775. end;
  776. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  777. function TutlStack.GetUtlEnumerator: IutlEnumerator;
  778. begin
  779. result := TEnumerator.Create(self, false);
  780. end;
  781. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  782. procedure TutlStack.Push(constref aItem: T);
  783. begin
  784. if (Count = Capacity) then
  785. Expand;
  786. GetInternalItem(fCount)^ := aItem;
  787. inc(fCount);
  788. end;
  789. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  790. function TutlStack.Pop: T;
  791. begin
  792. Pop(false);
  793. end;
  794. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  795. function TutlStack.Pop(const aFreeItem: Boolean): T;
  796. var
  797. p: PT;
  798. begin
  799. if IsEmpty then
  800. raise EInvalidOperation.Create('stack is empty');
  801. p := GetInternalItem(fCount-1);
  802. if aFreeItem
  803. then FillByte(result{%H-}, SizeOf(result), 0)
  804. else result := p^;
  805. Release(p^, aFreeItem);
  806. dec(fCount);
  807. end;
  808. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  809. function TutlStack.Peek: T;
  810. begin
  811. if IsEmpty then
  812. raise EInvalidOperation.Create('stack is empty');
  813. result := GetInternalItem(fCount-1)^;
  814. end;
  815. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  816. procedure TutlStack.ShrinkToFit;
  817. begin
  818. Shrink(true);
  819. end;
  820. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  821. procedure TutlStack.Clear;
  822. begin
  823. while (fCount > 0) do begin
  824. dec(fCount);
  825. Release(GetInternalItem(fCount)^, true);
  826. end;
  827. if CanShrink then
  828. ShrinkToFit;
  829. end;
  830. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  831. constructor TutlStack.Create(const aOwnsItems: Boolean);
  832. begin
  833. inherited Create(aOwnsItems);
  834. fCount := 0
  835. end;
  836. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  837. destructor TutlStack.Destroy;
  838. begin
  839. Clear;
  840. inherited Destroy;
  841. end;
  842. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  843. //TutlSimpleList////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  844. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  845. function TutlSimpleList.GetFirst: T;
  846. begin
  847. if IsEmpty then
  848. raise EInvalidOperation.Create('list is empty');
  849. result := GetInternalItem(0)^;
  850. end;
  851. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  852. function TutlSimpleList.GetLast: T;
  853. begin
  854. if IsEmpty then
  855. raise EInvalidOperation.Create('list is empty');
  856. result := GetInternalItem(Count-1)^;
  857. end;
  858. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  859. function TutlSimpleList.Add(constref aItem: T): Integer;
  860. begin
  861. result := Count;
  862. InsertIntern(result, aItem);
  863. end;
  864. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  865. procedure TutlSimpleList.Insert(const aIndex: Integer; constref aItem: T);
  866. begin
  867. InsertIntern(aIndex, aItem);
  868. end;
  869. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  870. procedure TutlSimpleList.Exchange(const aIndex1, aIndex2: Integer);
  871. var
  872. tmp: T;
  873. p1, p2: PT;
  874. begin
  875. if (aIndex1 < 0) or (aIndex1 >= Count) then
  876. raise EOutOfRangeException.Create(aIndex1, 0, Count-1);
  877. if (aIndex2 < 0) or (aIndex2 >= Count) then
  878. raise EOutOfRangeException.Create(aIndex2, 0, Count-1);
  879. p1 := GetInternalItem(aIndex1);
  880. p2 := GetInternalItem(aIndex2);
  881. System.Move(p1^, tmp{%H-}, SizeOf(T));
  882. System.Move(p2^, p1^, SizeOf(T));
  883. System.Move(tmp, p2^, SizeOf(T));
  884. FillByte(tmp, SizeOf(tmp), 0)
  885. end;
  886. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  887. procedure TutlSimpleList.Move(const aCurrentIndex, aNewIndex: Integer);
  888. var
  889. tmp: T;
  890. cur, new: PT;
  891. begin
  892. if (aCurrentIndex < 0) or (aCurrentIndex >= Count) then
  893. raise EOutOfRangeException.Create(aCurrentIndex, 0, Count-1);
  894. if (aNewIndex < 0) or (aNewIndex >= Count) then
  895. raise EOutOfRangeException.Create(aNewIndex, 0, Count-1);
  896. if (aCurrentIndex = aNewIndex) then
  897. exit;
  898. cur := GetInternalItem(aCurrentIndex);
  899. new := GetInternalItem(aNewIndex);
  900. System.Move(cur^, tmp{%H-}, SizeOf(T));
  901. if (aNewIndex > aCurrentIndex) then begin
  902. System.Move((cur+1)^, cur^, SizeOf(T) * (aNewIndex - aCurrentIndex));
  903. end else begin
  904. System.Move(new^, (new+1)^, SizeOf(T) * (aCurrentIndex - aNewIndex));
  905. end;
  906. System.Move(tmp, new^, SizeOf(T));
  907. FillByte(tmp, SizeOf(tmp), 0);
  908. end;
  909. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  910. procedure TutlSimpleList.Delete(const aIndex: Integer);
  911. begin
  912. DeleteIntern(aIndex, true);
  913. end;
  914. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  915. function TutlSimpleList.Extract(const aIndex: Integer): T;
  916. begin
  917. result := GetItem(aIndex);
  918. DeleteIntern(aIndex, false);
  919. end;
  920. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  921. procedure TutlSimpleList.PushFirst(constref aItem: T);
  922. begin
  923. InsertIntern(0, aItem);
  924. end;
  925. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  926. function TutlSimpleList.PopFirst(const aFreeItem: Boolean): T;
  927. begin
  928. if aFreeItem
  929. then FillByte(result{%H-}, SizeOf(result), 0)
  930. else result := GetItem(0);
  931. DeleteIntern(0, aFreeItem);
  932. end;
  933. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  934. procedure TutlSimpleList.PushLast(constref aItem: T);
  935. begin
  936. InsertIntern(Count, aItem);
  937. end;
  938. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  939. function TutlSimpleList.PopLast(const aFreeItem: Boolean): T;
  940. begin
  941. if aFreeItem
  942. then FillByte(result{%H-}, SizeOf(result), 0)
  943. else result := GetItem(Count-1);
  944. DeleteIntern(Count-1, aFreeItem);
  945. end;
  946. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  947. //TutlCustomList////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  948. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  949. function TutlCustomList.IndexOf(const aItem: T): Integer;
  950. begin
  951. result := Count-1;
  952. while (result >= 0)
  953. and not fEqualityComparer.EqualityCompare(Items[result], aItem)
  954. do
  955. dec(result);
  956. end;
  957. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  958. function TutlCustomList.Extract(const aItem: T; const aDefault: T): T;
  959. var
  960. i: Integer;
  961. begin
  962. i := IndexOf(aItem);
  963. if (i >= 0) then begin
  964. result := Items[i];
  965. DeleteIntern(i, false);
  966. end else
  967. result := aDefault;
  968. end;
  969. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  970. function TutlCustomList.Remove(const aItem: T): Integer;
  971. begin
  972. result := IndexOf(aItem);
  973. if (result >= 0) then
  974. DeleteIntern(result, true);
  975. end;
  976. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  977. constructor TutlCustomList.Create(const aEqualityComparer: IEqualityComparer; const aOwnsItems: Boolean);
  978. begin
  979. if not Assigned(aEqualityComparer) then
  980. raise EArgumentNilException.Create('aEqualityComparer');
  981. inherited Create(aOwnsItems);
  982. fEqualityComparer := aEqualityComparer;
  983. end;
  984. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  985. destructor TutlCustomList.Destroy;
  986. begin
  987. fEqualityComparer := nil;
  988. inherited Destroy;
  989. end;
  990. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  991. //TutlList//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  992. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  993. constructor TutlList.Create(const aOwnsItems: Boolean);
  994. begin
  995. inherited Create(TEqualityComparer.Create, aOwnsItems);
  996. end;
  997. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  998. //TutlCustomHashSet/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  999. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1000. procedure TutlCustomHashSet.SetCount(const aValue: Integer);
  1001. begin
  1002. raise ENotSupportedException.Create('SetCount not supported');
  1003. end;
  1004. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1005. procedure TutlCustomHashSet.SetItem(const aIndex: Integer; aValue: T);
  1006. begin
  1007. if not fComparer.EqualityCompare(GetItem(aIndex), aValue) then
  1008. EInvalidOperation.Create('values are not equal');
  1009. inherited SetItem(aIndex, aValue);
  1010. end;
  1011. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1012. function TutlCustomHashSet.Add(constref aItem: T): Boolean;
  1013. var
  1014. i: Integer;
  1015. begin
  1016. result := not TBinarySearch.Search(self, fComparer, aItem, i);
  1017. if result then
  1018. InsertIntern(i, aItem);
  1019. end;
  1020. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1021. function TutlCustomHashSet.Contains(constref aItem: T): Boolean;
  1022. var
  1023. i: Integer;
  1024. begin
  1025. result := TBinarySearch.Search(self, fComparer, aItem, i);
  1026. end;
  1027. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1028. function TutlCustomHashSet.IndexOf(constref aItem: T): Integer;
  1029. begin
  1030. if not TBinarySearch.Search(self, fComparer, aItem, result) then
  1031. result := -1;
  1032. end;
  1033. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1034. function TutlCustomHashSet.Remove(constref aItem: T): Boolean;
  1035. var
  1036. i: Integer;
  1037. begin
  1038. result := TBinarySearch.Search(self, fComparer, aItem, i);
  1039. if result then
  1040. DeleteIntern(i, true);
  1041. end;
  1042. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1043. procedure TutlCustomHashSet.Delete(const aIndex: Integer);
  1044. begin
  1045. DeleteIntern(aIndex, true);
  1046. end;
  1047. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1048. constructor TutlCustomHashSet.Create(const aComparer: IComparer; const aOwnsItems: Boolean);
  1049. begin
  1050. inherited Create(aOwnsItems);
  1051. fComparer := aComparer;
  1052. end;
  1053. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1054. destructor TutlCustomHashSet.Destroy;
  1055. begin
  1056. fComparer := nil;
  1057. inherited Destroy;
  1058. end;
  1059. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1060. //TutlHastSet///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1061. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1062. constructor TutlHashSet.Create(const aOwnsItems: Boolean);
  1063. begin
  1064. inherited Create(TComparer.Create, aOwnsItems);
  1065. end;
  1066. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1067. //TutlCustomMap.THashSet////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1068. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1069. procedure TutlCustomMap.THashSet.Release(var aItem: TKeyValuePair; const aFreeItem: Boolean);
  1070. begin
  1071. if not utlFinalizeObject(aItem.Key, TypeInfo(aItem.Key), fOwner.OwnsKeys and aFreeItem) then
  1072. Finalize(aItem.Key);
  1073. if not utlFinalizeObject(aItem.Value, TypeInfo(aItem.Value), fOwner.OwnsValues and aFreeItem) then
  1074. Finalize(aItem.Key);
  1075. inherited Release(aItem, aFreeItem);
  1076. end;
  1077. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1078. constructor TutlCustomMap.THashSet.Create(const aOwner: TutlCustomMap; const aComparer: IComparer);
  1079. begin
  1080. inherited Create(aComparer, true);
  1081. fOwner := aOwner;
  1082. end;
  1083. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1084. //TutlCustomMap.TKeyValuePairComparer///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1085. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1086. function TutlCustomMap.TKeyValuePairComparer.EqualityCompare(constref i1, i2: TKeyValuePair): Boolean;
  1087. begin
  1088. result := fComparer.EqualityCompare(i1.Key, i2.Key);
  1089. end;
  1090. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1091. function TutlCustomMap.TKeyValuePairComparer.Compare(constref i1, i2: TKeyValuePair): Integer;
  1092. begin
  1093. result := fComparer.Compare(i1.Key, i2.Key);
  1094. end;
  1095. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1096. constructor TutlCustomMap.TKeyValuePairComparer.Create(aComparer: IComparer);
  1097. begin
  1098. if not Assigned(aComparer) then
  1099. raise EArgumentNilException.Create('aComparer');
  1100. inherited Create;
  1101. fComparer := aComparer;
  1102. end;
  1103. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1104. destructor TutlCustomMap.TKeyValuePairComparer.Destroy;
  1105. begin
  1106. fComparer := nil;
  1107. inherited Destroy;
  1108. end;
  1109. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1110. //TutlCustomMap.TKeyEnumerator//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1111. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1112. function TutlCustomMap.TKeyEnumerator.InternalMoveNext: Boolean;
  1113. begin
  1114. result := fEnumerator.MoveNext;
  1115. end;
  1116. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1117. procedure TutlCustomMap.TKeyEnumerator.InternalReset;
  1118. begin
  1119. fEnumerator.Reset;
  1120. end;
  1121. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1122. function TutlCustomMap.TKeyEnumerator.GetCurrent: TKey;
  1123. begin
  1124. result := fEnumerator.GetCurrent.Key;
  1125. end;
  1126. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1127. constructor TutlCustomMap.TKeyEnumerator.Create(aEnumerator: IutlKeyValuePairEnumerator);
  1128. begin
  1129. if not Assigned(aEnumerator) then
  1130. raise EArgumentNilException.Create('aEnumerator');
  1131. fEnumerator := aEnumerator;
  1132. inherited Create;
  1133. end;
  1134. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1135. //TutlCustomMap.TValueEnumerator////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1136. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1137. function TutlCustomMap.TValueEnumerator.InternalMoveNext: Boolean;
  1138. begin
  1139. result := fEnumerator.MoveNext;
  1140. end;
  1141. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1142. procedure TutlCustomMap.TValueEnumerator.InternalReset;
  1143. begin
  1144. fEnumerator.Reset;
  1145. end;
  1146. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1147. function TutlCustomMap.TValueEnumerator.GetCurrent: TValue;
  1148. begin
  1149. result := fEnumerator.GetCurrent.Value;
  1150. end;
  1151. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1152. constructor TutlCustomMap.TValueEnumerator.Create(aEnumerator: IutlKeyValuePairEnumerator);
  1153. begin
  1154. if not Assigned(aEnumerator) then
  1155. raise EArgumentNilException.Create('aEnumerator');
  1156. fEnumerator := aEnumerator;
  1157. inherited Create;
  1158. end;
  1159. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1160. //TutlCustomMap.TKeyCollection//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1161. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1162. function TutlCustomMap.TKeyCollection.GetEnumerator: IKeyEnumerator;
  1163. begin
  1164. result := TKeyEnumerator.Create(fHashSet.GetUtlEnumerator);
  1165. end;
  1166. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1167. function TutlCustomMap.TKeyCollection.GetUtlEnumerator: IutlKeyEnumerator;
  1168. begin
  1169. result := TKeyEnumerator.Create(fHashSet.GetUtlEnumerator);
  1170. end;
  1171. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1172. function TutlCustomMap.TKeyCollection.GetCount: Integer;
  1173. begin
  1174. result := fHashSet.Count;
  1175. end;
  1176. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1177. function TutlCustomMap.TKeyCollection.GetItem(const aIndex: Integer): TKey;
  1178. begin
  1179. result := fHashSet[aIndex].Key;
  1180. end;
  1181. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1182. constructor TutlCustomMap.TKeyCollection.Create(const aHashSet: THashSet);
  1183. begin
  1184. inherited Create;
  1185. fHashSet := aHashSet;
  1186. end;
  1187. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1188. //TutlCustomMap.TKeyValuePairCollection/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1189. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1190. function TutlCustomMap.TKeyValuePairCollection.GetEnumerator: IKeyValuePairEnumerator;
  1191. begin
  1192. result := fHashSet.GetEnumerator;
  1193. end;
  1194. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1195. function TutlCustomMap.TKeyValuePairCollection.GetUtlEnumerator: IutlKeyValuePairEnumerator;
  1196. begin
  1197. result := fHashSet.GetUtlEnumerator;
  1198. end;
  1199. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1200. function TutlCustomMap.TKeyValuePairCollection.GetCount: Integer;
  1201. begin
  1202. result := fHashSet.Count;
  1203. end;
  1204. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1205. function TutlCustomMap.TKeyValuePairCollection.GetItem(const aIndex: Integer): TKeyValuePair;
  1206. begin
  1207. result := fHashSet[aIndex];
  1208. end;
  1209. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1210. constructor TutlCustomMap.TKeyValuePairCollection.Create(const aHashSet: THashSet);
  1211. begin
  1212. inherited Create;
  1213. fHashSet := aHashSet;
  1214. end;
  1215. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1216. //TutlCustomMap/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1217. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1218. function TutlCustomMap.GetValue(aKey: TKey): TValue;
  1219. var
  1220. i: Integer;
  1221. kvp: TKeyValuePair;
  1222. begin
  1223. kvp.Key := aKey;
  1224. i := fHashSetRef.IndexOf(kvp);
  1225. if (i < 0)
  1226. then FillByte(result{%H-}, SizeOf(result), 0)
  1227. else result := fHashSetRef[i].Value;
  1228. end;
  1229. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1230. function TutlCustomMap.GetValueAt(const aIndex: Integer): TValue;
  1231. begin
  1232. result := fHashSetRef[aIndex].Value;
  1233. end;
  1234. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1235. function TutlCustomMap.GetCount: Integer;
  1236. begin
  1237. result := fHashSetRef.Count;
  1238. end;
  1239. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1240. function TutlCustomMap.GetIsEmpty: Boolean;
  1241. begin
  1242. result := fHashSetRef.IsEmpty;
  1243. end;
  1244. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1245. function TutlCustomMap.GetCapacity: Integer;
  1246. begin
  1247. result := fHashSetRef.Capacity;
  1248. end;
  1249. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1250. function TutlCustomMap.GetCanShrink: Boolean;
  1251. begin
  1252. result := fHashSetRef.CanShrink;
  1253. end;
  1254. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1255. function TutlCustomMap.GetCanExpand: Boolean;
  1256. begin
  1257. result := fHashSetRef.CanExpand;
  1258. end;
  1259. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1260. procedure TutlCustomMap.SetCapacity(const aValue: Integer);
  1261. begin
  1262. fHashSetRef.Capacity := aValue;
  1263. end;
  1264. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1265. procedure TutlCustomMap.SetCanShrink(const aValue: Boolean);
  1266. begin
  1267. fHashSetRef.CanShrink := aValue;
  1268. end;
  1269. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1270. procedure TutlCustomMap.SetCanExpand(const aValue: Boolean);
  1271. begin
  1272. fHashSetRef.CanExpand := aValue;
  1273. end;
  1274. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1275. procedure TutlCustomMap.SetValue(aKey: TKey; const aValue: TValue);
  1276. var
  1277. i: Integer;
  1278. kvp: TKeyValuePair;
  1279. begin
  1280. kvp.Key := aKey;
  1281. kvp.Value := aValue;
  1282. i := fHashSetRef.IndexOf(kvp);
  1283. if (i < 0) then begin
  1284. if not fAutoCreate then
  1285. raise EInvalidOperation.Create('key not found');
  1286. fHashSetRef.Add(kvp);
  1287. end else
  1288. fHashSetRef[i] := kvp;
  1289. end;
  1290. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1291. procedure TutlCustomMap.SetValueAt(const aIndex: Integer; const aValue: TValue);
  1292. var
  1293. kvp: TKeyValuePair;
  1294. begin
  1295. kvp := fHashSetRef[aIndex];
  1296. kvp.Value := aValue;
  1297. fHashSetRef[aIndex] := kvp;
  1298. end;
  1299. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1300. function TutlCustomMap.GetEnumerator: IValueEnumerator;
  1301. begin
  1302. result := TValueEnumerator.Create(fHashSetRef.GetUtlEnumerator);
  1303. end;
  1304. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1305. function TutlCustomMap.GetUtlEnumerator: IutlValueEnumerator;
  1306. begin
  1307. result := TValueEnumerator.Create(fHashSetRef.GetUtlEnumerator);
  1308. end;
  1309. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1310. procedure TutlCustomMap.Add(constref aKey: TKey; constref aValue: TValue);
  1311. begin
  1312. if not TryAdd(aKey, aValue) then
  1313. raise EInvalidOperation.Create('key already exists');
  1314. end;
  1315. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1316. function TutlCustomMap.TryAdd(constref aKey: TKey; constref aValue: TValue): Boolean;
  1317. var
  1318. kvp: TKeyValuePair;
  1319. begin
  1320. kvp.Key := aKey;
  1321. kvp.Value := aValue;
  1322. result := fHashSetRef.Add(kvp);
  1323. end;
  1324. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1325. function TutlCustomMap.TryGetValue(constref aKey: TKey; out aValue: TValue): Boolean;
  1326. var
  1327. i: Integer;
  1328. begin
  1329. i := IndexOf(aKey);
  1330. result := (i >= 0);
  1331. if result
  1332. then aValue := fHashSetRef[i].Value
  1333. else FillByte(result, SizeOf(result), 0);
  1334. end;
  1335. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1336. function TutlCustomMap.IndexOf(constref aKey: TKey): Integer;
  1337. var
  1338. kvp: TKeyValuePair;
  1339. begin
  1340. kvp.Key := aKey;
  1341. result := fHashSetRef.IndexOf(kvp);
  1342. end;
  1343. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1344. function TutlCustomMap.Contains(constref aKey: TKey): Boolean;
  1345. begin
  1346. result := (IndexOf(aKey) >= 0);
  1347. end;
  1348. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1349. function TutlCustomMap.Remove(constref aKey: TKey): Boolean;
  1350. var
  1351. kvp: TKeyValuePair;
  1352. begin
  1353. kvp.Key := aKey;
  1354. result := fHashSetRef.Remove(kvp);
  1355. end;
  1356. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1357. procedure TutlCustomMap.Delete(constref aKey: TKey);
  1358. begin
  1359. if not Remove(aKey) then
  1360. raise EInvalidOperation.Create('key not found');
  1361. end;
  1362. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1363. procedure TutlCustomMap.DeleteAt(const aIndex: Integer);
  1364. begin
  1365. fHashSetRef.Delete(aIndex);
  1366. end;
  1367. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1368. procedure TutlCustomMap.Clear;
  1369. begin
  1370. fHashSetRef.Clear;
  1371. end;
  1372. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1373. constructor TutlCustomMap.Create(
  1374. const aHashSet: THashSet;
  1375. const aOwnsKeys: Boolean;
  1376. const aOwnsValues: Boolean);
  1377. begin
  1378. if not Assigned(aHashSet) then
  1379. EArgumentNilException.Create('aHashSet');
  1380. inherited Create;
  1381. fAutoCreate := false;
  1382. fHashSetRef := aHashSet;
  1383. fOwnsKeys := aOwnsKeys;
  1384. fOwnsValues := aOwnsValues;
  1385. fKeyCollection := TKeyCollection.Create(fHashSetRef);
  1386. fKeyValuePairCollection := TKeyValuePairCollection.Create(fHashSetRef);
  1387. end;
  1388. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1389. destructor TutlCustomMap.Destroy;
  1390. begin
  1391. Clear;
  1392. FreeAndNil(fKeyValuePairCollection);
  1393. FreeAndNil(fKeyCollection);
  1394. fHashSetRef := nil;
  1395. inherited Destroy;
  1396. end;
  1397. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1398. //TutlMap///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1399. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1400. constructor TutlMap.Create(const aOwnsKeys: Boolean; const aOwnsValues: Boolean);
  1401. begin
  1402. fHashSetImpl := THashSet.Create(self, TKeyValuePairComparer.Create(TComparer.Create));
  1403. inherited Create(fHashSetImpl, aOwnsKeys, aOwnsValues);
  1404. end;
  1405. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1406. destructor TutlMap.Destroy;
  1407. begin
  1408. inherited Destroy;
  1409. FreeAndNil(fHashSetImpl);
  1410. end;
  1411. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1412. //TutlHandleManager//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1413. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1414. procedure TutlHandleManager.Grow;
  1415. var
  1416. oldIdx, newIdx, i: Integer;
  1417. begin
  1418. oldIdx := High(fEntries);
  1419. SetLength(fEntries, Length(fEntries) + fGrowSize);
  1420. newIdx := High(fEntries);
  1421. for i := oldIdx to newIdx do
  1422. fEntries[i].NextFreeIndex := i + 1;
  1423. end;
  1424. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1425. function TutlHandleManager.Get(const aHandle: TutlHandle): T;
  1426. begin
  1427. if not TryGet(aHandle, result) then
  1428. raise EArgumentException.Create('unknown or invalid handle');
  1429. end;
  1430. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1431. function TutlHandleManager.TryGet(const aHandle: TutlHandle; out aData: T): Boolean;
  1432. begin
  1433. with THandleData(aHandle) do begin
  1434. result := IsValid(aHandle);
  1435. if result
  1436. then aData := fEntries[Index].Data
  1437. else FillByte(aData, SizeOf(T), 0);
  1438. end;
  1439. end;
  1440. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1441. function TutlHandleManager.Add(constref aData: T; const aIdentifier: Word): TutlHandle;
  1442. var
  1443. i: Integer;
  1444. begin
  1445. i := fFirstFreeIndex;
  1446. if (High(fEntries) < i) then
  1447. Grow;
  1448. Assert(not fEntries[i].IsActive);
  1449. fFirstFreeIndex := fEntries[i].NextFreeIndex;
  1450. fEntries[i].NextFreeIndex := 0;
  1451. fEntries[i].Counter := fEntries[i].Counter + 1;
  1452. if (fEntries[i].Counter = 0) then
  1453. fEntries[i].Counter := 1;
  1454. fEntries[i].IsActive := true;
  1455. fEntries[i].Data := aData;
  1456. inc(fCount);
  1457. with THandleData(result) do begin
  1458. Index := i;
  1459. Counter := fEntries[i].Counter;
  1460. Identifier := aIdentifier;
  1461. end;
  1462. end;
  1463. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1464. function TutlHandleManager.IsValid(const aHandle: TutlHandle): Boolean;
  1465. begin
  1466. with THandleData(aHandle) do begin
  1467. result := (fEntries[Index].Counter = Counter)
  1468. and (fEntries[Index].IsActive)
  1469. and (h.Index <= High(fEntries));
  1470. end;
  1471. end;
  1472. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1473. procedure TutlHandleManager.Update(const aHandle: TutlHandle; aData: T);
  1474. begin
  1475. if not IsValid(aHandle) then
  1476. raise EArgumentException.Create('unknown or invalid handle');
  1477. with THandleData(aHandle) do begin
  1478. if not utlFinalizeObject(fEntries[Index].Data, TypeInfo(T), fOwnsValues) then
  1479. Finalize(fEntries[Index].Data);
  1480. fEntries[Index].Data := aData;
  1481. end;
  1482. end;
  1483. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1484. procedure TutlHandleManager.Remove(const aHandle: TutlHandle);
  1485. begin
  1486. if not IsValid(aHandle) then
  1487. raise EArgumentException.Create('unknown or invalid handle');
  1488. with THandleData(aHandle) do begin
  1489. fEntries[Index].NextFreeIndex := fFirstFreeIndex;
  1490. fEntries[Index].IsActive := false;
  1491. fFirstFreeIndex := Index;
  1492. if not utlFinalizeObject(fEntries[Index].Data, TypeInfo(T), fOwnsValues) then
  1493. Finalize(fEntries[Index].Data);
  1494. end;
  1495. dec(fCount);
  1496. end;
  1497. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1498. procedure TutlHandleManager.Clear;
  1499. var
  1500. i: Integer;
  1501. begin
  1502. for i := low(fEntries) to high(fEntries) do begin
  1503. if fEntries[i].IsActive and not utlFinalizeObject(fEntries[i].Data, TypeInfo(T), fOwnsValues) then
  1504. Finalize(fEntries[i].Data);
  1505. end;
  1506. SetLength(fEntries, 0);
  1507. end;
  1508. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1509. constructor TutlHandleManager.Create(const aOwnsValues: Boolean);
  1510. begin
  1511. inherited Create;
  1512. fGrowSize := 50;
  1513. fCount := 0;
  1514. fFirstFreeIndex := 0;
  1515. fOwnsValues := aOwnsValues;
  1516. end;
  1517. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1518. destructor TutlHandleManager.Destroy;
  1519. begin
  1520. Clear;
  1521. inherited Destroy;
  1522. end;
  1523. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1524. class function TutlHandleManager.GetIdentifier(const aHandle: TutlHandle): Word;
  1525. begin
  1526. result := THandleData(aHandle).Identifier;
  1527. end;
  1528. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1529. //EutlEnumConvert///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1530. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1531. constructor EEnumConvertException.Create(const aValue, aExpectedType: String);
  1532. begin
  1533. inherited Create(Format('%s is not a %s', [aValue, aExpectedType]));
  1534. end;
  1535. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1536. //TutlEnumHelperBase////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1537. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1538. class procedure TutlEnumHelperBase.RegisterType(const aValues: TIntArray; const aNames: TStringArray);
  1539. begin
  1540. fValuesMap.Add(ClassName, aValues);
  1541. fNamesMap.Add (ClassName, aNames);
  1542. end;
  1543. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1544. class procedure TutlEnumHelperBase.UnregisterType;
  1545. begin
  1546. fValuesMap.Remove(ClassName);
  1547. fNamesMap.Remove(ClassName);
  1548. end;
  1549. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1550. class function TutlEnumHelperBase.ToString(const aValue: Integer; const aAllowOrd: Boolean = false): String;
  1551. var
  1552. i: Integer;
  1553. iArr: TIntArray;
  1554. sArr: TStringArray;
  1555. begin
  1556. iArr := fValuesMap[ClassName];
  1557. sArr := fNamesMap[ClassName];
  1558. for i := low(iArr) to high(iArr) do begin
  1559. if (iArr[i] = aValue) then begin
  1560. result := sArr[i];
  1561. exit;
  1562. end;
  1563. end;
  1564. if aAllowOrd
  1565. then result := IntToStr(aValue)
  1566. else result := '';
  1567. end;
  1568. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1569. class function TutlEnumHelperBase.TryToEnum(const aStr: String; out aValue: Integer; const aAllowOrd: Boolean = false): Boolean;
  1570. var
  1571. i: Integer;
  1572. iArr: TIntArray;
  1573. sArr: TStringArray;
  1574. begin
  1575. iArr := fValuesMap[ClassName];
  1576. sArr := fNamesMap[ClassName];
  1577. for i := low(sArr) to high(sArr) do begin
  1578. if (sArr[i] = aStr) then begin
  1579. result := true;
  1580. aValue := iArr[i];
  1581. exit;
  1582. end;
  1583. end;
  1584. if aAllowOrd
  1585. then result := TryStrToInt(aStr, aValue)
  1586. else result := false;
  1587. end;
  1588. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1589. class function TutlEnumHelperBase.ToEnum(const aStr: String; const aAllowOrd: Boolean): Integer;
  1590. begin
  1591. if not TryToEnum(aStr, result, aAllowOrd) then
  1592. raise EConvertError.Create(aStr + ' is an unknown enum value');
  1593. end;
  1594. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1595. class function TutlEnumHelperBase.ToEnum(const aStr: String; const aDefault: Integer; const aAllowOrd: Boolean): Integer;
  1596. begin
  1597. if not TryToEnum(aStr, result, aAllowOrd) then
  1598. result := aDefault;
  1599. end;
  1600. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1601. class function TutlEnumHelperBase.IntValues: TIntArray;
  1602. begin
  1603. result := fValuesMap[ClassName];
  1604. end;
  1605. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1606. class function TutlEnumHelperBase.Names: TStringArray;
  1607. begin
  1608. result := fNamesMap[ClassName];
  1609. end;
  1610. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1611. class constructor TutlEnumHelperBase.Initialize;
  1612. begin
  1613. fNamesMap := TNamesMap.Create(true, true);
  1614. fValuesMap := TValuesMap.Create(true, true);
  1615. end;
  1616. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1617. class destructor TutlEnumHelperBase.Finalize;
  1618. begin
  1619. FreeAndNil(fNamesMap);
  1620. FreeAndNil(fValuesMap);
  1621. end;
  1622. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1623. //TutlEnumHelper////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1624. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1625. class function TutlEnumHelper.ToString(const aValue: T; const aAllowOrd: Boolean): String;
  1626. begin
  1627. {$Push}
  1628. {$IOChecks OFF}
  1629. WriteStr(Result, aValue);
  1630. if IOResult = 107 then
  1631. Result := '';
  1632. {$Pop}
  1633. end;
  1634. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1635. class function TutlEnumHelper.TryToEnum(const aStr: String; out aValue: T; const aAllowOrd: Boolean): Boolean;
  1636. var
  1637. a: T;
  1638. i: Integer;
  1639. begin
  1640. a := T(0);
  1641. Result := false;
  1642. if Length(aStr) = 0 then
  1643. exit;
  1644. {$Push}
  1645. {$IOChecks OFF}
  1646. ReadStr(aStr, a);
  1647. Result := IOResult <> 106;
  1648. {$Pop}
  1649. if Result then
  1650. aValue := a
  1651. else if aAllowOrd then begin
  1652. result := TryStrToInt(aStr, i);
  1653. if result then
  1654. aValue := T(i);
  1655. end;
  1656. end;
  1657. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1658. class function TutlEnumHelper.ToEnum(const aStr: String; const aAllowOrd: Boolean): T;
  1659. begin
  1660. if not TryToEnum(aStr, result, aAllowOrd) then
  1661. raise EEnumConvertException.Create(aStr, TypeInfo^.Name);
  1662. end;
  1663. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1664. class function TutlEnumHelper.ToEnum(const aStr: String; const aDefault: T; const aAllowOrd: Boolean): T;
  1665. begin
  1666. if not TryToEnum(aStr, result, aAllowOrd) then
  1667. result := aDefault;
  1668. end;
  1669. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1670. class function TutlEnumHelper.Values: TValueArray;
  1671. begin
  1672. result := fValues;
  1673. end;
  1674. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1675. class function TutlEnumHelper.IntValues: TIntArray;
  1676. begin
  1677. result := fIntValues;
  1678. end;
  1679. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1680. class function TutlEnumHelper.Names: TStringArray;
  1681. begin
  1682. result := fNames;
  1683. end;
  1684. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1685. class function TutlEnumHelper.TypeInfo: PTypeInfo;
  1686. begin
  1687. result := fTypeInfo;
  1688. end;
  1689. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1690. class constructor TutlEnumHelper.Initialize;
  1691. var
  1692. tiArray: PTypeInfo;
  1693. tdArray, tdEnum: PTypeData;
  1694. PName: PShortString;
  1695. i: integer;
  1696. en: T;
  1697. sl: TStringList;
  1698. begin
  1699. {
  1700. See FPC Bug http://bugs.freepascal.org/view.php?id=27622
  1701. For Sparse Enums, the compiler won't give us TypeInfo, because it contains some wrong data. This is
  1702. safe, but sadly we don't even get the *correct* fields (TypeName, NameList), even though they are
  1703. generated in any case.
  1704. Fortunately, arrays do know this type info segment as their Element Type (and we declared one anyway).
  1705. }
  1706. tiArray := System.TypeInfo(TValueArray);
  1707. tdArray := GetTypeData(tiArray);
  1708. fTypeInfo := tdArray^.elType2;
  1709. {
  1710. Now that we have the TypeInfo, fill our values from it. This is safe because while the *values* in
  1711. TypeData are wrong for Sparse Enums, the *PName* are always correct.
  1712. }
  1713. tdEnum := GetTypeData(FTypeInfo);
  1714. PName := @tdEnum^.NameList;
  1715. sl := TStringList.Create;
  1716. try
  1717. while Length(PName^) > 0 do begin
  1718. {
  1719. Memory layout for TTypeData has the declaring EnumUnitName after the last NameList entry.
  1720. This can normally not be the same as a valid enum value, because it is in the same identifier
  1721. namespace. However, with scoped enums we might have the same name for module and element, because
  1722. the full identifier for the element would be TypeName.ElementName.
  1723. In either case, the next PShortString will point to a zero-length string, and the loop is left
  1724. with the last element being invalid (either empty or whatever value the unit-named element has).
  1725. }
  1726. sl.Add(PName^);
  1727. if TryToEnum(PName^, en) then
  1728. sl.Objects[sl.Count-1] := TObject({%H-}Pointer(PtrUInt(en)));
  1729. inc(PByte(PName), Length(PName^) + 1);
  1730. end;
  1731. sl.Delete(sl.Count-1); // remove the EnumUnitName item
  1732. SetLength(fValues, sl.Count);
  1733. SetLength(fIntValues, sl.Count);
  1734. SetLength(fNames, sl.Count);
  1735. for i := 0 to sl.Count-1 do begin
  1736. fNames[i] := sl[i];
  1737. fValues[i] := T(PtrUInt(sl.Objects[i]));
  1738. fIntValues[i] := Integer(fValues[i]);
  1739. end;
  1740. finally
  1741. FreeAndNil(sl);
  1742. end;
  1743. RegisterType(fIntValues, fNames);
  1744. end;
  1745. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1746. class destructor TutlEnumHelper.Finalize;
  1747. begin
  1748. Finalize(fNames);
  1749. Finalize(fValues);
  1750. Finalize(fIntValues);
  1751. UnregisterType;
  1752. end;
  1753. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1754. //TutlSetHelperBase/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1755. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1756. class function TutlSetHelperBase.IsSet(const aSet; const aSize: Integer; const aValue: Integer): Boolean;
  1757. begin
  1758. if (aValue >= 8*aSize) then
  1759. raise EOutOfRangeException.Create(aValue, 0, 8*aSize-1);
  1760. result := ((PByte(@aSet)[aValue shr 3] and (1 shl (aValue and 7))) <> 0);
  1761. end;
  1762. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1763. class procedure TutlSetHelperBase.SetValue(var aSet; const aSize: Integer; const aValue: Integer);
  1764. begin
  1765. if (aValue >= 8*aSize) then
  1766. raise EOutOfRangeException.Create(aValue, 0, 8*aSize-1);
  1767. PByte(@aSet)[aValue shr 3] := PByte(@aSet)[aValue shr 3] or (1 shl (aValue and 7));
  1768. end;
  1769. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1770. class procedure TutlSetHelperBase.ClearValue(var aSet; const aSize: Integer; const aValue: Integer);
  1771. begin
  1772. if (aValue >= 8*aSize) then
  1773. raise EOutOfRangeException.Create(aValue, 0, 8*aSize-1);
  1774. PByte(@aSet)[aValue shr 3] := PByte(@aSet)[aValue shr 3] and not (1 shl (aValue and 7));
  1775. end;
  1776. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1777. class procedure TutlSetHelperBase.RegisterEnumHelper(const aHelper: TutlEnumHelperBaseClass);
  1778. begin
  1779. fEnumHelpers.Add(ClassName, aHelper);
  1780. end;
  1781. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1782. class procedure TutlSetHelperBase.UnregisterEnumHelper;
  1783. begin
  1784. fEnumHelpers.Remove(ClassName);
  1785. end;
  1786. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1787. class function TutlSetHelperBase.ToString(const aSet; const aSize: Integer; const aSeparator: String;
  1788. const aAllowOrd: Boolean): String;
  1789. var
  1790. i: Integer;
  1791. h: TutlEnumHelperBaseClass;
  1792. arr: TutlEnumHelperBase.TIntArray;
  1793. begin
  1794. h := EnumHelper;
  1795. if not Assigned(h) then
  1796. raise EInvalidOperation.Create('enum helper class is not set');
  1797. result := '';
  1798. arr := h.IntValues;
  1799. for i in arr do begin
  1800. if IsSet(aSet, aSize, i) then begin
  1801. if result > '' then
  1802. result := result + aSeparator;
  1803. result := result + h.ToString(i, aAllowOrd);
  1804. end;
  1805. end;
  1806. end;
  1807. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1808. class function TutlSetHelperBase.TryToSet(const aStr: String; out aSet; const aSize: Integer; const aAllowOrd: Boolean): Boolean;
  1809. begin
  1810. result := TryToSet(aStr, ',', aSet, aSize, aAllowOrd);
  1811. end;
  1812. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1813. class function TutlSetHelperBase.TryToSet(const aStr: String; const aSeparator: String; out aSet; const aSize: Integer; const aAllowOrd: Boolean): Boolean;
  1814. var
  1815. i, j, e: Integer;
  1816. s: String;
  1817. h: TutlEnumHelperBaseClass;
  1818. begin
  1819. if (aSeparator = '') then
  1820. raise EArgumentException.Create('''aSeparator'' can not be empty');
  1821. h := EnumHelper;
  1822. if not Assigned(h) then
  1823. raise EInvalidOperation.Create('enum helper class is not set');
  1824. result := true;
  1825. i := 1;
  1826. j := 1;
  1827. FillByte(aSet{%H-}, aSize, 0);
  1828. while (i <= Length(aStr)) do begin
  1829. if (Copy(aStr, i, Length(aSeparator)) = aSeparator) then begin
  1830. s := Trim(copy(aStr, j, i - j));
  1831. if (s <> '') then begin
  1832. result := result and h.TryToEnum(s, e);
  1833. if not result then
  1834. exit;
  1835. SetValue(aSet, aSize, e);
  1836. j := i + Length(aSeparator);
  1837. end;
  1838. end;
  1839. inc(i);
  1840. end;
  1841. s := Trim(copy(aStr, j, i - j));
  1842. if (s <> '') then begin
  1843. result := result and h.TryToEnum(s, e);
  1844. if not result then
  1845. exit;
  1846. SetValue(aSet, aSize, e);
  1847. end;
  1848. end;
  1849. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1850. class function TutlSetHelperBase.Compare(const aSet1; const aSet2; const aSize: Integer): Integer;
  1851. var
  1852. e: Integer;
  1853. h: TutlEnumHelperBaseClass;
  1854. begin
  1855. h := EnumHelper;
  1856. if not Assigned(h) then
  1857. raise EInvalidOperation.Create('enum helper class is not set');
  1858. result := 0;
  1859. for e in h.IntValues do begin
  1860. if IsSet(aSet1, aSize, e) and not IsSet(aSet2, aSize, e) then begin
  1861. result := 1;
  1862. break;
  1863. end else
  1864. if not IsSet(aSet1, aSize, e) and IsSet(aSet2, aSize, e) then begin
  1865. result := -1;
  1866. break;
  1867. end;
  1868. end;
  1869. end;
  1870. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1871. class function TutlSetHelperBase.EnumHelper: TutlEnumHelperBaseClass;
  1872. begin
  1873. result := fEnumHelpers[ClassName];
  1874. end;
  1875. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1876. class constructor TutlSetHelperBase.Initialize;
  1877. begin
  1878. fEnumHelpers := TEnumHelperMap.Create(true, true);
  1879. end;
  1880. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1881. class destructor TutlSetHelperBase.Finalize;
  1882. begin
  1883. FreeAndNil(fEnumHelpers);
  1884. end;
  1885. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1886. //TutlSetHelper/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1887. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1888. class function TutlSetHelper.ToString(const aValue: TSet; const aSeparator: String; const aAllowOrd: Boolean): String;
  1889. begin
  1890. result := ToString(aValue, SizeOf(aValue), aSeparator, aAllowOrd);
  1891. end;
  1892. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1893. class function TutlSetHelper.TryToSet(const aStr: String; out aValue: TSet; const aAllowOrd: Boolean): Boolean;
  1894. begin
  1895. result := TryToSet(aStr, ',', aValue, SizeOf(aValue), aAllowOrd);
  1896. end;
  1897. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1898. class function TutlSetHelper.TryToSet(const aStr: String; const aSeparator: String; out aValue: TSet; const aAllowOrd: Boolean): Boolean;
  1899. begin
  1900. result := TryToSet(aStr, aSeparator, aValue, SizeOf(aValue), aAllowOrd);
  1901. end;
  1902. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1903. class function TutlSetHelper.ToSet(const aStr: String; const aDefault: TSet; const aAllowOrd: Boolean): TSet;
  1904. begin
  1905. if not TryToSet(aStr, ',', result, SizeOf(result), aAllowOrd) then
  1906. result := aDefault;
  1907. end;
  1908. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1909. class function TutlSetHelper.ToSet(const aStr: String; const aAllowOrd: Boolean): TSet;
  1910. begin
  1911. if not TryToSet(aStr, ',', result, SizeOf(result), aAllowOrd) then
  1912. raise EEnumConvertException.CreateFmt('"%s" is an invalid value', [aStr]);
  1913. end;
  1914. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1915. class function TutlSetHelper.Compare(const aSet1, aSet2: TSet): Integer;
  1916. begin
  1917. result := Compare(aSet1, aSet2, SizeOf(aSet1));
  1918. end;
  1919. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1920. class constructor TutlSetHelper.Initialize;
  1921. begin
  1922. RegisterEnumHelper(TEnumHelper);
  1923. end;
  1924. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1925. class destructor TutlSetHelper.Finalize;
  1926. begin
  1927. UnregisterEnumHelper();
  1928. end;
  1929. end.