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

2708 line
108 KiB

  1. unit uutlGenerics;
  2. {$mode objfpc}{$H+}
  3. {$modeswitch advancedrecords}
  4. interface
  5. uses
  6. Classes, SysUtils, typinfo,
  7. uutlCommon, uutlArrayContainer, uutlListBase, uutlComparer, uutlAlgorithm, uutlInterfaces,
  8. uutlEnumerator;
  9. type
  10. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  11. generic TutlQueue<T> = class(
  12. specialize TutlArrayContainer<T>
  13. , specialize IEnumerable<T>
  14. , specialize IutlEnumerable<T>
  15. , specialize IutlReadOnlyArray<T>)
  16. private type
  17. TEnumerator = class(
  18. specialize TutlEnumerator<T>
  19. , specialize IEnumerator<T>
  20. , specialize IutlEnumerator<T>)
  21. strict private
  22. fOwner: TutlQueue;
  23. fReversed: Boolean;
  24. fCurrent: Integer;
  25. protected { TutlEnumerator }
  26. function InternalMoveNext: Boolean; override;
  27. procedure InternalReset; override;
  28. {$IFDEF UTL_ENUMERATORS}
  29. public { IutlEnumerator }
  30. function Reverse: IutlEnumerator; override;
  31. {$ENDIF}
  32. public { IEnumerator }
  33. function GetCurrent: T; override;
  34. public
  35. constructor Create(const aOwner: TutlQueue; const aReversed: Boolean);
  36. end;
  37. public type
  38. IEnumerator = specialize IEnumerator<T>;
  39. IutlEnumerator = specialize IutlEnumerator<T>;
  40. strict private
  41. fCount: Integer;
  42. fReadPos: Integer;
  43. fWritePos: Integer;
  44. function GetItem(const aIndex: Integer): T;
  45. procedure SetItem(const aIndex: Integer; aItem: T);
  46. protected
  47. function GetCount: Integer; override;
  48. procedure SetCount(const aValue: Integer); override;
  49. procedure SetCapacity(const aValue: integer); override;
  50. public { IEnumerable }
  51. function GetEnumerator: IEnumerator;
  52. public { IutlEnumerable }
  53. function GetUtlEnumerator: IutlEnumerator;
  54. public
  55. property Count: Integer read GetCount;
  56. property IsEmpty;
  57. property Capacity;
  58. property CanExpand;
  59. property CanShrink;
  60. property OwnsItems;
  61. property Items[const aIndex: Integer]: T read GetItem write SetItem; default;
  62. procedure Enqueue(constref aItem: T);
  63. function Dequeue: T;
  64. function Dequeue(const aFreeItem: Boolean): T;
  65. function Peek: T;
  66. procedure ShrinkToFit;
  67. procedure Clear;
  68. constructor Create(const aOwnsItems: Boolean);
  69. destructor Destroy; override;
  70. end;
  71. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  72. generic TutlStack<T> = class(
  73. specialize TutlArrayContainer<T>
  74. , specialize IEnumerable<T>
  75. , specialize IutlEnumerable<T>
  76. , specialize IutlReadOnlyArray<T>)
  77. private type
  78. TEnumerator = class(
  79. specialize TutlMemoryEnumerator<T>
  80. , specialize IEnumerator<T>
  81. , specialize IutlEnumerator<T>)
  82. private
  83. fOwner: TutlStack;
  84. protected { IEnumerator }
  85. procedure InternalReset; override;
  86. {$IFDEF UTL_ENUMERATORS}
  87. public { IutlEnumerator }
  88. function Reverse: IutlEnumerator; override;
  89. {$ENDIF}
  90. public
  91. constructor Create(const aOwner: TutlStack; const aReversed: Boolean); reintroduce;
  92. end;
  93. public type
  94. IEnumerator = specialize IEnumerator<T>;
  95. IutlEnumerator = specialize IutlEnumerator<T>;
  96. strict private
  97. fCount: Integer;
  98. function GetItem(const aIndex: Integer): T;
  99. procedure SetItem(const aIndex: Integer; aValue: T);
  100. protected
  101. function GetCount: Integer; override;
  102. procedure SetCount(const aValue: Integer); override;
  103. public { IEnumerable }
  104. function GetEnumerator: IEnumerator;
  105. public { IutlEnumerable }
  106. function GetUtlEnumerator: IutlEnumerator;
  107. public
  108. property Count: Integer read GetCount;
  109. property IsEmpty;
  110. property Capacity;
  111. property CanExpand;
  112. property CanShrink;
  113. property OwnsItems;
  114. property Items[const aIndex: Integer]: T read GetItem write SetItem; default;
  115. procedure Push(constref aItem: T);
  116. function Pop: T;
  117. function Pop(const aFreeItem: Boolean): T;
  118. function Peek: T;
  119. procedure ShrinkToFit;
  120. procedure Clear;
  121. constructor Create(const aOwnsItems: Boolean);
  122. destructor Destroy; override;
  123. end;
  124. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  125. generic TutlSimpleList<T> = class(
  126. specialize TutlListBase<T>
  127. , specialize IutlReadOnlyArray<T>
  128. , specialize IutlArray<T>)
  129. strict private
  130. function GetFirst: T;
  131. function GetLast: T;
  132. public
  133. property First: T read GetFirst;
  134. property Last: T read GetLast;
  135. property Items[const aIndex: Integer]: T read GetItem write SetItem; default;
  136. function Add (constref aItem: T): Integer;
  137. procedure Insert (const aIndex: Integer; constref aItem: T);
  138. procedure Exchange (const aIndex1, aIndex2: Integer);
  139. procedure Move (const aCurrentIndex, aNewIndex: Integer);
  140. procedure Delete (const aIndex: Integer);
  141. function Extract (const aIndex: Integer): T;
  142. procedure PushFirst (constref aItem: T);
  143. function PopFirst (const aFreeItem: Boolean): T;
  144. procedure PushLast (constref aItem: T);
  145. function PopLast (const aFreeItem: Boolean): T;
  146. end;
  147. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  148. generic TutlCustomList<T> = class(
  149. specialize TutlSimpleList<T>)
  150. public type
  151. IEqualityComparer = specialize IutlEqualityComparer<T>;
  152. strict private
  153. fEqualityComparer: IEqualityComparer;
  154. public
  155. function IndexOf (const aItem: T): Integer;
  156. function Extract (const aItem: T; const aDefault: T): T; overload;
  157. function Remove (const aItem: T): Integer;
  158. constructor Create (aEqualityComparer: IEqualityComparer; const aOwnsItems: Boolean);
  159. destructor Destroy; override;
  160. end;
  161. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  162. generic TutlList<T> = class(
  163. specialize TutlCustomList<T>)
  164. private type
  165. TQuickSortImpl = specialize TutlQuickSort<T>;
  166. IComparer = TQuickSortimpl.IComparer;
  167. TReverseComp = specialize TutlReverseComparer<T>;
  168. public type
  169. TEqualityComparer = specialize TutlEqualityComparer<T>;
  170. public
  171. procedure Sort(aComparer: IComparer; const aReverse: boolean = false);
  172. constructor Create(const aOwnsItems: Boolean);
  173. end;
  174. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  175. generic TutlCustomHashSet<T> = class(
  176. specialize TutlListBase<T>
  177. , specialize IutlReadOnlyArray<T>)
  178. private type
  179. TBinarySearch = specialize TutlBinarySearch<T>;
  180. public type
  181. IComparer = specialize IutlComparer<T>;
  182. strict private
  183. fComparer: IComparer;
  184. protected
  185. procedure SetCount (const aValue: Integer); override;
  186. procedure SetItem (const aIndex: Integer; aValue: T); override;
  187. public
  188. property Count: Integer read GetCount;
  189. property Items[const aIndex: Integer]: T read GetItem write SetItem; default;
  190. function Add (constref aItem: T): Boolean;
  191. function Contains (constref aItem: T): Boolean;
  192. function IndexOf (constref aItem: T): Integer;
  193. function Remove (constref aItem: T; const aFreeItem: Boolean = true): Boolean;
  194. procedure Delete (const aIndex: Integer);
  195. constructor Create (aComparer: IComparer; const aOwnsItems: Boolean);
  196. destructor Destroy; override;
  197. end;
  198. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  199. generic TutlHashSet<T> = class(
  200. specialize TutlCustomHashSet<T>)
  201. public type
  202. TComparer = specialize TutlComparer<T>;
  203. public
  204. constructor Create(const aOwnsItems: Boolean);
  205. end;
  206. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  207. generic TutlCustomMap<TKey, TValue> = class(
  208. TutlInterfaceNoRefCount
  209. , specialize IutlEnumerable<TValue>)
  210. public type
  211. ////////////////////////////////////////////////////////////////////////////////////////////////
  212. TKeyValuePair = packed record
  213. Key: TKey;
  214. Value: TValue;
  215. end;
  216. ////////////////////////////////////////////////////////////////////////////////////////////////
  217. IValueEnumerator = specialize IEnumerator<TValue>;
  218. IutlValueEnumerator = specialize IutlEnumerator<TValue>;
  219. IKeyEnumerator = specialize IEnumerator<TKey>;
  220. IutlKeyEnumerator = specialize IutlEnumerator<TKey>;
  221. IKeyValuePairEnumerator = specialize IEnumerator<TKeyValuePair>;
  222. IutlKeyValuePairEnumerator = specialize IutlEnumerator<TKeyValuePair>;
  223. ////////////////////////////////////////////////////////////////////////////////////////////////
  224. THashSet = class(
  225. specialize TutlCustomHashSet<TKeyValuePair>)
  226. strict private
  227. fOwner: TutlCustomMap;
  228. protected
  229. procedure Release(var aItem: TKeyValuePair; const aFreeItem: Boolean); override;
  230. public
  231. constructor Create(const aOwner: TutlCustomMap; aComparer: IComparer);
  232. end;
  233. ////////////////////////////////////////////////////////////////////////////////////////////////
  234. IComparer = specialize IutlComparer<TKey>;
  235. TKeyValuePairComparer = class(
  236. TInterfacedObject
  237. , THashSet.IComparer)
  238. strict private
  239. fComparer: IComparer;
  240. public { IutlEqualityComparer }
  241. function EqualityCompare(constref i1, i2: TKeyValuePair): Boolean;
  242. public { IutlComparer }
  243. function Compare(constref i1, i2: TKeyValuePair): Integer;
  244. public
  245. constructor Create(aComparer: IComparer);
  246. destructor Destroy; override;
  247. end;
  248. ////////////////////////////////////////////////////////////////////////////////////////////////
  249. TKeyEnumerator = class(
  250. specialize TutlEnumerator<TKey>
  251. , IKeyEnumerator
  252. , IutlKeyEnumerator)
  253. strict private
  254. fEnumerator: IutlKeyValuePairEnumerator;
  255. protected { TutlEnumerator }
  256. function InternalMoveNext: Boolean; override;
  257. procedure InternalReset; override;
  258. public { IEnumerator }
  259. function GetCurrent: TKey; override;
  260. public
  261. constructor Create(aEnumerator: IutlKeyValuePairEnumerator);
  262. end;
  263. ////////////////////////////////////////////////////////////////////////////////////////////////
  264. TValueEnumerator = class(
  265. specialize TutlEnumerator<TValue>
  266. , IValueEnumerator
  267. , IutlValueEnumerator)
  268. strict private
  269. fEnumerator: IutlKeyValuePairEnumerator;
  270. protected { TutlEnumerator }
  271. function InternalMoveNext: Boolean; override;
  272. procedure InternalReset; override;
  273. public { IEnumerator }
  274. function GetCurrent: TValue; override;
  275. public
  276. constructor Create(aEnumerator: IutlKeyValuePairEnumerator);
  277. end;
  278. ////////////////////////////////////////////////////////////////////////////////////////////////
  279. TKeyCollection = class(
  280. TutlInterfaceNoRefCount
  281. , specialize IutlReadOnlyArray<TKey>
  282. , specialize IutlEnumerable<TKey>)
  283. strict private
  284. fHashSet: THashSet;
  285. public { IEnumerable }
  286. function GetEnumerator: IKeyEnumerator;
  287. public { IutlEnumerable }
  288. function GetUtlEnumerator: IutlKeyEnumerator;
  289. public { IutlReadOnlyArray }
  290. function GetCount: Integer;
  291. function GetItem(const aIndex: Integer): TKey;
  292. property Count: Integer read GetCount;
  293. property Items[const aIndex: Integer]: TKey read GetItem; default;
  294. public
  295. constructor Create(const aHashSet: THashSet);
  296. end;
  297. ////////////////////////////////////////////////////////////////////////////////////////////////
  298. TKeyValuePairCollection = class(
  299. TutlInterfaceNoRefCount
  300. , specialize IutlReadOnlyArray<TKeyValuePair>
  301. , specialize IutlEnumerable<TKeyValuePair>)
  302. strict private
  303. fHashSet: THashSet;
  304. public { IEnumerable }
  305. function GetEnumerator: IKeyValuePairEnumerator;
  306. public { IutlEnumerable }
  307. function GetUtlEnumerator: IutlKeyValuePairEnumerator;
  308. public { IutlReadOnlyArray }
  309. function GetCount: Integer;
  310. function GetItem(const aIndex: Integer): TKeyValuePair;
  311. property Count: Integer read GetCount;
  312. property Items[const aIndex: Integer]: TKeyValuePair read GetItem; default;
  313. public
  314. constructor Create(const aHashSet: THashSet);
  315. end;
  316. strict private
  317. fAutoCreate: Boolean;
  318. fOwnsKeys: Boolean;
  319. fOwnsValues: Boolean;
  320. fHashSetRef: THashSet;
  321. fKeyCollection: TKeyCollection;
  322. fKeyValuePairCollection: TKeyValuePairCollection;
  323. function GetValue (aKey: TKey): TValue; inline;
  324. function GetValueAt (const aIndex: Integer): TValue; inline;
  325. function GetCount: Integer; inline;
  326. function GetIsEmpty: Boolean; inline;
  327. function GetCapacity: Integer; inline;
  328. function GetCanShrink: Boolean; inline;
  329. function GetCanExpand: Boolean; inline;
  330. procedure SetCapacity (const aValue: Integer); inline;
  331. procedure SetCanShrink (const aValue: Boolean); inline;
  332. procedure SetCanExpand (const aValue: Boolean); inline;
  333. protected
  334. procedure SetValue (aKey: TKey; const aValue: TValue); virtual;
  335. procedure SetValueAt (const aIndex: Integer; const aValue: TValue); virtual;
  336. public { IEnumerable }
  337. function GetEnumerator: IValueEnumerator;
  338. public { IutlEnumerable }
  339. function GetUtlEnumerator: IutlValueEnumerator;
  340. public
  341. property Values [aKey: TKey]: TValue read GetValue write SetValue; default;
  342. property ValueAt[const aIndex: Integer]: TValue read GetValueAt write SetValueAt;
  343. property Keys: TKeyCollection read fKeyCollection;
  344. property KeyValuePairs: TKeyValuePairCollection read fKeyValuePairCollection;
  345. property Count: Integer read GetCount;
  346. property IsEmpty: Boolean read GetIsEmpty;
  347. property Capacity: Integer read GetCapacity write SetCapacity;
  348. property CanShrink: Boolean read GetCanShrink write SetCanShrink;
  349. property CanExpand: Boolean read GetCanExpand write SetCanExpand;
  350. property OwnsKeys: Boolean read fOwnsKeys write fOwnsKeys;
  351. property OwnsValues: Boolean read fOwnsValues write fOwnsValues;
  352. property AutoCreate: Boolean read fAutoCreate write fAutoCreate;
  353. procedure Add (constref aKey: TKey; constref aValue: TValue);
  354. function TryAdd (constref aKey: TKey; constref aValue: TValue): Boolean;
  355. function TryGetValue (constref aKey: TKey; out aValue: TValue): Boolean;
  356. function IndexOf (constref aKey: TKey): Integer;
  357. function Contains (constref aKey: TKey): Boolean;
  358. function Remove (constref aKey: TKey; const aFreeItem: Boolean = true): Boolean;
  359. procedure Delete (constref aKey: TKey);
  360. procedure DeleteAt (const aIndex: Integer);
  361. procedure Clear;
  362. constructor Create(const aHashSet: THashSet; const aOwnsKeys: Boolean; const aOwnsValues: Boolean);
  363. destructor Destroy; override;
  364. end;
  365. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  366. generic TutlMap<TKey, TValue> = class(
  367. specialize TutlCustomMap<TKey, TValue>)
  368. public type
  369. TComparer = specialize TutlComparer<TKey>;
  370. strict private
  371. fHashSetImpl: THashSet;
  372. public
  373. constructor Create(const aOwnsKeys: Boolean; const aOwnsValues: Boolean);
  374. destructor Destroy; override;
  375. end;
  376. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  377. TutlHandle = QWord;
  378. generic TutlHandleManager<T> = class(
  379. TutlInterfacedObject
  380. , specialize IutlEnumerable<TutlHandle>)
  381. private type
  382. THandleData = packed record
  383. case Integer of
  384. 0: (
  385. Handle: TutlHandle // 0..63
  386. );
  387. 1: (
  388. Index: Cardinal; // 0..31 index in data array (unique for each priority)
  389. Counter: Word; // 32..47 reusage counter
  390. TypeID: Byte; // 48..55 Stored Data Type
  391. Priority: Byte; // 56..63 Priority to share handles between multiple systems
  392. );
  393. end;
  394. TIndex = Cardinal;
  395. TEntryStatus = byte;
  396. PHandleEntry = ^THandleEntry;
  397. THandleEntry = packed record
  398. Next: TIndex; // 0..31 next used/free item
  399. Prev: TIndex; // 32..63 prev used/free item
  400. Counter: Word; // 64..79 current counter value
  401. Status: TEntryStatus; // 80..87 item status
  402. TypeID: Byte; // 88..95 type id
  403. Data: T; // actual data
  404. end;
  405. THandleEntries = array of THandleEntry;
  406. PPriorityItem = ^TPriorityItem;
  407. TPriorityItem = packed record
  408. FirstFree: TIndex;
  409. LastFree: TIndex;
  410. FirstUsed: TIndex;
  411. LastUsed: TIndex;
  412. Handles: THandleEntries;
  413. function GetHandleEntry(const aIndex: TIndex): PHandleEntry;
  414. procedure Grow(const aSize: Integer = 0);
  415. procedure PushFront(const aIndex: TIndex; var FirstIndex, LastIndex: TIndex; const aStatus: TEntryStatus);
  416. procedure PushBack (const aIndex: TIndex; var FirstIndex, LastIndex: TIndex; const aStatus: TEntryStatus);
  417. procedure Remove (const aIndex: TIndex; var FirstIndex, LastIndex: TIndex; const aStatus: TEntryStatus);
  418. function PopFront(var FirstIndex, LastIndex: TIndex; const aStatus: TEntryStatus; const aCanGrow: Boolean): TIndex;
  419. function PopBack (var FirstIndex, LastIndex: TIndex; const aStatus: TEntryStatus; const aCanGrow: Boolean): TIndex;
  420. procedure PushFrontFreeIndex(const aIndex: TIndex); inline;
  421. procedure PushBackFreeIndex (const aIndex: TIndex); inline;
  422. procedure PushFrontUsedIndex(const aIndex: TIndex); inline;
  423. procedure PushBackUsedIndex (const aIndex: TIndex); inline;
  424. procedure RemoveFreeIndex (const aIndex: TIndex); inline;
  425. procedure RemoveUsedIndex (const aIndex: TIndex); inline;
  426. function PopFrontFreeIndex: TIndex;
  427. function PopBackFreeIndex: TIndex;
  428. function PopFrontUsedIndex: TIndex;
  429. function PopBackUsedIndex: TIndex;
  430. end;
  431. TPriorityItems = array of TPriorityItem;
  432. TEnumerator = class(specialize TutlEnumerator<TutlHandle>)
  433. private
  434. fOwner: TutlHandleManager;
  435. fPriority: Integer;
  436. fIndex: TIndex;
  437. fHandle: THandleEntry;
  438. protected
  439. function InternalMoveNext: Boolean; override;
  440. procedure InternalReset; override;
  441. public
  442. function GetCurrent: TutlHandle; override;
  443. constructor Create(const aOwner: TutlHandleManager);
  444. end;
  445. private const
  446. UNKNOWN_INDEX: TIndex = high(TIndex);
  447. GROW_SIZE = 100;
  448. ENTRY_STATUS_UNKNOWN: byte = 0;
  449. ENTRY_STATUS_FREE: byte = 1;
  450. ENTRY_STATUS_USED: byte = 2;
  451. private
  452. class function HighIndex(constref aEntries: THandleEntries): TIndex; inline;
  453. public type
  454. IEnumerator = specialize IEnumerator<TutlHandle>;
  455. IutlEnumerator = specialize IutlEnumerator<TutlHandle>;
  456. private
  457. fCount: Integer;
  458. fItems: TPriorityItems;
  459. fOwnsValues: Boolean;
  460. function GetPriorityItem(const aPriority: Byte): PPriorityItem;
  461. public
  462. function GetValue (const aHandle: TutlHandle): T;
  463. function TryGetValue (const aHandle: TutlHandle; out aData: T): Boolean;
  464. procedure SetValue (const aHandle: TutlHandle; aData: T);
  465. function TrySetValue (const aHandle: TutlHandle; aData: T): Boolean;
  466. function Add (const aTypeID: Byte; const aPriority: Byte; constref aData: T): TutlHandle;
  467. function IsValid (const aHandle: TutlHandle): Boolean; inline;
  468. procedure Update (const aHandle: TutlHandle; aData: T);
  469. function Remove (const aHandle: TutlHandle): Boolean;
  470. procedure Delete (const aHandle: TutlHandle);
  471. procedure Clear;
  472. public { IutlEnumerable }
  473. function GetEnumerator: IEnumerator;
  474. function GetUtlEnumerator: IutlEnumerator;
  475. public
  476. property Items[const aHandle: TutlHandle]: T read GetValue write SetValue; default;
  477. property Count: Integer read fCount;
  478. constructor Create(const aOwnsValues: Boolean);
  479. destructor Destroy; override;
  480. public
  481. class function GetTypeID (const aHandle: TutlHandle): Byte; inline;
  482. class function GetPriority(const aHandle: TutlHandle): Byte; inline;
  483. end;
  484. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  485. EEnumConvertException = class(EConvertError)
  486. public
  487. constructor Create(const aValue, aExpectedType: String);
  488. end;
  489. TutlEnumHelperBaseClass = class of TutlEnumHelperBase;
  490. TutlEnumHelperBase = class
  491. public type
  492. TIntArray = array of Integer;
  493. TStringArray = array of String;
  494. private type
  495. TValuesMap = specialize TutlMap<string, TIntArray>;
  496. TNamesMap = specialize TutlMap<string, TStringArray>;
  497. private class var
  498. fValuesMap: TValuesMap;
  499. fNamesMap: TNamesMap;
  500. protected
  501. class procedure RegisterType (const aValues: TIntArray; const aNames: TStringArray);
  502. class procedure UnregisterType();
  503. public
  504. class function ToString (const aValue: Integer; const aAllowOrd: Boolean = false): String; reintroduce;
  505. class function TryToEnum (const aStr: String; out aValue: Integer; const aAllowOrd: Boolean = false): Boolean;
  506. class function ToEnum (const aStr: String; const aAllowOrd: Boolean = false): Integer; overload;
  507. class function ToEnum (const aStr: String; const aDefault: Integer; const aAllowOrd: Boolean = false): Integer; overload;
  508. class function IntValues: TIntArray;
  509. class function Names: TStringArray;
  510. public
  511. class constructor Initialize;
  512. class destructor Finalize;
  513. end;
  514. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  515. generic TutlEnumHelper<T> = class(TutlEnumHelperBase)
  516. public type
  517. TEnumType = T;
  518. TValueArray = array of T;
  519. private class var
  520. fValues: TValueArray;
  521. fNames: TStringArray;
  522. fIntValues: TIntArray;
  523. fTypeInfo: PTypeInfo;
  524. public
  525. class function ToString (const aValue: T; const aAllowOrd: Boolean = false): String; reintroduce;
  526. class function TryToEnum (const aStr: String; out aValue: T; const aAllowOrd: Boolean = false): Boolean;
  527. class function ToEnum (const aStr: String; const aAllowOrd: Boolean = false): T; overload;
  528. class function ToEnum (const aStr: String; const aDefault: T; const aAllowOrd: Boolean = false): T; overload;
  529. class function Values: TValueArray; inline;
  530. class function IntValues: TIntArray; inline;
  531. class function Names: TStringArray; inline;
  532. class function TypeInfo: PTypeInfo; inline;
  533. class constructor Initialize;
  534. class destructor Finalize;
  535. end;
  536. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  537. TutlSetHelperBase = class
  538. private type
  539. TEnumHelperMap = specialize TutlMap<string, TutlEnumHelperBaseClass>;
  540. private class var
  541. fEnumHelpers: TEnumHelperMap;
  542. private
  543. class function IsSet (const aSet; const aSize: Integer; const aValue: Integer): Boolean;
  544. class procedure SetValue (var aSet; const aSize: Integer; const aValue: Integer);
  545. class procedure ClearValue(var aSet; const aSize: Integer; const aValue: Integer);
  546. protected
  547. class procedure RegisterEnumHelper(const aHelper: TutlEnumHelperBaseClass);
  548. class procedure UnregisterEnumHelper;
  549. public
  550. class function ToString(
  551. const aSet;
  552. const aSize: Integer;
  553. const aSeparator: String = ', ';
  554. const aAllowOrd: Boolean = false): String; reintroduce;
  555. class function TryToSet(
  556. const aStr: String;
  557. out aSet;
  558. const aSize: Integer;
  559. const aAllowOrd: Boolean = false): Boolean;
  560. class function TryToSet(
  561. const aStr: String;
  562. const aSeparator: String;
  563. out aSet;
  564. const aSize: Integer;
  565. const aAllowOrd: Boolean = false): Boolean;
  566. class function Compare(
  567. const aSet1;
  568. const aSet2;
  569. const aSize: Integer): Integer;
  570. class function EnumHelper: TutlEnumHelperBaseClass;
  571. class constructor Initialize;
  572. class destructor Finalize;
  573. end;
  574. TutlSetHelperBaseClass = class of TutlSetHelperBase;
  575. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  576. generic TutlSetHelper<TEnum, TSet> = class(TutlSetHelperBase)
  577. public type
  578. TEnumHelper = specialize TutlEnumHelper<TEnum>;
  579. TEnumType = TEnum;
  580. TSetType = TSet;
  581. public
  582. class function ToString(
  583. const aValue: TSet;
  584. const aSeparator: String = ', ';
  585. const aAllowOrd: Boolean = false): String; overload;
  586. class function TryToSet(
  587. const aStr: String;
  588. out aValue: TSet;
  589. const aAllowOrd: Boolean = false): Boolean; overload;
  590. class function TryToSet(
  591. const aStr: String;
  592. const aSeparator: String;
  593. out aValue: TSet;
  594. const aAllowOrd: Boolean = false): Boolean; overload;
  595. class function ToSet(
  596. const aStr: String;
  597. const aDefault: TSet;
  598. const aAllowOrd: Boolean = false): TSet; overload;
  599. class function ToSet(
  600. const aStr: String;
  601. const aAllowOrd: Boolean = false): TSet; overload;
  602. class function Compare(
  603. const aSet1, aSet2: TSet): Integer; overload;
  604. class constructor Initialize;
  605. class destructor Finalize;
  606. end;
  607. implementation
  608. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  609. //TutlQueue.TEnumerator/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  610. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  611. function TutlQueue.TEnumerator.InternalMoveNext: Boolean;
  612. begin
  613. if fReversed
  614. then dec(fCurrent)
  615. else inc(fCurrent);
  616. result := (0 <= fCurrent) and (fCurrent < fOwner.Count);
  617. end;
  618. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  619. procedure TutlQueue.TEnumerator.InternalReset;
  620. begin
  621. if fReversed
  622. then fCurrent := fOwner.Count
  623. else fCurrent := -1;
  624. end;
  625. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  626. {$IFDEF UTL_ENUMERATORS}
  627. function TutlQueue.TEnumerator.Reverse: IutlEnumerator;
  628. begin
  629. result := TEnumerator.Create(fOwner, not fReversed);
  630. end;
  631. {$ENDIF}
  632. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  633. function TutlQueue.TEnumerator.GetCurrent: T;
  634. begin
  635. result := fOwner[fCurrent];
  636. end;
  637. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  638. constructor TutlQueue.TEnumerator.Create(const aOwner: TutlQueue; const aReversed: Boolean);
  639. begin
  640. if not Assigned(aOwner) then
  641. raise EArgumentNilException.Create('aOwner');
  642. fOwner := aOwner;
  643. fReversed := aReversed;
  644. inherited Create;
  645. end;
  646. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  647. //TutlQueue/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  648. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  649. function TutlQueue.GetItem(const aIndex: Integer): T;
  650. var
  651. i: Integer;
  652. begin
  653. if (aIndex < 0) or (aIndex >= fCount) then
  654. raise EOutOfRangeException.Create(aIndex, 0, fCount-1);
  655. i := fReadPos + aIndex;
  656. if (i >= Capacity) then
  657. i := i - Capacity;
  658. result := GetInternalItem(i)^;
  659. end;
  660. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  661. procedure TutlQueue.SetItem(const aIndex: Integer; aItem: T);
  662. var
  663. i: Integer;
  664. begin
  665. if (aIndex < 0) or (aIndex >= fCount) then
  666. raise EOutOfRangeException.Create(aIndex, 0, fCount-1);
  667. i := fReadPos + aIndex;
  668. if (i >= Capacity) then
  669. i := i - Capacity;
  670. GetInternalItem(i)^ := aItem;
  671. end;
  672. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  673. function TutlQueue.GetCount: Integer;
  674. begin
  675. result := fCount;
  676. end;
  677. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  678. procedure TutlQueue.SetCount(const aValue: Integer);
  679. begin
  680. raise ENotSupportedException.Create('SetCount not supported');
  681. end;
  682. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  683. procedure TutlQueue.SetCapacity(const aValue: integer);
  684. var
  685. cnt: Integer;
  686. begin
  687. if (aValue < Count) then
  688. raise EArgumentException.Create('can not reduce capacity below count');
  689. if (aValue < Capacity) then begin // is shrinking
  690. if (fReadPos <= fWritePos) then begin // ReadPos Before WritePos -> Move To Begin
  691. System.Move(GetInternalItem(fReadPos)^, GetInternalItem(0)^, SizeOf(T) * Count);
  692. fReadPos := 0;
  693. fWritePos := Count;
  694. end else if (fReadPos > fWritePos) then begin // ReadPos Behind WritePos
  695. cnt := Capacity - aValue;
  696. System.Move(GetInternalItem(fReadPos)^, GetInternalItem(fReadPos - cnt)^, SizeOf(T) * cnt);
  697. dec(fReadPos, cnt);
  698. end;
  699. end;
  700. inherited SetCapacity(aValue);
  701. // ReadPos After WritePos and Expanding
  702. if (fReadPos > fWritePos) and (aValue > Capacity) then begin
  703. cnt := aValue - Capacity;
  704. System.Move(GetInternalItem(fReadPos)^, GetInternalItem(fReadPos - cnt)^, SizeOf(T) * cnt);
  705. inc(fReadPos, cnt);
  706. end;
  707. end;
  708. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  709. function TutlQueue.GetEnumerator: IEnumerator;
  710. begin
  711. result := TEnumerator.Create(self, false);
  712. result.Reset;
  713. end;
  714. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  715. function TutlQueue.GetUtlEnumerator: IutlEnumerator;
  716. begin
  717. result := TEnumerator.Create(self, false);
  718. result.Reset;
  719. end;
  720. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  721. procedure TutlQueue.Enqueue(constref aItem: T);
  722. begin
  723. if (Count = Capacity) then
  724. Expand;
  725. fWritePos := fWritePos mod Capacity;
  726. GetInternalItem(fWritePos)^ := aItem;
  727. inc(fCount);
  728. inc(fWritePos);
  729. end;
  730. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  731. function TutlQueue.Dequeue: T;
  732. begin
  733. result := Dequeue(false);
  734. end;
  735. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  736. function TutlQueue.Dequeue(const aFreeItem: Boolean): T;
  737. var
  738. p: PT;
  739. begin
  740. if IsEmpty then
  741. raise EInvalidOperation.Create('queue is empty');
  742. p := GetInternalItem(fReadPos);
  743. if aFreeItem
  744. then FillByte(result{%H-}, SizeOf(result), 0)
  745. else result := p^;
  746. Release(p^, aFreeItem);
  747. dec(fCount);
  748. fReadPos := (fReadPos + 1) mod Capacity;
  749. end;
  750. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  751. function TutlQueue.Peek: T;
  752. begin
  753. if IsEmpty then
  754. raise EInvalidOperation.Create('queue is empty');
  755. result := GetInternalItem(fReadPos)^;
  756. end;
  757. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  758. procedure TutlQueue.ShrinkToFit;
  759. begin
  760. Shrink(true);
  761. end;
  762. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  763. procedure TutlQueue.Clear;
  764. begin
  765. while (fReadPos <> fWritePos) do begin
  766. Release(GetInternalItem(fReadPos)^, true);
  767. fReadPos := (fReadPos + 1) mod Capacity;
  768. end;
  769. fCount := 0;
  770. if CanShrink then
  771. ShrinkToFit;
  772. end;
  773. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  774. constructor TutlQueue.Create(const aOwnsItems: Boolean);
  775. begin
  776. inherited Create(aOwnsItems);
  777. fCount := 0;
  778. fReadPos := 0;
  779. fWritePos := 0;
  780. end;
  781. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  782. destructor TutlQueue.Destroy;
  783. begin
  784. Clear;
  785. inherited Destroy;
  786. end;
  787. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  788. //TutlStack.TEnumerator/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  789. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  790. procedure TutlStack.TEnumerator.InternalReset;
  791. begin
  792. First := 0;
  793. Last := fOwner.Count-1;
  794. if (Last >= First)
  795. then Memory := fOwner.GetInternalItem(0)
  796. else Memory := nil;
  797. inherited InternalReset;
  798. end;
  799. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  800. {$IFDEF UTL_ENUMERATORS}
  801. function TutlStack.TEnumerator.Reverse: IutlEnumerator;
  802. begin
  803. result := TEnumerator.Create(fOwner, not Reversed);
  804. end;
  805. {$ENDIF}
  806. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  807. constructor TutlStack.TEnumerator.Create(const aOwner: TutlStack; const aReversed: Boolean);
  808. begin
  809. if not Assigned(aOwner) then
  810. raise EArgumentNilException.Create('aOwner');
  811. fOwner := aOwner;
  812. inherited Create(nil, aReversed, 0, -1);
  813. end;
  814. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  815. //TutlStack/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  816. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  817. function TutlStack.GetItem(const aIndex: Integer): T;
  818. begin
  819. if (aIndex < 0) or (aIndex >= fCount) then
  820. raise EOutOfRangeException.Create(aIndex, 0, fCount-1);
  821. result := GetInternalItem(aIndex)^;
  822. end;
  823. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  824. procedure TutlStack.SetItem(const aIndex: Integer; aValue: T);
  825. begin
  826. if (aIndex < 0) or (aIndex >= fCount) then
  827. raise EOutOfRangeException.Create(aIndex, 0, fCount-1);
  828. GetInternalItem(aIndex)^ := aValue;
  829. end;
  830. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  831. function TutlStack.GetCount: Integer;
  832. begin
  833. result := fCount;
  834. end;
  835. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  836. procedure TutlStack.SetCount(const aValue: Integer);
  837. begin
  838. raise ENotSupportedException.Create('SetCount not supported');
  839. end;
  840. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  841. function TutlStack.GetEnumerator: IEnumerator;
  842. begin
  843. result := TEnumerator.Create(self, false);
  844. end;
  845. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  846. function TutlStack.GetUtlEnumerator: IutlEnumerator;
  847. begin
  848. result := TEnumerator.Create(self, false);
  849. end;
  850. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  851. procedure TutlStack.Push(constref aItem: T);
  852. begin
  853. if (Count = Capacity) then
  854. Expand;
  855. GetInternalItem(fCount)^ := aItem;
  856. inc(fCount);
  857. end;
  858. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  859. function TutlStack.Pop: T;
  860. begin
  861. Pop(false);
  862. end;
  863. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  864. function TutlStack.Pop(const aFreeItem: Boolean): T;
  865. var
  866. p: PT;
  867. begin
  868. if IsEmpty then
  869. raise EInvalidOperation.Create('stack is empty');
  870. p := GetInternalItem(fCount-1);
  871. if aFreeItem
  872. then FillByte(result{%H-}, SizeOf(result), 0)
  873. else result := p^;
  874. Release(p^, aFreeItem);
  875. dec(fCount);
  876. end;
  877. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  878. function TutlStack.Peek: T;
  879. begin
  880. if IsEmpty then
  881. raise EInvalidOperation.Create('stack is empty');
  882. result := GetInternalItem(fCount-1)^;
  883. end;
  884. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  885. procedure TutlStack.ShrinkToFit;
  886. begin
  887. Shrink(true);
  888. end;
  889. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  890. procedure TutlStack.Clear;
  891. begin
  892. while (fCount > 0) do begin
  893. dec(fCount);
  894. Release(GetInternalItem(fCount)^, true);
  895. end;
  896. if CanShrink then
  897. ShrinkToFit;
  898. end;
  899. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  900. constructor TutlStack.Create(const aOwnsItems: Boolean);
  901. begin
  902. inherited Create(aOwnsItems);
  903. fCount := 0
  904. end;
  905. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  906. destructor TutlStack.Destroy;
  907. begin
  908. Clear;
  909. inherited Destroy;
  910. end;
  911. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  912. //TutlSimpleList////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  913. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  914. function TutlSimpleList.GetFirst: T;
  915. begin
  916. if IsEmpty then
  917. raise EInvalidOperation.Create('list is empty');
  918. result := GetInternalItem(0)^;
  919. end;
  920. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  921. function TutlSimpleList.GetLast: T;
  922. begin
  923. if IsEmpty then
  924. raise EInvalidOperation.Create('list is empty');
  925. result := GetInternalItem(Count-1)^;
  926. end;
  927. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  928. function TutlSimpleList.Add(constref aItem: T): Integer;
  929. begin
  930. result := Count;
  931. InsertIntern(result, aItem);
  932. end;
  933. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  934. procedure TutlSimpleList.Insert(const aIndex: Integer; constref aItem: T);
  935. begin
  936. InsertIntern(aIndex, aItem);
  937. end;
  938. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  939. procedure TutlSimpleList.Exchange(const aIndex1, aIndex2: Integer);
  940. var
  941. tmp: T;
  942. p1, p2: PT;
  943. begin
  944. if (aIndex1 < 0) or (aIndex1 >= Count) then
  945. raise EOutOfRangeException.Create(aIndex1, 0, Count-1);
  946. if (aIndex2 < 0) or (aIndex2 >= Count) then
  947. raise EOutOfRangeException.Create(aIndex2, 0, Count-1);
  948. p1 := GetInternalItem(aIndex1);
  949. p2 := GetInternalItem(aIndex2);
  950. System.Move(p1^, tmp{%H-}, SizeOf(T));
  951. System.Move(p2^, p1^, SizeOf(T));
  952. System.Move(tmp, p2^, SizeOf(T));
  953. FillByte(tmp, SizeOf(tmp), 0);
  954. end;
  955. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  956. procedure TutlSimpleList.Move(const aCurrentIndex, aNewIndex: Integer);
  957. var
  958. tmp: T;
  959. cur, new: PT;
  960. begin
  961. if (aCurrentIndex < 0) or (aCurrentIndex >= Count) then
  962. raise EOutOfRangeException.Create(aCurrentIndex, 0, Count-1);
  963. if (aNewIndex < 0) or (aNewIndex >= Count) then
  964. raise EOutOfRangeException.Create(aNewIndex, 0, Count-1);
  965. if (aCurrentIndex = aNewIndex) then
  966. exit;
  967. cur := GetInternalItem(aCurrentIndex);
  968. new := GetInternalItem(aNewIndex);
  969. System.Move(cur^, tmp{%H-}, SizeOf(T));
  970. if (aNewIndex > aCurrentIndex) then begin
  971. System.Move((cur+1)^, cur^, SizeOf(T) * (aNewIndex - aCurrentIndex));
  972. end else begin
  973. System.Move(new^, (new+1)^, SizeOf(T) * (aCurrentIndex - aNewIndex));
  974. end;
  975. System.Move(tmp, new^, SizeOf(T));
  976. FillByte(tmp, SizeOf(tmp), 0);
  977. end;
  978. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  979. procedure TutlSimpleList.Delete(const aIndex: Integer);
  980. begin
  981. DeleteIntern(aIndex, true);
  982. end;
  983. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  984. function TutlSimpleList.Extract(const aIndex: Integer): T;
  985. begin
  986. result := GetItem(aIndex);
  987. DeleteIntern(aIndex, false);
  988. end;
  989. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  990. procedure TutlSimpleList.PushFirst(constref aItem: T);
  991. begin
  992. InsertIntern(0, aItem);
  993. end;
  994. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  995. function TutlSimpleList.PopFirst(const aFreeItem: Boolean): T;
  996. begin
  997. if aFreeItem
  998. then FillByte(result{%H-}, SizeOf(result), 0)
  999. else result := GetItem(0);
  1000. DeleteIntern(0, aFreeItem);
  1001. end;
  1002. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1003. procedure TutlSimpleList.PushLast(constref aItem: T);
  1004. begin
  1005. InsertIntern(Count, aItem);
  1006. end;
  1007. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1008. function TutlSimpleList.PopLast(const aFreeItem: Boolean): T;
  1009. begin
  1010. if aFreeItem
  1011. then FillByte(result{%H-}, SizeOf(result), 0)
  1012. else result := GetItem(Count-1);
  1013. DeleteIntern(Count-1, aFreeItem);
  1014. end;
  1015. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1016. //TutlCustomList////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1017. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1018. function TutlCustomList.IndexOf(const aItem: T): Integer;
  1019. begin
  1020. result := Count-1;
  1021. while (result >= 0)
  1022. and not fEqualityComparer.EqualityCompare(Items[result], aItem)
  1023. do
  1024. dec(result);
  1025. end;
  1026. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1027. function TutlCustomList.Extract(const aItem: T; const aDefault: T): T;
  1028. var
  1029. i: Integer;
  1030. begin
  1031. i := IndexOf(aItem);
  1032. if (i >= 0) then begin
  1033. result := Items[i];
  1034. DeleteIntern(i, false);
  1035. end else
  1036. result := aDefault;
  1037. end;
  1038. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1039. function TutlCustomList.Remove(const aItem: T): Integer;
  1040. begin
  1041. result := IndexOf(aItem);
  1042. if (result >= 0) then
  1043. DeleteIntern(result, true);
  1044. end;
  1045. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1046. constructor TutlCustomList.Create(aEqualityComparer: IEqualityComparer; const aOwnsItems: Boolean);
  1047. begin
  1048. if not Assigned(aEqualityComparer) then
  1049. raise EArgumentNilException.Create('aEqualityComparer');
  1050. inherited Create(aOwnsItems);
  1051. fEqualityComparer := aEqualityComparer;
  1052. end;
  1053. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1054. destructor TutlCustomList.Destroy;
  1055. begin
  1056. fEqualityComparer := nil;
  1057. inherited Destroy;
  1058. end;
  1059. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1060. //TutlList//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1061. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1062. procedure TutlList.Sort(aComparer: IComparer; const aReverse: boolean);
  1063. begin
  1064. if aReverse then
  1065. aComparer:= TReverseComp.Create(aComparer);
  1066. TQuickSortImpl.Sort(Self, aComparer);
  1067. end;
  1068. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1069. constructor TutlList.Create(const aOwnsItems: Boolean);
  1070. begin
  1071. inherited Create(TEqualityComparer.Create, aOwnsItems);
  1072. end;
  1073. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1074. //TutlCustomHashSet/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1075. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1076. procedure TutlCustomHashSet.SetCount(const aValue: Integer);
  1077. begin
  1078. raise ENotSupportedException.Create('SetCount not supported');
  1079. end;
  1080. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1081. procedure TutlCustomHashSet.SetItem(const aIndex: Integer; aValue: T);
  1082. begin
  1083. if not fComparer.EqualityCompare(GetItem(aIndex), aValue) then
  1084. EInvalidOperation.Create('values are not equal');
  1085. inherited SetItem(aIndex, aValue);
  1086. end;
  1087. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1088. function TutlCustomHashSet.Add(constref aItem: T): Boolean;
  1089. var
  1090. i: Integer;
  1091. begin
  1092. result := not TBinarySearch.Search(self, fComparer, aItem, i);
  1093. if result then
  1094. InsertIntern(i, aItem);
  1095. end;
  1096. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1097. function TutlCustomHashSet.Contains(constref aItem: T): Boolean;
  1098. var
  1099. i: Integer;
  1100. begin
  1101. result := TBinarySearch.Search(self, fComparer, aItem, i);
  1102. end;
  1103. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1104. function TutlCustomHashSet.IndexOf(constref aItem: T): Integer;
  1105. begin
  1106. if not TBinarySearch.Search(self, fComparer, aItem, result) then
  1107. result := -1;
  1108. end;
  1109. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1110. function TutlCustomHashSet.Remove(constref aItem: T; const aFreeItem: Boolean): Boolean;
  1111. var
  1112. i: Integer;
  1113. begin
  1114. result := TBinarySearch.Search(self, fComparer, aItem, i);
  1115. if result then
  1116. DeleteIntern(i, aFreeItem);
  1117. end;
  1118. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1119. procedure TutlCustomHashSet.Delete(const aIndex: Integer);
  1120. begin
  1121. DeleteIntern(aIndex, true);
  1122. end;
  1123. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1124. constructor TutlCustomHashSet.Create(aComparer: IComparer; const aOwnsItems: Boolean);
  1125. begin
  1126. inherited Create(aOwnsItems);
  1127. fComparer := aComparer;
  1128. end;
  1129. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1130. destructor TutlCustomHashSet.Destroy;
  1131. begin
  1132. fComparer := nil;
  1133. inherited Destroy;
  1134. end;
  1135. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1136. //TutlHastSet///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1137. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1138. constructor TutlHashSet.Create(const aOwnsItems: Boolean);
  1139. begin
  1140. inherited Create(TComparer.Create, aOwnsItems);
  1141. end;
  1142. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1143. //TutlCustomMap.THashSet////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1144. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1145. procedure TutlCustomMap.THashSet.Release(var aItem: TKeyValuePair; const aFreeItem: Boolean);
  1146. begin
  1147. if not utlFinalizeObject(aItem.Key, TypeInfo(aItem.Key), fOwner.OwnsKeys and aFreeItem) then
  1148. Finalize(aItem.Key);
  1149. if not utlFinalizeObject(aItem.Value, TypeInfo(aItem.Value), fOwner.OwnsValues and aFreeItem) then
  1150. Finalize(aItem.Key);
  1151. inherited Release(aItem, aFreeItem);
  1152. end;
  1153. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1154. constructor TutlCustomMap.THashSet.Create(const aOwner: TutlCustomMap; aComparer: IComparer);
  1155. begin
  1156. inherited Create(aComparer, true);
  1157. fOwner := aOwner;
  1158. end;
  1159. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1160. //TutlCustomMap.TKeyValuePairComparer///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1161. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1162. function TutlCustomMap.TKeyValuePairComparer.EqualityCompare(constref i1, i2: TKeyValuePair): Boolean;
  1163. begin
  1164. result := fComparer.EqualityCompare(i1.Key, i2.Key);
  1165. end;
  1166. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1167. function TutlCustomMap.TKeyValuePairComparer.Compare(constref i1, i2: TKeyValuePair): Integer;
  1168. begin
  1169. result := fComparer.Compare(i1.Key, i2.Key);
  1170. end;
  1171. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1172. constructor TutlCustomMap.TKeyValuePairComparer.Create(aComparer: IComparer);
  1173. begin
  1174. if not Assigned(aComparer) then
  1175. raise EArgumentNilException.Create('aComparer');
  1176. inherited Create;
  1177. fComparer := aComparer;
  1178. end;
  1179. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1180. destructor TutlCustomMap.TKeyValuePairComparer.Destroy;
  1181. begin
  1182. fComparer := nil;
  1183. inherited Destroy;
  1184. end;
  1185. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1186. //TutlCustomMap.TKeyEnumerator//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1187. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1188. function TutlCustomMap.TKeyEnumerator.InternalMoveNext: Boolean;
  1189. begin
  1190. result := fEnumerator.MoveNext;
  1191. end;
  1192. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1193. procedure TutlCustomMap.TKeyEnumerator.InternalReset;
  1194. begin
  1195. fEnumerator.Reset;
  1196. end;
  1197. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1198. function TutlCustomMap.TKeyEnumerator.GetCurrent: TKey;
  1199. begin
  1200. result := fEnumerator.GetCurrent.Key;
  1201. end;
  1202. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1203. constructor TutlCustomMap.TKeyEnumerator.Create(aEnumerator: IutlKeyValuePairEnumerator);
  1204. begin
  1205. if not Assigned(aEnumerator) then
  1206. raise EArgumentNilException.Create('aEnumerator');
  1207. fEnumerator := aEnumerator;
  1208. inherited Create;
  1209. end;
  1210. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1211. //TutlCustomMap.TValueEnumerator////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1212. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1213. function TutlCustomMap.TValueEnumerator.InternalMoveNext: Boolean;
  1214. begin
  1215. result := fEnumerator.MoveNext;
  1216. end;
  1217. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1218. procedure TutlCustomMap.TValueEnumerator.InternalReset;
  1219. begin
  1220. fEnumerator.Reset;
  1221. end;
  1222. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1223. function TutlCustomMap.TValueEnumerator.GetCurrent: TValue;
  1224. begin
  1225. result := fEnumerator.GetCurrent.Value;
  1226. end;
  1227. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1228. constructor TutlCustomMap.TValueEnumerator.Create(aEnumerator: IutlKeyValuePairEnumerator);
  1229. begin
  1230. if not Assigned(aEnumerator) then
  1231. raise EArgumentNilException.Create('aEnumerator');
  1232. fEnumerator := aEnumerator;
  1233. inherited Create;
  1234. end;
  1235. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1236. //TutlCustomMap.TKeyCollection//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1237. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1238. function TutlCustomMap.TKeyCollection.GetEnumerator: IKeyEnumerator;
  1239. begin
  1240. result := TKeyEnumerator.Create(fHashSet.GetUtlEnumerator);
  1241. end;
  1242. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1243. function TutlCustomMap.TKeyCollection.GetUtlEnumerator: IutlKeyEnumerator;
  1244. begin
  1245. result := TKeyEnumerator.Create(fHashSet.GetUtlEnumerator);
  1246. end;
  1247. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1248. function TutlCustomMap.TKeyCollection.GetCount: Integer;
  1249. begin
  1250. result := fHashSet.Count;
  1251. end;
  1252. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1253. function TutlCustomMap.TKeyCollection.GetItem(const aIndex: Integer): TKey;
  1254. begin
  1255. result := fHashSet[aIndex].Key;
  1256. end;
  1257. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1258. constructor TutlCustomMap.TKeyCollection.Create(const aHashSet: THashSet);
  1259. begin
  1260. inherited Create;
  1261. fHashSet := aHashSet;
  1262. end;
  1263. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1264. //TutlCustomMap.TKeyValuePairCollection/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1265. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1266. function TutlCustomMap.TKeyValuePairCollection.GetEnumerator: IKeyValuePairEnumerator;
  1267. begin
  1268. result := fHashSet.GetEnumerator;
  1269. end;
  1270. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1271. function TutlCustomMap.TKeyValuePairCollection.GetUtlEnumerator: IutlKeyValuePairEnumerator;
  1272. begin
  1273. result := fHashSet.GetUtlEnumerator;
  1274. end;
  1275. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1276. function TutlCustomMap.TKeyValuePairCollection.GetCount: Integer;
  1277. begin
  1278. result := fHashSet.Count;
  1279. end;
  1280. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1281. function TutlCustomMap.TKeyValuePairCollection.GetItem(const aIndex: Integer): TKeyValuePair;
  1282. begin
  1283. result := fHashSet[aIndex];
  1284. end;
  1285. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1286. constructor TutlCustomMap.TKeyValuePairCollection.Create(const aHashSet: THashSet);
  1287. begin
  1288. inherited Create;
  1289. fHashSet := aHashSet;
  1290. end;
  1291. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1292. //TutlCustomMap/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1293. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1294. function TutlCustomMap.GetValue(aKey: TKey): TValue;
  1295. var
  1296. i: Integer;
  1297. kvp: TKeyValuePair;
  1298. begin
  1299. kvp.Key := aKey;
  1300. i := fHashSetRef.IndexOf(kvp);
  1301. if (i < 0)
  1302. then FillByte(result{%H-}, SizeOf(result), 0)
  1303. else result := fHashSetRef[i].Value;
  1304. end;
  1305. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1306. function TutlCustomMap.GetValueAt(const aIndex: Integer): TValue;
  1307. begin
  1308. result := fHashSetRef[aIndex].Value;
  1309. end;
  1310. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1311. function TutlCustomMap.GetCount: Integer;
  1312. begin
  1313. result := fHashSetRef.Count;
  1314. end;
  1315. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1316. function TutlCustomMap.GetIsEmpty: Boolean;
  1317. begin
  1318. result := fHashSetRef.IsEmpty;
  1319. end;
  1320. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1321. function TutlCustomMap.GetCapacity: Integer;
  1322. begin
  1323. result := fHashSetRef.Capacity;
  1324. end;
  1325. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1326. function TutlCustomMap.GetCanShrink: Boolean;
  1327. begin
  1328. result := fHashSetRef.CanShrink;
  1329. end;
  1330. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1331. function TutlCustomMap.GetCanExpand: Boolean;
  1332. begin
  1333. result := fHashSetRef.CanExpand;
  1334. end;
  1335. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1336. procedure TutlCustomMap.SetCapacity(const aValue: Integer);
  1337. begin
  1338. fHashSetRef.Capacity := aValue;
  1339. end;
  1340. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1341. procedure TutlCustomMap.SetCanShrink(const aValue: Boolean);
  1342. begin
  1343. fHashSetRef.CanShrink := aValue;
  1344. end;
  1345. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1346. procedure TutlCustomMap.SetCanExpand(const aValue: Boolean);
  1347. begin
  1348. fHashSetRef.CanExpand := aValue;
  1349. end;
  1350. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1351. procedure TutlCustomMap.SetValue(aKey: TKey; const aValue: TValue);
  1352. var
  1353. i: Integer;
  1354. kvp: TKeyValuePair;
  1355. begin
  1356. kvp.Key := aKey;
  1357. kvp.Value := aValue;
  1358. i := fHashSetRef.IndexOf(kvp);
  1359. if (i < 0) then begin
  1360. if not fAutoCreate then
  1361. raise EInvalidOperation.Create('key not found');
  1362. fHashSetRef.Add(kvp);
  1363. end else
  1364. fHashSetRef[i] := kvp;
  1365. end;
  1366. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1367. procedure TutlCustomMap.SetValueAt(const aIndex: Integer; const aValue: TValue);
  1368. var
  1369. kvp: TKeyValuePair;
  1370. begin
  1371. kvp := fHashSetRef[aIndex];
  1372. kvp.Value := aValue;
  1373. fHashSetRef[aIndex] := kvp;
  1374. end;
  1375. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1376. function TutlCustomMap.GetEnumerator: IValueEnumerator;
  1377. begin
  1378. result := TValueEnumerator.Create(fHashSetRef.GetUtlEnumerator);
  1379. end;
  1380. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1381. function TutlCustomMap.GetUtlEnumerator: IutlValueEnumerator;
  1382. begin
  1383. result := TValueEnumerator.Create(fHashSetRef.GetUtlEnumerator);
  1384. end;
  1385. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1386. procedure TutlCustomMap.Add(constref aKey: TKey; constref aValue: TValue);
  1387. begin
  1388. if not TryAdd(aKey, aValue) then
  1389. raise EInvalidOperation.Create('key already exists');
  1390. end;
  1391. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1392. function TutlCustomMap.TryAdd(constref aKey: TKey; constref aValue: TValue): Boolean;
  1393. var
  1394. kvp: TKeyValuePair;
  1395. begin
  1396. kvp.Key := aKey;
  1397. kvp.Value := aValue;
  1398. result := fHashSetRef.Add(kvp);
  1399. end;
  1400. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1401. function TutlCustomMap.TryGetValue(constref aKey: TKey; out aValue: TValue): Boolean;
  1402. var
  1403. i: Integer;
  1404. begin
  1405. i := IndexOf(aKey);
  1406. result := (i >= 0);
  1407. if result
  1408. then aValue := fHashSetRef[i].Value
  1409. else FillByte(result, SizeOf(result), 0);
  1410. end;
  1411. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1412. function TutlCustomMap.IndexOf(constref aKey: TKey): Integer;
  1413. var
  1414. kvp: TKeyValuePair;
  1415. begin
  1416. kvp.Key := aKey;
  1417. result := fHashSetRef.IndexOf(kvp);
  1418. end;
  1419. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1420. function TutlCustomMap.Contains(constref aKey: TKey): Boolean;
  1421. begin
  1422. result := (IndexOf(aKey) >= 0);
  1423. end;
  1424. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1425. function TutlCustomMap.Remove(constref aKey: TKey; const aFreeItem: Boolean): Boolean;
  1426. var
  1427. kvp: TKeyValuePair;
  1428. begin
  1429. kvp.Key := aKey;
  1430. result := fHashSetRef.Remove(kvp, aFreeItem);
  1431. end;
  1432. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1433. procedure TutlCustomMap.Delete(constref aKey: TKey);
  1434. begin
  1435. if not Remove(aKey) then
  1436. raise EInvalidOperation.Create('key not found');
  1437. end;
  1438. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1439. procedure TutlCustomMap.DeleteAt(const aIndex: Integer);
  1440. begin
  1441. fHashSetRef.Delete(aIndex);
  1442. end;
  1443. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1444. procedure TutlCustomMap.Clear;
  1445. begin
  1446. fHashSetRef.Clear;
  1447. end;
  1448. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1449. constructor TutlCustomMap.Create(
  1450. const aHashSet: THashSet;
  1451. const aOwnsKeys: Boolean;
  1452. const aOwnsValues: Boolean);
  1453. begin
  1454. if not Assigned(aHashSet) then
  1455. EArgumentNilException.Create('aHashSet');
  1456. inherited Create;
  1457. fAutoCreate := false;
  1458. fHashSetRef := aHashSet;
  1459. fOwnsKeys := aOwnsKeys;
  1460. fOwnsValues := aOwnsValues;
  1461. fKeyCollection := TKeyCollection.Create(fHashSetRef);
  1462. fKeyValuePairCollection := TKeyValuePairCollection.Create(fHashSetRef);
  1463. end;
  1464. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1465. destructor TutlCustomMap.Destroy;
  1466. begin
  1467. Clear;
  1468. FreeAndNil(fKeyValuePairCollection);
  1469. FreeAndNil(fKeyCollection);
  1470. fHashSetRef := nil;
  1471. inherited Destroy;
  1472. end;
  1473. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1474. //TutlMap///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1475. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1476. constructor TutlMap.Create(const aOwnsKeys: Boolean; const aOwnsValues: Boolean);
  1477. begin
  1478. fHashSetImpl := THashSet.Create(self, TKeyValuePairComparer.Create(TComparer.Create));
  1479. inherited Create(fHashSetImpl, aOwnsKeys, aOwnsValues);
  1480. end;
  1481. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1482. destructor TutlMap.Destroy;
  1483. begin
  1484. inherited Destroy;
  1485. FreeAndNil(fHashSetImpl);
  1486. end;
  1487. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1488. //TutlHandleManager.TPriorityItem////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1489. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1490. function TutlHandleManager.TPriorityItem.GetHandleEntry(const aIndex: TIndex): PHandleEntry;
  1491. begin
  1492. if (aIndex > HighIndex(Handles)) then
  1493. Grow;
  1494. result := @Handles[aIndex];
  1495. end;
  1496. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1497. procedure TutlHandleManager.TPriorityItem.Grow(const aSize: Integer);
  1498. var
  1499. oldIdx, newIdx, i: TIndex;
  1500. begin
  1501. oldIdx := Length(Handles);
  1502. if (aSize = 0) then
  1503. SetLength(Handles, Length(Handles) + GROW_SIZE)
  1504. else if (Length(Handles) >= aSize) then
  1505. exit
  1506. else
  1507. SetLength(Handles, aSize);
  1508. newIdx := High(Handles);
  1509. for i := oldIdx to newIdx do begin
  1510. FillByte(Handles[i].Data, SizeOf(T), 0);
  1511. Handles[i].Counter := 0;
  1512. Handles[i].Status := ENTRY_STATUS_UNKNOWN;
  1513. Handles[i].Next := High(TIndex);
  1514. Handles[i].Prev := High(TIndex);
  1515. PushBackFreeIndex(i);
  1516. end;
  1517. end;
  1518. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1519. procedure TutlHandleManager.TPriorityItem.PushFront(const aIndex: TIndex; var FirstIndex, LastIndex: TIndex;
  1520. const aStatus: TEntryStatus);
  1521. begin
  1522. Assert(aIndex <= HighIndex(Handles));
  1523. Assert(Handles[aIndex].Status = ENTRY_STATUS_UNKNOWN);
  1524. if (FirstIndex <> UNKNOWN_INDEX)
  1525. and (FirstIndex <= HighIndex(Handles))
  1526. and (Handles[FirstIndex].Status = aStatus)
  1527. then
  1528. Handles[FirstIndex].Prev := aIndex;
  1529. with Handles[aIndex] do begin
  1530. Prev := UNKNOWN_INDEX;
  1531. Next := FirstIndex;
  1532. Status := aStatus;
  1533. end;
  1534. FirstIndex := aIndex;
  1535. if (LastIndex = UNKNOWN_INDEX) then
  1536. LastIndex := aIndex;
  1537. end;
  1538. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1539. procedure TutlHandleManager.TPriorityItem.PushBack(const aIndex: TIndex; var FirstIndex, LastIndex: TIndex;
  1540. const aStatus: TEntryStatus);
  1541. begin
  1542. Assert(aIndex <= HighIndex(Handles));
  1543. Assert(Handles[aIndex].Status = ENTRY_STATUS_UNKNOWN);
  1544. if (LastIndex <> UNKNOWN_INDEX)
  1545. and (LastIndex <= HighIndex(Handles))
  1546. and (Handles[LastIndex].Status = aStatus)
  1547. then
  1548. Handles[LastIndex].Next := aIndex;
  1549. with Handles[aIndex] do begin
  1550. Prev := LastIndex;
  1551. Next := UNKNOWN_INDEX;
  1552. Status := aStatus;
  1553. end;
  1554. LastIndex := aIndex;
  1555. if (FirstIndex = UNKNOWN_INDEX) then
  1556. FirstIndex := aIndex;
  1557. end;
  1558. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1559. procedure TutlHandleManager.TPriorityItem.Remove(const aIndex: TIndex; var FirstIndex, LastIndex: TIndex; const aStatus: TEntryStatus);
  1560. begin
  1561. Assert(aIndex <> UNKNOWN_INDEX);
  1562. Assert(aIndex <= HighIndex(Handles));
  1563. Assert(Handles[aIndex].Status = aStatus);
  1564. with Handles[aIndex] do begin
  1565. if (Prev <> UNKNOWN_INDEX) then begin
  1566. Assert(Prev <= HighIndex(Handles));
  1567. Handles[Prev].Next := Next;
  1568. end;
  1569. if (Next <> UNKNOWN_INDEX) then begin
  1570. Assert(Next <= HighIndex(Handles));
  1571. Handles[Next].Prev := Prev;
  1572. end;
  1573. if (aIndex = FirstIndex) then
  1574. FirstIndex := Next;
  1575. if (aIndex = LastIndex) then
  1576. LastIndex := Prev;
  1577. Prev := UNKNOWN_INDEX;
  1578. Next := UNKNOWN_INDEX;
  1579. Status := ENTRY_STATUS_UNKNOWN;
  1580. end;
  1581. end;
  1582. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1583. function TutlHandleManager.TPriorityItem.PopFront(var FirstIndex, LastIndex: TIndex; const aStatus: TEntryStatus; const aCanGrow: Boolean): TIndex;
  1584. begin
  1585. if aCanGrow
  1586. and ( (FirstIndex = UNKNOWN_INDEX)
  1587. or (FirstIndex > HighIndex(Handles)))
  1588. then
  1589. Grow;
  1590. Assert(FirstIndex <> UNKNOWN_INDEX);
  1591. Assert(FirstIndex <= HighIndex(Handles));
  1592. Assert(Handles[FirstIndex].Status = aStatus);
  1593. result := FirstIndex;
  1594. with Handles[result] do begin
  1595. if (LastIndex = FirstIndex) then
  1596. LastIndex := Next;
  1597. FirstIndex := Next;
  1598. Prev := UNKNOWN_INDEX;
  1599. Next := UNKNOWN_INDEX;
  1600. Status := ENTRY_STATUS_UNKNOWN;
  1601. end;
  1602. if (FirstIndex <> UNKNOWN_INDEX)
  1603. and (FirstIndex <= HighIndex(Handles))
  1604. and (Handles[FirstIndex].Status = aStatus)
  1605. then
  1606. Handles[FirstIndex].Prev := UNKNOWN_INDEX;
  1607. end;
  1608. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1609. function TutlHandleManager.TPriorityItem.PopBack(var FirstIndex, LastIndex: TIndex; const aStatus: TEntryStatus; const aCanGrow: Boolean): TIndex;
  1610. begin
  1611. if aCanGrow
  1612. and ( (LastIndex <> UNKNOWN_INDEX)
  1613. or (LastIndex <= HighIndex(Handles)))
  1614. then
  1615. Grow;
  1616. Assert(LastIndex <> UNKNOWN_INDEX);
  1617. Assert(LastIndex <= HighIndex(Handles));
  1618. Assert(Handles[LastIndex].Status = aStatus);
  1619. result := LastIndex;
  1620. with Handles[result] do begin
  1621. if (FirstIndex = LastIndex) then
  1622. FirstIndex := Next;
  1623. LastIndex := Prev;
  1624. Prev := UNKNOWN_INDEX;
  1625. Next := UNKNOWN_INDEX;
  1626. Status := ENTRY_STATUS_UNKNOWN;
  1627. end;
  1628. if (LastIndex <> UNKNOWN_INDEX)
  1629. and (LastIndex <= HighIndex(Handles))
  1630. and (Handles[LastIndex].Status = aStatus)
  1631. then
  1632. Handles[LastIndex].Next := UNKNOWN_INDEX;
  1633. end;
  1634. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1635. procedure TutlHandleManager.TPriorityItem.PushFrontFreeIndex(const aIndex: TIndex);
  1636. begin
  1637. PushFront(aIndex, FirstFree, LastFree, ENTRY_STATUS_FREE);
  1638. end;
  1639. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1640. procedure TutlHandleManager.TPriorityItem.PushBackFreeIndex(const aIndex: TIndex);
  1641. begin
  1642. PushBack(aIndex, FirstFree, LastFree, ENTRY_STATUS_FREE);
  1643. end;
  1644. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1645. procedure TutlHandleManager.TPriorityItem.PushFrontUsedIndex(const aIndex: TIndex);
  1646. begin
  1647. PushFront(aIndex, FirstUsed, LastUsed, ENTRY_STATUS_USED);
  1648. end;
  1649. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1650. procedure TutlHandleManager.TPriorityItem.PushBackUsedIndex(const aIndex: TIndex);
  1651. begin
  1652. PushBack(aIndex, FirstUsed, LastUsed, ENTRY_STATUS_USED);
  1653. end;
  1654. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1655. procedure TutlHandleManager.TPriorityItem.RemoveFreeIndex(const aIndex: TIndex);
  1656. begin
  1657. Remove(aIndex, FirstFree, LastFree, ENTRY_STATUS_FREE);
  1658. end;
  1659. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1660. procedure TutlHandleManager.TPriorityItem.RemoveUsedIndex(const aIndex: TIndex);
  1661. begin
  1662. Remove(aIndex, FirstUsed, LastUsed, ENTRY_STATUS_USED);
  1663. end;
  1664. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1665. function TutlHandleManager.TPriorityItem.PopFrontFreeIndex: TIndex;
  1666. begin
  1667. result := PopFront(FirstFree, LastFree, ENTRY_STATUS_FREE, true);
  1668. end;
  1669. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1670. function TutlHandleManager.TPriorityItem.PopBackFreeIndex: TIndex;
  1671. begin
  1672. result := PopBack(FirstFree, LastFree, ENTRY_STATUS_FREE, false);
  1673. end;
  1674. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1675. function TutlHandleManager.TPriorityItem.PopFrontUsedIndex: TIndex;
  1676. begin
  1677. result := PopFront(FirstUsed, LastUsed, ENTRY_STATUS_USED, false);
  1678. end;
  1679. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1680. function TutlHandleManager.TPriorityItem.PopBackUsedIndex: TIndex;
  1681. begin
  1682. result := PopBack(FirstUsed, LastUsed, ENTRY_STATUS_USED, false);
  1683. end;
  1684. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1685. //TutlHandleManager.TEnumerator//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1686. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1687. function TutlHandleManager.TEnumerator.InternalMoveNext: Boolean;
  1688. var
  1689. p: PPriorityItem;
  1690. begin
  1691. repeat
  1692. if (fIndex = UNKNOWN_INDEX) then begin
  1693. inc(fPriority);
  1694. if (fPriority > High(fOwner.fItems)) then
  1695. break;
  1696. p := fOwner.GetPriorityItem(fPriority);
  1697. fIndex := p^.FirstUsed;
  1698. end else begin
  1699. p := fOwner.GetPriorityItem(fPriority);
  1700. fIndex := p^.Handles[fIndex].Next;
  1701. if (fIndex > HighIndex(p^.Handles)) then
  1702. fIndex := UNKNOWN_INDEX;
  1703. end;
  1704. until (fPriority > High(fOwner.fItems)) or (fIndex <> UNKNOWN_INDEX);
  1705. result := (fPriority <= High(fOwner.fItems));
  1706. if result then begin
  1707. p := fOwner.GetPriorityItem(fPriority);
  1708. fHandle := p^.Handles[fIndex];
  1709. end else
  1710. FillByte(fHandle, SizeOf(fHandle), 0);
  1711. end;
  1712. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1713. procedure TutlHandleManager.TEnumerator.InternalReset;
  1714. begin
  1715. fPriority := -1;
  1716. fIndex := UNKNOWN_INDEX;
  1717. end;
  1718. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1719. function TutlHandleManager.TEnumerator.GetCurrent: TutlHandle;
  1720. begin
  1721. if (fHandle.Status <> ENTRY_STATUS_USED) then
  1722. raise EInvalidOperation.Create('enumerator not initialized or collection changed');
  1723. with THandleData(result) do begin
  1724. Index := fIndex;
  1725. Counter := fHandle.Counter;
  1726. TypeID := fHandle.TypeID;
  1727. Priority := fPriority;
  1728. end;
  1729. end;
  1730. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1731. constructor TutlHandleManager.TEnumerator.Create(const aOwner: TutlHandleManager);
  1732. begin
  1733. if not Assigned(aOwner) then
  1734. raise EArgumentNilException.Create('aOwner');
  1735. inherited Create;
  1736. fOwner := aOwner;
  1737. FillByte(fHandle, SizeOf(fHandle), 0);
  1738. end;
  1739. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1740. //TutlHandleManager Class Methods////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1741. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1742. class function TutlHandleManager.HighIndex(constref aEntries: THandleEntries): TIndex;
  1743. begin
  1744. result := TIndex(High(aEntries));
  1745. end;
  1746. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1747. //TutlHandleManager//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1748. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1749. function TutlHandleManager.GetPriorityItem(const aPriority: Byte): PPriorityItem;
  1750. var
  1751. oldIdx, newIdx, i: Integer;
  1752. begin
  1753. if (aPriority > High(fItems)) then begin
  1754. oldIdx := Length(fItems);
  1755. SetLength(fItems, aPriority + 1);
  1756. newIdx := High(fItems);
  1757. for i := oldIdx to newIdx do with fItems[i] do begin
  1758. FirstFree := UNKNOWN_INDEX;
  1759. LastFree := UNKNOWN_INDEX;
  1760. FirstUsed := UNKNOWN_INDEX;
  1761. LastUsed := UNKNOWN_INDEX;
  1762. SetLength(Handles, 0);
  1763. end;
  1764. end;
  1765. result := @fItems[aPriority];
  1766. end;
  1767. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1768. function TutlHandleManager.GetValue(const aHandle: TutlHandle): T;
  1769. begin
  1770. if not TryGetValue(aHandle, result) then
  1771. raise EArgumentException.Create('unknown or invalid handle');
  1772. end;
  1773. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1774. function TutlHandleManager.TryGetValue(const aHandle: TutlHandle; out aData: T): Boolean;
  1775. begin
  1776. result := IsValid(aHandle);
  1777. with THandleData(aHandle) do begin
  1778. if result
  1779. then aData := fItems[Priority].Handles[Index].Data
  1780. else FillByte(aData, SizeOf(T), 0);
  1781. end;
  1782. end;
  1783. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1784. procedure TutlHandleManager.SetValue(const aHandle: TutlHandle; aData: T);
  1785. begin
  1786. if not TrySetValue(aHandle, aData) then
  1787. raise EArgumentException.Create('unknown or invalid handle');
  1788. end;
  1789. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1790. function TutlHandleManager.TrySetValue(const aHandle: TutlHandle; aData: T): Boolean;
  1791. var
  1792. p: PPriorityItem;
  1793. h: PHandleEntry;
  1794. begin
  1795. if not IsValid(aHandle) then with THandleData(aHandle) do begin
  1796. p := GetPriorityItem(Priority);
  1797. p^.Grow(Index + 1);
  1798. h := p^.GetHandleEntry(Index);
  1799. result := (h^.Status = ENTRY_STATUS_FREE);
  1800. if result then begin
  1801. p^.RemoveFreeIndex (Index);
  1802. p^.PushBackUsedIndex(Index);
  1803. h^.Counter := Counter;
  1804. h^.Data := aData;
  1805. h^.TypeID := TypeID;
  1806. end;
  1807. end else
  1808. Update(aHandle, aData);
  1809. end;
  1810. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1811. function TutlHandleManager.Add(const aTypeID: Byte; const aPriority: Byte; constref aData: T): TutlHandle;
  1812. var
  1813. p: PPriorityItem;
  1814. h: PHandleEntry;
  1815. i: Integer;
  1816. begin
  1817. p := GetPriorityItem(aPriority);
  1818. i := p^.PopFrontFreeIndex;
  1819. p^.PushBackUsedIndex(i);
  1820. h := p^.GetHandleEntry(i);
  1821. h^.TypeID := aTypeID;
  1822. h^.Counter := h^.Counter + 1;
  1823. if (h^.Counter = 0) then
  1824. h^.Counter := 1;
  1825. h^.Data := aData;
  1826. with THandleData(result) do begin
  1827. Index := i;
  1828. Counter := h^.Counter;
  1829. TypeID := aTypeID;
  1830. Priority := aPriority;
  1831. end;
  1832. inc(fCount);
  1833. end;
  1834. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1835. function TutlHandleManager.IsValid(const aHandle: TutlHandle): Boolean;
  1836. begin
  1837. with THandleData(aHandle) do begin
  1838. result := (Priority <= High(fItems))
  1839. and (Index <= HighIndex(fItems[Priority].Handles))
  1840. and (fItems[Priority].Handles[Index].Counter = Counter)
  1841. and (fItems[Priority].Handles[Index].Status = ENTRY_STATUS_USED);
  1842. end;
  1843. end;
  1844. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1845. procedure TutlHandleManager.Update(const aHandle: TutlHandle; aData: T);
  1846. begin
  1847. if not IsValid(aHandle) then
  1848. raise EArgumentException.Create('unknown or invalid handle');
  1849. with THandleData(aHandle) do begin
  1850. if not utlFinalizeObject(fItems[Priority].Handles[Index].Data, TypeInfo(T), fOwnsValues) then
  1851. Finalize(fItems[Priority].Handles[Index].Data);
  1852. fItems[Priority].Handles[Index].Data := aData;
  1853. end;
  1854. end;
  1855. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1856. function TutlHandleManager.Remove(const aHandle: TutlHandle): Boolean;
  1857. var
  1858. p: PPriorityItem;
  1859. begin
  1860. result := IsValid(aHandle);
  1861. if not result then
  1862. exit;
  1863. with THandleData(aHandle) do begin
  1864. p := GetPriorityItem(Priority);
  1865. p^.RemoveUsedIndex(Index);
  1866. p^.PushFrontFreeIndex(Index);
  1867. end;
  1868. dec(fCount);
  1869. end;
  1870. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1871. procedure TutlHandleManager.Delete(const aHandle: TutlHandle);
  1872. begin
  1873. if not Remove(aHandle) then
  1874. raise EArgumentException.Create('unknown or invalid handle');
  1875. end;
  1876. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1877. procedure TutlHandleManager.Clear;
  1878. var
  1879. i, j: Integer;
  1880. begin
  1881. for j := low(fItems) to high(fItems) do begin
  1882. for i := low(fItems[j].Handles) to high(fItems[j].Handles) do begin
  1883. if (fItems[j].Handles[i].Status = ENTRY_STATUS_USED) and not utlFinalizeObject(fItems[j].Handles[i].Data, TypeInfo(T), fOwnsValues) then
  1884. Finalize(fItems[j].Handles[i].Data);
  1885. FillByte(fItems[j].Handles[i].Data, SizeOf(T), 0);
  1886. end;
  1887. SetLength(fItems[j].Handles, 0);
  1888. end;
  1889. SetLength(fItems, 0);
  1890. end;
  1891. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1892. function TutlHandleManager.GetEnumerator: IEnumerator;
  1893. begin
  1894. result := TEnumerator.Create(self);
  1895. end;
  1896. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1897. function TutlHandleManager.GetUtlEnumerator: IutlEnumerator;
  1898. begin
  1899. result := TEnumerator.Create(self);
  1900. end;
  1901. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1902. constructor TutlHandleManager.Create(const aOwnsValues: Boolean);
  1903. begin
  1904. inherited Create;
  1905. fCount := 0;
  1906. fOwnsValues := aOwnsValues;
  1907. end;
  1908. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1909. destructor TutlHandleManager.Destroy;
  1910. begin
  1911. // Clear;
  1912. inherited Destroy;
  1913. end;
  1914. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1915. class function TutlHandleManager.GetTypeID(const aHandle: TutlHandle): Byte;
  1916. begin
  1917. result := THandleData(aHandle).TypeID;
  1918. end;
  1919. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1920. class function TutlHandleManager.GetPriority(const aHandle: TutlHandle): Byte;
  1921. begin
  1922. result := THandleData(aHandle).Priority;
  1923. end;
  1924. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1925. //EutlEnumConvert///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1926. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1927. constructor EEnumConvertException.Create(const aValue, aExpectedType: String);
  1928. begin
  1929. inherited Create(Format('%s is not a %s', [aValue, aExpectedType]));
  1930. end;
  1931. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1932. //TutlEnumHelperBase////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1933. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1934. class procedure TutlEnumHelperBase.RegisterType(const aValues: TIntArray; const aNames: TStringArray);
  1935. begin
  1936. fValuesMap.Add(ClassName, aValues);
  1937. fNamesMap.Add (ClassName, aNames);
  1938. end;
  1939. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1940. class procedure TutlEnumHelperBase.UnregisterType;
  1941. begin
  1942. fValuesMap.Remove(ClassName);
  1943. fNamesMap.Remove(ClassName);
  1944. end;
  1945. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1946. class function TutlEnumHelperBase.ToString(const aValue: Integer; const aAllowOrd: Boolean = false): String;
  1947. var
  1948. i: Integer;
  1949. iArr: TIntArray;
  1950. sArr: TStringArray;
  1951. begin
  1952. iArr := fValuesMap[ClassName];
  1953. sArr := fNamesMap[ClassName];
  1954. for i := low(iArr) to high(iArr) do begin
  1955. if (iArr[i] = aValue) then begin
  1956. result := sArr[i];
  1957. exit;
  1958. end;
  1959. end;
  1960. if aAllowOrd
  1961. then result := IntToStr(aValue)
  1962. else result := '';
  1963. end;
  1964. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1965. class function TutlEnumHelperBase.TryToEnum(const aStr: String; out aValue: Integer; const aAllowOrd: Boolean = false): Boolean;
  1966. var
  1967. i: Integer;
  1968. iArr: TIntArray;
  1969. sArr: TStringArray;
  1970. begin
  1971. iArr := fValuesMap[ClassName];
  1972. sArr := fNamesMap[ClassName];
  1973. for i := low(sArr) to high(sArr) do begin
  1974. if (sArr[i] = aStr) then begin
  1975. result := true;
  1976. aValue := iArr[i];
  1977. exit;
  1978. end;
  1979. end;
  1980. if aAllowOrd
  1981. then result := TryStrToInt(aStr, aValue)
  1982. else result := false;
  1983. end;
  1984. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1985. class function TutlEnumHelperBase.ToEnum(const aStr: String; const aAllowOrd: Boolean): Integer;
  1986. begin
  1987. if not TryToEnum(aStr, result, aAllowOrd) then
  1988. raise EConvertError.Create(aStr + ' is an unknown enum value');
  1989. end;
  1990. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1991. class function TutlEnumHelperBase.ToEnum(const aStr: String; const aDefault: Integer; const aAllowOrd: Boolean): Integer;
  1992. begin
  1993. if not TryToEnum(aStr, result, aAllowOrd) then
  1994. result := aDefault;
  1995. end;
  1996. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1997. class function TutlEnumHelperBase.IntValues: TIntArray;
  1998. begin
  1999. result := fValuesMap[ClassName];
  2000. end;
  2001. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2002. class function TutlEnumHelperBase.Names: TStringArray;
  2003. begin
  2004. result := fNamesMap[ClassName];
  2005. end;
  2006. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2007. class constructor TutlEnumHelperBase.Initialize;
  2008. begin
  2009. fNamesMap := TNamesMap.Create(true, true);
  2010. fValuesMap := TValuesMap.Create(true, true);
  2011. end;
  2012. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2013. class destructor TutlEnumHelperBase.Finalize;
  2014. begin
  2015. FreeAndNil(fNamesMap);
  2016. FreeAndNil(fValuesMap);
  2017. end;
  2018. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2019. //TutlEnumHelper////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2020. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2021. class function TutlEnumHelper.ToString(const aValue: T; const aAllowOrd: Boolean): String;
  2022. begin
  2023. {$Push}
  2024. {$IOChecks OFF}
  2025. WriteStr(Result, aValue);
  2026. if IOResult = 107 then
  2027. Result := '';
  2028. {$Pop}
  2029. end;
  2030. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2031. class function TutlEnumHelper.TryToEnum(const aStr: String; out aValue: T; const aAllowOrd: Boolean): Boolean;
  2032. var
  2033. a: T;
  2034. i: Integer;
  2035. begin
  2036. a := T(0);
  2037. Result := false;
  2038. if Length(aStr) = 0 then
  2039. exit;
  2040. {$Push}
  2041. {$IOChecks OFF}
  2042. ReadStr(aStr, a);
  2043. Result := IOResult <> 106;
  2044. {$Pop}
  2045. if Result then
  2046. aValue := a
  2047. else if aAllowOrd then begin
  2048. result := TryStrToInt(aStr, i);
  2049. if result then
  2050. aValue := T(i);
  2051. end;
  2052. end;
  2053. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2054. class function TutlEnumHelper.ToEnum(const aStr: String; const aAllowOrd: Boolean): T;
  2055. begin
  2056. if not TryToEnum(aStr, result, aAllowOrd) then
  2057. raise EEnumConvertException.Create(aStr, TypeInfo^.Name);
  2058. end;
  2059. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2060. class function TutlEnumHelper.ToEnum(const aStr: String; const aDefault: T; const aAllowOrd: Boolean): T;
  2061. begin
  2062. if not TryToEnum(aStr, result, aAllowOrd) then
  2063. result := aDefault;
  2064. end;
  2065. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2066. class function TutlEnumHelper.Values: TValueArray;
  2067. begin
  2068. result := fValues;
  2069. end;
  2070. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2071. class function TutlEnumHelper.IntValues: TIntArray;
  2072. begin
  2073. result := fIntValues;
  2074. end;
  2075. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2076. class function TutlEnumHelper.Names: TStringArray;
  2077. begin
  2078. result := fNames;
  2079. end;
  2080. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2081. class function TutlEnumHelper.TypeInfo: PTypeInfo;
  2082. begin
  2083. result := fTypeInfo;
  2084. end;
  2085. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2086. class constructor TutlEnumHelper.Initialize;
  2087. var
  2088. tiArray: PTypeInfo;
  2089. tdArray, tdEnum: PTypeData;
  2090. PName: PShortString;
  2091. i: integer;
  2092. en: T;
  2093. sl: TStringList;
  2094. begin
  2095. {
  2096. See FPC Bug http://bugs.freepascal.org/view.php?id=27622
  2097. For Sparse Enums, the compiler won't give us TypeInfo, because it contains some wrong data. This is
  2098. safe, but sadly we don't even get the *correct* fields (TypeName, NameList), even though they are
  2099. generated in any case.
  2100. Fortunately, arrays do know this type info segment as their Element Type (and we declared one anyway).
  2101. }
  2102. tiArray := System.TypeInfo(TValueArray);
  2103. tdArray := GetTypeData(tiArray);
  2104. fTypeInfo := tdArray^.elType2;
  2105. {
  2106. Now that we have the TypeInfo, fill our values from it. This is safe because while the *values* in
  2107. TypeData are wrong for Sparse Enums, the *PName* are always correct.
  2108. }
  2109. tdEnum := GetTypeData(FTypeInfo);
  2110. PName := @tdEnum^.NameList;
  2111. sl := TStringList.Create;
  2112. try
  2113. while Length(PName^) > 0 do begin
  2114. {
  2115. Memory layout for TTypeData has the declaring EnumUnitName after the last NameList entry.
  2116. This can normally not be the same as a valid enum value, because it is in the same identifier
  2117. namespace. However, with scoped enums we might have the same name for module and element, because
  2118. the full identifier for the element would be TypeName.ElementName.
  2119. In either case, the next PShortString will point to a zero-length string, and the loop is left
  2120. with the last element being invalid (either empty or whatever value the unit-named element has).
  2121. }
  2122. sl.Add(PName^);
  2123. if TryToEnum(PName^, en) then
  2124. sl.Objects[sl.Count-1] := TObject({%H-}Pointer(PtrUInt(en)));
  2125. inc(PByte(PName), Length(PName^) + 1);
  2126. end;
  2127. sl.Delete(sl.Count-1); // remove the EnumUnitName item
  2128. SetLength(fValues, sl.Count);
  2129. SetLength(fIntValues, sl.Count);
  2130. SetLength(fNames, sl.Count);
  2131. for i := 0 to sl.Count-1 do begin
  2132. fNames[i] := sl[i];
  2133. fValues[i] := T(PtrUInt(sl.Objects[i]));
  2134. fIntValues[i] := Integer(fValues[i]);
  2135. end;
  2136. finally
  2137. FreeAndNil(sl);
  2138. end;
  2139. RegisterType(fIntValues, fNames);
  2140. end;
  2141. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2142. class destructor TutlEnumHelper.Finalize;
  2143. begin
  2144. Finalize(fNames);
  2145. Finalize(fValues);
  2146. Finalize(fIntValues);
  2147. UnregisterType;
  2148. end;
  2149. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2150. //TutlSetHelperBase/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2151. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2152. class function TutlSetHelperBase.IsSet(const aSet; const aSize: Integer; const aValue: Integer): Boolean;
  2153. begin
  2154. if (aValue >= 8*aSize) then
  2155. raise EOutOfRangeException.Create(aValue, 0, 8*aSize-1);
  2156. result := ((PByte(@aSet)[aValue shr 3] and (1 shl (aValue and 7))) <> 0);
  2157. end;
  2158. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2159. class procedure TutlSetHelperBase.SetValue(var aSet; const aSize: Integer; const aValue: Integer);
  2160. begin
  2161. if (aValue >= 8*aSize) then
  2162. raise EOutOfRangeException.Create(aValue, 0, 8*aSize-1);
  2163. PByte(@aSet)[aValue shr 3] := PByte(@aSet)[aValue shr 3] or (1 shl (aValue and 7));
  2164. end;
  2165. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2166. class procedure TutlSetHelperBase.ClearValue(var aSet; const aSize: Integer; const aValue: Integer);
  2167. begin
  2168. if (aValue >= 8*aSize) then
  2169. raise EOutOfRangeException.Create(aValue, 0, 8*aSize-1);
  2170. PByte(@aSet)[aValue shr 3] := PByte(@aSet)[aValue shr 3] and not (1 shl (aValue and 7));
  2171. end;
  2172. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2173. class procedure TutlSetHelperBase.RegisterEnumHelper(const aHelper: TutlEnumHelperBaseClass);
  2174. begin
  2175. fEnumHelpers.Add(ClassName, aHelper);
  2176. end;
  2177. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2178. class procedure TutlSetHelperBase.UnregisterEnumHelper;
  2179. begin
  2180. fEnumHelpers.Remove(ClassName);
  2181. end;
  2182. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2183. class function TutlSetHelperBase.ToString(const aSet; const aSize: Integer; const aSeparator: String;
  2184. const aAllowOrd: Boolean): String;
  2185. var
  2186. i: Integer;
  2187. h: TutlEnumHelperBaseClass;
  2188. arr: TutlEnumHelperBase.TIntArray;
  2189. begin
  2190. h := EnumHelper;
  2191. if not Assigned(h) then
  2192. raise EInvalidOperation.Create('enum helper class is not set');
  2193. result := '';
  2194. arr := h.IntValues;
  2195. for i in arr do begin
  2196. if IsSet(aSet, aSize, i) then begin
  2197. if result > '' then
  2198. result := result + aSeparator;
  2199. result := result + h.ToString(i, aAllowOrd);
  2200. end;
  2201. end;
  2202. end;
  2203. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2204. class function TutlSetHelperBase.TryToSet(const aStr: String; out aSet; const aSize: Integer; const aAllowOrd: Boolean): Boolean;
  2205. begin
  2206. result := TryToSet(aStr, ',', aSet, aSize, aAllowOrd);
  2207. end;
  2208. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2209. class function TutlSetHelperBase.TryToSet(const aStr: String; const aSeparator: String; out aSet; const aSize: Integer; const aAllowOrd: Boolean): Boolean;
  2210. var
  2211. i, j, e: Integer;
  2212. s: String;
  2213. h: TutlEnumHelperBaseClass;
  2214. begin
  2215. if (aSeparator = '') then
  2216. raise EArgumentException.Create('''aSeparator'' can not be empty');
  2217. h := EnumHelper;
  2218. if not Assigned(h) then
  2219. raise EInvalidOperation.Create('enum helper class is not set');
  2220. result := true;
  2221. i := 1;
  2222. j := 1;
  2223. FillByte(aSet{%H-}, aSize, 0);
  2224. while (i <= Length(aStr)) do begin
  2225. if (Copy(aStr, i, Length(aSeparator)) = aSeparator) then begin
  2226. s := Trim(copy(aStr, j, i - j));
  2227. if (s <> '') then begin
  2228. result := result and h.TryToEnum(s, e);
  2229. if not result then
  2230. exit;
  2231. SetValue(aSet, aSize, e);
  2232. j := i + Length(aSeparator);
  2233. end;
  2234. end;
  2235. inc(i);
  2236. end;
  2237. s := Trim(copy(aStr, j, i - j));
  2238. if (s <> '') then begin
  2239. result := result and h.TryToEnum(s, e);
  2240. if not result then
  2241. exit;
  2242. SetValue(aSet, aSize, e);
  2243. end;
  2244. end;
  2245. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2246. class function TutlSetHelperBase.Compare(const aSet1; const aSet2; const aSize: Integer): Integer;
  2247. var
  2248. e: Integer;
  2249. h: TutlEnumHelperBaseClass;
  2250. begin
  2251. h := EnumHelper;
  2252. if not Assigned(h) then
  2253. raise EInvalidOperation.Create('enum helper class is not set');
  2254. result := 0;
  2255. for e in h.IntValues do begin
  2256. if IsSet(aSet1, aSize, e) and not IsSet(aSet2, aSize, e) then begin
  2257. result := 1;
  2258. break;
  2259. end else
  2260. if not IsSet(aSet1, aSize, e) and IsSet(aSet2, aSize, e) then begin
  2261. result := -1;
  2262. break;
  2263. end;
  2264. end;
  2265. end;
  2266. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2267. class function TutlSetHelperBase.EnumHelper: TutlEnumHelperBaseClass;
  2268. begin
  2269. result := fEnumHelpers[ClassName];
  2270. end;
  2271. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2272. class constructor TutlSetHelperBase.Initialize;
  2273. begin
  2274. fEnumHelpers := TEnumHelperMap.Create(true, true);
  2275. end;
  2276. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2277. class destructor TutlSetHelperBase.Finalize;
  2278. begin
  2279. FreeAndNil(fEnumHelpers);
  2280. end;
  2281. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2282. //TutlSetHelper/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2283. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2284. class function TutlSetHelper.ToString(const aValue: TSet; const aSeparator: String; const aAllowOrd: Boolean): String;
  2285. begin
  2286. result := ToString(aValue, SizeOf(aValue), aSeparator, aAllowOrd);
  2287. end;
  2288. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2289. class function TutlSetHelper.TryToSet(const aStr: String; out aValue: TSet; const aAllowOrd: Boolean): Boolean;
  2290. begin
  2291. result := TryToSet(aStr, ',', aValue, SizeOf(aValue), aAllowOrd);
  2292. end;
  2293. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2294. class function TutlSetHelper.TryToSet(const aStr: String; const aSeparator: String; out aValue: TSet; const aAllowOrd: Boolean): Boolean;
  2295. begin
  2296. result := TryToSet(aStr, aSeparator, aValue, SizeOf(aValue), aAllowOrd);
  2297. end;
  2298. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2299. class function TutlSetHelper.ToSet(const aStr: String; const aDefault: TSet; const aAllowOrd: Boolean): TSet;
  2300. begin
  2301. if not TryToSet(aStr, ',', result, SizeOf(result), aAllowOrd) then
  2302. result := aDefault;
  2303. end;
  2304. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2305. class function TutlSetHelper.ToSet(const aStr: String; const aAllowOrd: Boolean): TSet;
  2306. begin
  2307. if not TryToSet(aStr, ',', result, SizeOf(result), aAllowOrd) then
  2308. raise EEnumConvertException.CreateFmt('"%s" is an invalid value', [aStr]);
  2309. end;
  2310. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2311. class function TutlSetHelper.Compare(const aSet1, aSet2: TSet): Integer;
  2312. begin
  2313. result := Compare(aSet1, aSet2, SizeOf(aSet1));
  2314. end;
  2315. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2316. class constructor TutlSetHelper.Initialize;
  2317. begin
  2318. RegisterEnumHelper(TEnumHelper);
  2319. end;
  2320. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2321. class destructor TutlSetHelper.Finalize;
  2322. begin
  2323. UnregisterEnumHelper();
  2324. end;
  2325. end.