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.

1372 lines
54 KiB

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