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.
 
 

1414 lines
58 KiB

  1. unit uutlGenerics;
  2. { Package: Utils
  3. Prefix: utl - UTiLs
  4. Beschreibung: diese Unit implementiert allgemein nützliche ausschließlich-generische Klassen }
  5. {$mode objfpc}{$H+}
  6. {$modeswitch nestedprocvars}
  7. interface
  8. uses
  9. Classes, SysUtils, typinfo;
  10. type
  11. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  12. generic IutlEqualityComparer<T> = interface
  13. function EqualityCompare(const i1, i2: T): Boolean;
  14. end;
  15. generic TutlEqualityComparer<T> = class(TInterfacedObject, specialize IutlEqualityComparer<T>)
  16. public
  17. function EqualityCompare(const i1, i2: T): Boolean;
  18. end;
  19. generic TutlEventEqualityComparer<T> = class(TInterfacedObject, specialize IutlEqualityComparer<T>)
  20. public type
  21. TEqualityEvent = function(const i1, i2: T): Boolean;
  22. TEqualityEventO = function(const i1, i2: T): Boolean of object;
  23. TEqualityEventN = function(const i1, i2: T): Boolean is nested;
  24. private type
  25. TEqualityEventType = (eetNormal, eetObject, eetNested);
  26. private
  27. fEvent: TEqualityEvent;
  28. fEventO: TEqualityEventO;
  29. fEventN: TEqualityEventN;
  30. fEventType: TEqualityEventType;
  31. public
  32. function EqualityCompare(const i1, i2: T): Boolean;
  33. constructor Create(const aEvent: TEqualityEvent); overload;
  34. constructor Create(const aEvent: TEqualityEventO); overload;
  35. constructor Create(const aEvent: TEqualityEventN); overload;
  36. { HINT: you need to activate "$modeswitch nestedprocvars" when you want to use nested callbacks }
  37. end;
  38. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  39. generic IutlComparer<T> = interface
  40. function Compare(const i1, i2: T): Integer;
  41. end;
  42. generic TutlComparer<T> = class(TInterfacedObject, specialize IutlComparer<T>)
  43. public
  44. function Compare(const i1, i2: T): Integer;
  45. end;
  46. generic TutlEventComparer<T> = class(TInterfacedObject, specialize IutlComparer<T>)
  47. public type
  48. TEvent = function(const i1, i2: T): Integer;
  49. TEventO = function(const i1, i2: T): Integer of object;
  50. TEventN = function(const i1, i2: T): Integer is nested;
  51. private type
  52. TEventType = (etNormal, etObject, etNested);
  53. private
  54. fEvent: TEvent;
  55. fEventO: TEventO;
  56. fEventN: TEventN;
  57. fEventType: TEventType;
  58. public
  59. function Compare(const i1, i2: T): Integer;
  60. constructor Create(const aEvent: TEvent); overload;
  61. constructor Create(const aEvent: TEventO); overload;
  62. constructor Create(const aEvent: TEventN); overload;
  63. { HINT: you need to activate "$modeswitch nestedprocvars" when you want to use nested callbacks }
  64. end;
  65. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  66. generic TutlListBase<T> = class(TObject)
  67. private type
  68. TListItem = packed record
  69. data: T;
  70. end;
  71. PListItem = ^TListItem;
  72. public type
  73. TEnumerator = class(TObject)
  74. private
  75. fList: TFPList;
  76. fPosition: Integer;
  77. function GetCurrent: T;
  78. public
  79. property Current: T read GetCurrent;
  80. function MoveNext: Boolean;
  81. constructor Create(const aList: TFPList);
  82. end;
  83. private
  84. fList: TFPList;
  85. fOwnsObjects: Boolean;
  86. protected
  87. property List: TFPList read fList;
  88. function GetCount: Integer;
  89. function GetItem(const aIndex: Integer): T;
  90. procedure SetCount(const aValue: Integer);
  91. procedure SetItem(const aIndex: Integer; const aItem: T);
  92. function CreateItem: PListItem; virtual;
  93. procedure DestroyItem(const aItem: PListItem; const aFreeItem: Boolean = true); virtual;
  94. procedure InsertIntern(const aIndex: Integer; const aItem: T); virtual;
  95. procedure DeleteIntern(const aIndex: Integer; const aFreeItem: Boolean = true);
  96. public
  97. property OwnsObjects: Boolean read fOwnsObjects write fOwnsObjects;
  98. function GetEnumerator: TEnumerator;
  99. procedure Clear;
  100. constructor Create(const aOwnsObjects: Boolean = true);
  101. destructor Destroy; override;
  102. end;
  103. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  104. { a simple list without the ability to compare objects (e.g. for IndexOf, Remove, Extract) }
  105. generic TutlSimpleList<T> = class(specialize TutlListBase<T>)
  106. public type
  107. IComparer = specialize IutlComparer<T>;
  108. TSortDirection = (sdAscending, sdDescending);
  109. private
  110. function Split(aComparer: IComparer; const aDirection: TSortDirection; const aLeft, aRight: Integer): Integer;
  111. procedure QuickSort(aComparer: IComparer; const aDirection: TSortDirection; const aLeft, aRight: Integer);
  112. public
  113. property Items[const aIndex: Integer]: T read GetItem write SetItem; default;
  114. property Count: Integer read GetCount write SetCount;
  115. function Add(const aItem: T): Integer;
  116. procedure Insert(const aIndex: Integer; const aItem: T);
  117. procedure Exchange(const aIndex1, aIndex2: Integer);
  118. procedure Move(const aCurIndex, aNewIndex: Integer);
  119. procedure Sort(aComparer: IComparer; const aDirection: TSortDirection = sdAscending);
  120. procedure Delete(const aIndex: Integer);
  121. function First: T;
  122. procedure PushFirst(const aItem: T);
  123. function PopFirst(const aFreeItem: Boolean = false): T;
  124. function Last: T;
  125. procedure PushLast(const aItem: T);
  126. function PopLast(const aFreeItem: Boolean = false): T;
  127. end;
  128. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  129. generic TutlCustomList<T> = class(specialize TutlSimpleList<T>)
  130. public type
  131. IEqualityComparer = specialize IutlEqualityComparer<T>;
  132. private
  133. fEqualityComparer: IEqualityComparer;
  134. public
  135. function IndexOf(const aItem: T): Integer;
  136. function Extract(const aItem: T; const aDefault: T): T;
  137. function Remove(const aItem: T): Integer;
  138. constructor Create(aEqualityComparer: IEqualityComparer; const aOwnsObjects: Boolean = true);
  139. destructor Destroy; override;
  140. end;
  141. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  142. generic TutlList<T> = class(specialize TutlCustomList<T>)
  143. public type
  144. TEqualityComparer = specialize TutlEqualityComparer<T>;
  145. public
  146. constructor Create(const aOwnsObjects: Boolean = true);
  147. end;
  148. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  149. generic TutlCustomHashSet<T> = class(specialize TutlListBase<T>)
  150. public type
  151. IComparer = specialize IutlComparer<T>;
  152. private
  153. fComparer: IComparer;
  154. function SearchItem(const aMin, aMax: Integer; const aItem: T; out aIndex: Integer): Integer;
  155. public
  156. property Items[const aIndex: Integer]: T read GetItem; default;
  157. property Count: Integer read GetCount;
  158. function Add(const aItem: T): Boolean;
  159. function Contains(const aItem: T): Boolean;
  160. function IndexOf(const aItem: T): Integer;
  161. function Remove(const aItem: T): Boolean;
  162. procedure Delete(const aIndex: Integer);
  163. constructor Create(aComparer: IComparer; const aOwnsObjects: Boolean = true);
  164. destructor Destroy; override;
  165. end;
  166. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  167. generic TutlHashSet<T> = class(specialize TutlCustomHashSet<T>)
  168. public type
  169. TComparer = specialize TutlComparer<T>;
  170. public
  171. constructor Create(const aOwnsObjects: Boolean = true);
  172. end;
  173. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  174. EutlMap = class(Exception);
  175. generic TutlCustomMap<TKey, TValue> = class(TObject)
  176. public type
  177. IComparer = specialize IutlComparer<TKey>;
  178. TKeyValuePair = packed record
  179. Key: TKey;
  180. Value: TValue;
  181. end;
  182. private type
  183. THashSetBase = specialize TutlCustomHashSet<TKeyValuePair>;
  184. THashSet = class(THashSetBase)
  185. protected
  186. procedure DestroyItem(const aItem: PListItem; const aFreeItem: Boolean = true); override;
  187. public
  188. property Items[const aIndex: Integer]: TKeyValuePair read GetItem write SetItem; default;
  189. end;
  190. TKVPComparer = class(TInterfacedObject, THashSet.IComparer)
  191. private
  192. fComparer: IComparer;
  193. public
  194. function Compare(const i1, i2: TKeyValuePair): Integer;
  195. constructor Create(aComparer: IComparer);
  196. destructor Destroy; override;
  197. end;
  198. TValueEnumerator = class(TObject)
  199. private
  200. fHashSet: THashSet;
  201. fPos: Integer;
  202. function GetCurrent: TValue;
  203. public
  204. property Current: TValue read GetCurrent;
  205. function MoveNext: Boolean;
  206. constructor Create(const aHashSet: THashSet);
  207. end;
  208. TKeyEnumerator = class(TObject)
  209. private
  210. fHashSet: THashSet;
  211. fPos: Integer;
  212. function GetCurrent: TKey;
  213. public
  214. property Current: TKey read GetCurrent;
  215. function MoveNext: Boolean;
  216. constructor Create(const aHashSet: THashSet);
  217. end;
  218. TKeyValuePairEnumerator = class(TObject)
  219. private
  220. fHashSet: THashSet;
  221. fPos: Integer;
  222. function GetCurrent: TKeyValuePair;
  223. public
  224. property Current: TKeyValuePair read GetCurrent;
  225. function MoveNext: Boolean;
  226. constructor Create(const aHashSet: THashSet);
  227. end;
  228. TKeyWrapper = class(TObject)
  229. private
  230. fHashSet: THashSet;
  231. function GetItem(const aIndex: Integer): TKey;
  232. function GetCount: Integer;
  233. public
  234. property Items[const aIndex: Integer]: TKey read GetItem; default;
  235. property Count: Integer read GetCount;
  236. function GetEnumerator: TKeyEnumerator;
  237. constructor Create(const aHashSet: THashSet);
  238. end;
  239. TKeyValuePairWrapper = class(TObject)
  240. private
  241. fHashSet: THashSet;
  242. function GetItem(const aIndex: Integer): TKeyValuePair;
  243. function GetCount: Integer;
  244. public
  245. property Items[const aIndex: Integer]: TKeyValuePair read GetItem; default;
  246. property Count: Integer read GetCount;
  247. function GetEnumerator: TKeyValuePairEnumerator;
  248. constructor Create(const aHashSet: THashSet);
  249. end;
  250. private
  251. fComparer: IComparer;
  252. fHashSet: THashSet;
  253. fKeyWrapper: TKeyWrapper;
  254. fKeyValuePairWrapper: TKeyValuePairWrapper;
  255. function GetValues(const aKey: TKey): TValue;
  256. function GetValueAt(const aIndex: Integer): TValue;
  257. function GetCount: Integer;
  258. procedure SetValueAt(const aIndex: Integer; aValue: TValue);
  259. procedure SetValues(const aKey: TKey; aValue: TValue);
  260. public
  261. property Values [const aKey: TKey]: TValue read GetValues write SetValues; default;
  262. property ValueAt[const aIndex: Integer]: TValue read GetValueAt write SetValueAt;
  263. property Keys: TKeyWrapper read fKeyWrapper;
  264. property KeyValuePairs: TKeyValuePairWrapper read fKeyValuePairWrapper;
  265. property Count: Integer read GetCount;
  266. procedure Add(const aKey: TKey; const aValue: TValue);
  267. function IndexOf(const aKey: TKey): Integer;
  268. function Contains(const aKey: TKey): Boolean;
  269. procedure Delete(const aKey: TKey);
  270. procedure DeleteAt(const aIndex: Integer);
  271. procedure Clear;
  272. function GetEnumerator: TValueEnumerator;
  273. constructor Create(aComparer: IComparer; const aOwnsObjects: Boolean = true);
  274. destructor Destroy; override;
  275. end;
  276. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  277. generic TutlMap<TKey, TValue> = class(specialize TutlCustomMap<TKey, TValue>)
  278. public type
  279. TComparer = specialize TutlComparer<TKey>;
  280. public
  281. constructor Create(const aOwnsObjects: Boolean = true);
  282. end;
  283. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  284. generic TutlInterfaceList<T> = class(TInterfaceList)
  285. private type
  286. TInterfaceEnumerator = class(TObject)
  287. private
  288. fList: TInterfaceList;
  289. fPos: Integer;
  290. function GetCurrent: T;
  291. public
  292. property Current: T read GetCurrent;
  293. function MoveNext: Boolean;
  294. constructor Create(const aList: TInterfaceList);
  295. end;
  296. private
  297. function Get(i : Integer): T;
  298. procedure Put(i : Integer; aItem : T);
  299. public
  300. property Items[Index : Integer]: T read Get write Put; default;
  301. function First: T;
  302. function IndexOf(aItem : T): Integer;
  303. function Add(aItem : IUnknown): Integer;
  304. procedure Insert(i : Integer; aItem : T);
  305. function Last : T;
  306. function Remove(aItem : T): Integer;
  307. function GetEnumerator: TInterfaceEnumerator;
  308. end;
  309. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  310. generic TutlEnumHelper<T> = class(TObject)
  311. private type
  312. TValueArray = array of T;
  313. public
  314. class function ToString(aValue: T): String; reintroduce;
  315. class function TryToEnum(aStr: String; out aValue: T): Boolean;
  316. class function ToEnum(aStr: String): T; overload;
  317. class function ToEnum(aStr: String; const aDefault: T): T; overload;
  318. class function Values: TValueArray;
  319. end;
  320. function utlFreeOrFinalize(var obj; const aTypeInfo: PTypeInfo; const aFreeObj: Boolean = true): Boolean;
  321. implementation
  322. uses
  323. uutlExceptions;
  324. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  325. //Helper////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  326. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  327. operator < (const i1, i2: TObject): Boolean; inline;
  328. begin
  329. result := PtrUInt(i1) < PtrUInt(i2);
  330. end;
  331. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  332. operator > (const i1, i2: TObject): Boolean; inline;
  333. begin
  334. result := PtrUInt(i1) > PtrUInt(i2);
  335. end;
  336. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  337. function utlFreeOrFinalize(var obj; const aTypeInfo: PTypeInfo; const aFreeObj: Boolean = true): Boolean;
  338. var
  339. o: TObject;
  340. begin
  341. result := true;
  342. case aTypeInfo^.Kind of
  343. tkClass: begin
  344. if (aFreeObj) then begin
  345. o := TObject(obj);
  346. Pointer(obj) := nil;
  347. o.Free;
  348. end;
  349. end;
  350. tkInterface: begin
  351. IUnknown(obj) := nil;
  352. end;
  353. tkAString: begin
  354. AnsiString(Obj) := '';
  355. end;
  356. tkUString: begin
  357. UnicodeString(Obj) := '';
  358. end;
  359. tkString: begin
  360. String(Obj) := '';
  361. end;
  362. else
  363. result := false;
  364. end;
  365. end;
  366. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  367. //TutlEqualityComparer//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  368. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  369. function TutlEqualityComparer.EqualityCompare(const i1, i2: T): Boolean;
  370. begin
  371. result := (i1 = i2);
  372. end;
  373. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  374. function TutlEventEqualityComparer.EqualityCompare(const i1, i2: T): Boolean;
  375. begin
  376. case fEventType of
  377. eetNormal: result := fEvent(i1, i2);
  378. eetObject: result := fEventO(i1, i2);
  379. eetNested: result := fEventN(i1, i2);
  380. end;
  381. end;
  382. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  383. constructor TutlEventEqualityComparer.Create(const aEvent: TEqualityEvent);
  384. begin
  385. inherited Create;
  386. fEvent := aEvent;
  387. fEventType := eetNormal;
  388. end;
  389. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  390. constructor TutlEventEqualityComparer.Create(const aEvent: TEqualityEventO);
  391. begin
  392. inherited Create;
  393. fEventO := aEvent;
  394. fEventType := eetObject;
  395. end;
  396. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  397. constructor TutlEventEqualityComparer.Create(const aEvent: TEqualityEventN);
  398. begin
  399. inherited Create;
  400. fEventN := aEvent;
  401. fEventType := eetNested;
  402. end;
  403. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  404. //TutlComparer//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  405. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  406. function TutlComparer.Compare(const i1, i2: T): Integer;
  407. begin
  408. if (i1 < i2) then
  409. result := -1
  410. else if (i1 > i2) then
  411. result := 1
  412. else
  413. result := 0;
  414. end;
  415. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  416. function TutlEventComparer.Compare(const i1, i2: T): Integer;
  417. begin
  418. case fEventType of
  419. etNormal: result := fEvent(i1, i2);
  420. etObject: result := fEventO(i1, i2);
  421. etNested: result := fEventN(i1, i2);
  422. end;
  423. end;
  424. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  425. constructor TutlEventComparer.Create(const aEvent: TEvent);
  426. begin
  427. inherited Create;
  428. fEvent := aEvent;
  429. fEventType := etNormal;
  430. end;
  431. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  432. constructor TutlEventComparer.Create(const aEvent: TEventO);
  433. begin
  434. inherited Create;
  435. fEventO := aEvent;
  436. fEventType := etObject;
  437. end;
  438. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  439. constructor TutlEventComparer.Create(const aEvent: TEventN);
  440. begin
  441. inherited Create;
  442. fEventN := aEvent;
  443. fEventType := etNested;
  444. end;
  445. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  446. //TutlListBase//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  447. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  448. function TutlListBase.TEnumerator.GetCurrent: T;
  449. begin
  450. result := PListItem(fList[fPosition])^.data;
  451. end;
  452. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  453. function TutlListBase.TEnumerator.MoveNext: Boolean;
  454. begin
  455. inc(fPosition);
  456. result := (fPosition < fList.Count)
  457. end;
  458. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  459. constructor TutlListBase.TEnumerator.Create(const aList: TFPList);
  460. begin
  461. inherited Create;
  462. fList := aList;
  463. fPosition := -1;
  464. end;
  465. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  466. //TutlListBase//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  467. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  468. function TutlListBase.GetCount: Integer;
  469. begin
  470. result := fList.Count;
  471. end;
  472. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  473. function TutlListBase.GetItem(const aIndex: Integer): T;
  474. begin
  475. if (aIndex >= 0) and (aIndex < fList.Count) then
  476. result := PListItem(fList[aIndex])^.data
  477. else
  478. raise EOutOfRange.Create(aIndex, 0, fList.Count-1);
  479. end;
  480. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  481. procedure TutlListBase.SetCount(const aValue: Integer);
  482. var
  483. item: PListItem;
  484. begin
  485. if (aValue < 0) then
  486. raise EArgument.Create('new value for count must be positiv');
  487. while (aValue > fList.Count) do begin
  488. item := CreateItem;
  489. FillByte(item^, SizeOf(item^), 0);
  490. fList.Add(item);
  491. end;
  492. while (aValue < fList.Count) do
  493. DeleteIntern(fList.Count-1);
  494. end;
  495. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  496. procedure TutlListBase.SetItem(const aIndex: Integer; const aItem: T);
  497. var
  498. item: PListItem;
  499. begin
  500. if (aIndex >= 0) and (aIndex < fList.Count) then begin
  501. item := PListItem(fList[aIndex]);
  502. utlFreeOrFinalize(item^, TypeInfo(item^), fOwnsObjects);
  503. item^.data := aItem;
  504. end else
  505. raise EOutOfRange.Create(aIndex, 0, fList.Count-1);
  506. end;
  507. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  508. function TutlListBase.CreateItem: PListItem;
  509. begin
  510. new(result);
  511. end;
  512. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  513. procedure TutlListBase.DestroyItem(const aItem: PListItem; const aFreeItem: Boolean);
  514. begin
  515. utlFreeOrFinalize(aItem^.data, TypeInfo(aItem^.data), fOwnsObjects and aFreeItem);
  516. Dispose(aItem);
  517. end;
  518. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  519. procedure TutlListBase.InsertIntern(const aIndex: Integer; const aItem: T);
  520. var
  521. item: PListItem;
  522. begin
  523. item := CreateItem;
  524. try
  525. item^.data := aItem;
  526. fList.Insert(aIndex, item);
  527. except
  528. DestroyItem(item, false);
  529. raise;
  530. end;
  531. end;
  532. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  533. procedure TutlListBase.DeleteIntern(const aIndex: Integer; const aFreeItem: Boolean);
  534. var
  535. item: PListItem;
  536. begin
  537. if (aIndex >= 0) and (aIndex < fList.Count) then begin
  538. item := PListItem(fList[aIndex]);
  539. fList.Delete(aIndex);
  540. DestroyItem(item, aFreeItem);
  541. end else
  542. raise EOutOfRange.Create(aIndex, 0, fList.Count-1);
  543. end;
  544. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  545. function TutlListBase.GetEnumerator: TEnumerator;
  546. begin
  547. result := TEnumerator.Create(fList);
  548. end;
  549. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  550. procedure TutlListBase.Clear;
  551. begin
  552. while (fList.Count > 0) do
  553. DeleteIntern(fList.Count-1);
  554. end;
  555. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  556. constructor TutlListBase.Create(const aOwnsObjects: Boolean);
  557. begin
  558. inherited Create;
  559. fOwnsObjects := aOwnsObjects;
  560. fList := TFPList.Create;
  561. end;
  562. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  563. destructor TutlListBase.Destroy;
  564. begin
  565. Clear;
  566. FreeAndNil(fList);
  567. inherited Destroy;
  568. end;
  569. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  570. //TutlSimpleList////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  571. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  572. function TutlSimpleList.Split(aComparer: IComparer; const aDirection: TSortDirection; const aLeft, aRight: Integer): Integer;
  573. var
  574. i, j: Integer;
  575. pivot: T;
  576. begin
  577. i := aLeft;
  578. j := aRight - 1;
  579. pivot := GetItem(aRight);
  580. repeat
  581. while ((aDirection = sdAscending) and (aComparer.Compare(GetItem(i), pivot) <= 0) or
  582. (aDirection = sdDescending) and (aComparer.Compare(GetItem(i), pivot) >= 0)) and
  583. (i < aRight) do inc(i);
  584. while ((aDirection = sdAscending) and (aComparer.Compare(GetItem(j), pivot) >= 0) or
  585. (aDirection = sdDescending) and (aComparer.Compare(GetItem(j), pivot) <= 0)) and
  586. (j > aLeft) do dec(j);
  587. if (i < j) then
  588. Exchange(i, j);
  589. until (i >= j);
  590. if ((aDirection = sdAscending) and (aComparer.Compare(GetItem(i), pivot) > 0)) or
  591. ((aDirection = sdDescending) and (aComparer.Compare(GetItem(i), pivot) < 0)) then
  592. Exchange(i, aRight);
  593. result := i;
  594. end;
  595. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  596. procedure TutlSimpleList.QuickSort(aComparer: IComparer; const aDirection: TSortDirection; const aLeft, aRight: Integer);
  597. var
  598. s: Integer;
  599. begin
  600. if (aLeft < aRight) then begin
  601. s := Split(aComparer, aDirection, aLeft, aRight);
  602. QuickSort(aComparer, aDirection, aLeft, s - 1);
  603. QuickSort(aComparer, aDirection, s + 1, aRight);
  604. end;
  605. end;
  606. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  607. function TutlSimpleList.Add(const aItem: T): Integer;
  608. begin
  609. result := Count;
  610. InsertIntern(result, aItem);
  611. end;
  612. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  613. procedure TutlSimpleList.Insert(const aIndex: Integer; const aItem: T);
  614. begin
  615. InsertIntern(aIndex, aItem);
  616. end;
  617. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  618. procedure TutlSimpleList.Exchange(const aIndex1, aIndex2: Integer);
  619. begin
  620. if (aIndex1 < 0) or (aIndex1 >= Count) then
  621. raise EOutOfRange.Create(aIndex1, 0, Count-1);
  622. if (aIndex2 < 0) or (aIndex2 >= Count) then
  623. raise EOutOfRange.Create(aIndex2, 0, Count-1);
  624. fList.Exchange(aIndex1, aIndex2);
  625. end;
  626. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  627. procedure TutlSimpleList.Move(const aCurIndex, aNewIndex: Integer);
  628. begin
  629. if (aCurIndex < 0) or (aCurIndex >= Count) then
  630. raise EOutOfRange.Create(aCurIndex, 0, Count-1);
  631. if (aNewIndex < 0) or (aNewIndex >= Count) then
  632. raise EOutOfRange.Create(aNewIndex, 0, Count-1);
  633. fList.Move(aCurIndex, aNewIndex);
  634. end;
  635. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  636. procedure TutlSimpleList.Sort(aComparer: IComparer; const aDirection: TSortDirection);
  637. begin
  638. QuickSort(aComparer, aDirection, 0, fList.Count-1);
  639. end;
  640. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  641. procedure TutlSimpleList.Delete(const aIndex: Integer);
  642. begin
  643. DeleteIntern(aIndex);
  644. end;
  645. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  646. function TutlSimpleList.First: T;
  647. begin
  648. result := Items[0];
  649. end;
  650. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  651. procedure TutlSimpleList.PushFirst(const aItem: T);
  652. begin
  653. InsertIntern(0, aItem);
  654. end;
  655. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  656. function TutlSimpleList.PopFirst(const aFreeItem: Boolean): T;
  657. begin
  658. if aFreeItem then
  659. FillByte(result{%H-}, SizeOf(result), 0)
  660. else
  661. result := First;
  662. DeleteIntern(0, aFreeItem);
  663. end;
  664. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  665. function TutlSimpleList.Last: T;
  666. begin
  667. result := Items[Count-1];
  668. end;
  669. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  670. procedure TutlSimpleList.PushLast(const aItem: T);
  671. begin
  672. InsertIntern(Count, aItem);
  673. end;
  674. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  675. function TutlSimpleList.PopLast(const aFreeItem: Boolean): T;
  676. begin
  677. if aFreeItem then
  678. FillByte(result{%H-}, SizeOf(result), 0)
  679. else
  680. result := Last;
  681. DeleteIntern(Count-1, aFreeItem);
  682. end;
  683. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  684. //TutlCustomList////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  685. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  686. function TutlCustomList.IndexOf(const aItem: T): Integer;
  687. var
  688. c: Integer;
  689. begin
  690. c := List.Count;
  691. result := 0;
  692. while (result < c) and
  693. not fEqualityComparer.EqualityCompare(PListItem(List[result])^.data, aItem) do
  694. inc(result);
  695. if (result >= c) then
  696. result := -1;
  697. end;
  698. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  699. function TutlCustomList.Extract(const aItem: T; const aDefault: T): T;
  700. var
  701. i: Integer;
  702. begin
  703. i := IndexOf(aItem);
  704. if (i >= 0) then begin
  705. result := Items[i];
  706. DeleteIntern(i, false);
  707. end else
  708. result := aDefault;
  709. end;
  710. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  711. function TutlCustomList.Remove(const aItem: T): Integer;
  712. begin
  713. result := IndexOf(aItem);
  714. if (result >= 0) then
  715. DeleteIntern(result);
  716. end;
  717. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  718. constructor TutlCustomList.Create(aEqualityComparer: IEqualityComparer; const aOwnsObjects: Boolean);
  719. begin
  720. inherited Create(aOwnsObjects);
  721. fEqualityComparer := aEqualityComparer;
  722. end;
  723. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  724. destructor TutlCustomList.Destroy;
  725. begin
  726. fEqualityComparer := nil;
  727. inherited Destroy;
  728. end;
  729. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  730. //TutlList//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  731. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  732. constructor TutlList.Create(const aOwnsObjects: Boolean);
  733. begin
  734. inherited Create(TEqualityComparer.Create, aOwnsObjects);
  735. end;
  736. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  737. //TutlCustomHashSet/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  738. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  739. function TutlCustomHashSet.SearchItem(const aMin, aMax: Integer; const aItem: T; out aIndex: Integer): Integer;
  740. var
  741. i, cmp: Integer;
  742. begin
  743. if (aMin <= aMax) then begin
  744. i := aMin + Trunc((aMax - aMin) / 2);
  745. cmp := fComparer.Compare(aItem, GetItem(i));
  746. if (cmp = 0) then
  747. result := i
  748. else if (cmp < 0) then
  749. result := SearchItem(aMin, i-1, aItem, aIndex)
  750. else if (cmp > 0) then
  751. result := SearchItem(i+1, aMax, aItem, aIndex);
  752. end else begin
  753. result := -1;
  754. aIndex := aMin;
  755. end;
  756. end;
  757. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  758. function TutlCustomHashSet.Add(const aItem: T): Boolean;
  759. var
  760. i: Integer;
  761. begin
  762. result := (SearchItem(0, List.Count-1, aItem, i) < 0);
  763. if result then
  764. InsertIntern(i, aItem);
  765. end;
  766. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  767. function TutlCustomHashSet.Contains(const aItem: T): Boolean;
  768. var
  769. tmp: Integer;
  770. begin
  771. result := (SearchItem(0, List.Count-1, aItem, tmp) >= 0);
  772. end;
  773. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  774. function TutlCustomHashSet.IndexOf(const aItem: T): Integer;
  775. var
  776. tmp: Integer;
  777. begin
  778. result := SearchItem(0, List.Count-1, aItem, tmp);
  779. end;
  780. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  781. function TutlCustomHashSet.Remove(const aItem: T): Boolean;
  782. var
  783. i, tmp: Integer;
  784. begin
  785. i := SearchItem(0, List.Count-1, aItem, tmp);
  786. result := (i >= 0);
  787. if result then
  788. DeleteIntern(i);
  789. end;
  790. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  791. procedure TutlCustomHashSet.Delete(const aIndex: Integer);
  792. begin
  793. DeleteIntern(aIndex);
  794. end;
  795. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  796. constructor TutlCustomHashSet.Create(aComparer: IComparer; const aOwnsObjects: Boolean);
  797. begin
  798. inherited Create(aOwnsObjects);
  799. fComparer := aComparer;
  800. end;
  801. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  802. destructor TutlCustomHashSet.Destroy;
  803. begin
  804. fComparer := nil;
  805. inherited Destroy;
  806. end;
  807. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  808. //TutlHashSet///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  809. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  810. constructor TutlHashSet.Create(const aOwnsObjects: Boolean);
  811. begin
  812. inherited Create(TComparer.Create, aOwnsObjects);
  813. end;
  814. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  815. //TutlCustomMap.THashSet////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  816. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  817. procedure TutlCustomMap.THashSet.DestroyItem(const aItem: PListItem; const aFreeItem: Boolean);
  818. begin
  819. utlFreeOrFinalize(aItem^.data.key, TypeInfo(aItem^.data.key), aFreeItem and OwnsObjects);
  820. utlFreeOrFinalize(aItem^.data.value, TypeInfo(aItem^.data.value), aFreeItem and OwnsObjects);
  821. inherited DestroyItem(aItem, aFreeItem);
  822. end;
  823. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  824. //TutlCustomMap.TKVPComparer////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  825. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  826. function TutlCustomMap.TKVPComparer.Compare(const i1, i2: TKeyValuePair): Integer;
  827. begin
  828. result := fComparer.Compare(i1.Key, i2.Key);
  829. end;
  830. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  831. constructor TutlCustomMap.TKVPComparer.Create(aComparer: IComparer);
  832. begin
  833. inherited Create;
  834. fComparer := aComparer;
  835. end;
  836. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  837. destructor TutlCustomMap.TKVPComparer.Destroy;
  838. begin
  839. fComparer := nil;
  840. inherited Destroy;
  841. end;
  842. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  843. //TutlCustomMap.TValueEnumerator////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  844. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  845. function TutlCustomMap.TValueEnumerator.GetCurrent: TValue;
  846. begin
  847. result := fHashSet[fPos].Value;
  848. end;
  849. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  850. function TutlCustomMap.TValueEnumerator.MoveNext: Boolean;
  851. begin
  852. inc(fPos);
  853. result := (fPos < fHashSet.Count);
  854. end;
  855. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  856. constructor TutlCustomMap.TValueEnumerator.Create(const aHashSet: THashSet);
  857. begin
  858. inherited Create;
  859. fHashSet := aHashSet;
  860. fPos := -1;
  861. end;
  862. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  863. //TutlCustomMap.TKeyEnumerator//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  864. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  865. function TutlCustomMap.TKeyEnumerator.GetCurrent: TKey;
  866. begin
  867. result := fHashSet[fPos].Key;
  868. end;
  869. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  870. function TutlCustomMap.TKeyEnumerator.MoveNext: Boolean;
  871. begin
  872. inc(fPos);
  873. result := (fPos < fHashSet.Count);
  874. end;
  875. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  876. constructor TutlCustomMap.TKeyEnumerator.Create(const aHashSet: THashSet);
  877. begin
  878. inherited Create;
  879. fHashSet := aHashSet;
  880. fPos := -1;
  881. end;
  882. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  883. //TutlCustomMap.TKeyValuePairEnumerator/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  884. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  885. function TutlCustomMap.TKeyValuePairEnumerator.GetCurrent: TKeyValuePair;
  886. begin
  887. result := fHashSet[fPos];
  888. end;
  889. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  890. function TutlCustomMap.TKeyValuePairEnumerator.MoveNext: Boolean;
  891. begin
  892. inc(fPos);
  893. result := (fPos < fHashSet.Count);
  894. end;
  895. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  896. constructor TutlCustomMap.TKeyValuePairEnumerator.Create(const aHashSet: THashSet);
  897. begin
  898. inherited Create;
  899. fHashSet := aHashSet;
  900. fPos := -1;
  901. end;
  902. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  903. //TutlCustomMap.TKeyWrapper/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  904. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  905. function TutlCustomMap.TKeyWrapper.GetItem(const aIndex: Integer): TKey;
  906. begin
  907. result := fHashSet[aIndex].Key;
  908. end;
  909. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  910. function TutlCustomMap.TKeyWrapper.GetCount: Integer;
  911. begin
  912. result := fHashSet.Count;
  913. end;
  914. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  915. function TutlCustomMap.TKeyWrapper.GetEnumerator: TKeyEnumerator;
  916. begin
  917. result := TKeyEnumerator.Create(fHashSet);
  918. end;
  919. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  920. constructor TutlCustomMap.TKeyWrapper.Create(const aHashSet: THashSet);
  921. begin
  922. inherited Create;
  923. fHashSet := aHashSet;
  924. end;
  925. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  926. //TutlCustomMap.TKeyValuePairWrapper////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  927. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  928. function TutlCustomMap.TKeyValuePairWrapper.GetItem(const aIndex: Integer): TKeyValuePair;
  929. begin
  930. result := fHashSet[aIndex];
  931. end;
  932. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  933. function TutlCustomMap.TKeyValuePairWrapper.GetCount: Integer;
  934. begin
  935. result := fHashSet.Count;
  936. end;
  937. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  938. function TutlCustomMap.TKeyValuePairWrapper.GetEnumerator: TKeyValuePairEnumerator;
  939. begin
  940. result := TKeyValuePairEnumerator.Create(fHashSet);
  941. end;
  942. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  943. constructor TutlCustomMap.TKeyValuePairWrapper.Create(const aHashSet: THashSet);
  944. begin
  945. inherited Create;
  946. fHashSet := aHashSet;
  947. end;
  948. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  949. //TutlCustomMap/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  950. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  951. function TutlCustomMap.GetValues(const aKey: TKey): TValue;
  952. var
  953. i: Integer;
  954. kvp: TKeyValuePair;
  955. begin
  956. kvp.Key := aKey;
  957. i := fHashSet.IndexOf(kvp);
  958. if (i < 0) then
  959. FillByte(result{%H-}, SizeOf(result), 0)
  960. else
  961. result := fHashSet[i].Value;
  962. end;
  963. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  964. function TutlCustomMap.GetValueAt(const aIndex: Integer): TValue;
  965. begin
  966. result := fHashSet[aIndex].Value;
  967. end;
  968. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  969. function TutlCustomMap.GetCount: Integer;
  970. begin
  971. result := fHashSet.Count;
  972. end;
  973. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  974. procedure TutlCustomMap.SetValues(const aKey: TKey; aValue: TValue);
  975. var
  976. i: Integer;
  977. kvp: TKeyValuePair;
  978. begin
  979. kvp.Key := aKey;
  980. kvp.Value := aValue;
  981. i := fHashSet.IndexOf(kvp);
  982. if (i < 0) then
  983. raise EutlMap.Create('key not found');
  984. fHashSet[i] := kvp;
  985. end;
  986. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  987. procedure TutlCustomMap.SetValueAt(const aIndex: Integer; aValue: TValue);
  988. var
  989. kvp: TKeyValuePair;
  990. begin
  991. kvp := fHashSet[aIndex];
  992. kvp.Value := aValue;
  993. fHashSet[aIndex] := kvp;
  994. end;
  995. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  996. procedure TutlCustomMap.Add(const aKey: TKey; const aValue: TValue);
  997. var
  998. kvp: TKeyValuePair;
  999. begin
  1000. kvp.Key := aKey;
  1001. kvp.Value := aValue;
  1002. if not fHashSet.Add(kvp) then
  1003. raise EutlMap.Create('key is already in list');
  1004. end;
  1005. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1006. function TutlCustomMap.IndexOf(const aKey: TKey): Integer;
  1007. var
  1008. kvp: TKeyValuePair;
  1009. begin
  1010. kvp.Key := aKey;
  1011. result := fHashSet.IndexOf(kvp);
  1012. end;
  1013. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1014. function TutlCustomMap.Contains(const aKey: TKey): Boolean;
  1015. var
  1016. kvp: TKeyValuePair;
  1017. begin
  1018. kvp.Key := aKey;
  1019. result := (fHashSet.IndexOf(kvp) >= 0);
  1020. end;
  1021. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1022. procedure TutlCustomMap.Delete(const aKey: TKey);
  1023. var
  1024. kvp: TKeyValuePair;
  1025. begin
  1026. kvp.Key := aKey;
  1027. if not fHashSet.Remove(kvp) then
  1028. raise EutlMap.Create('key not found');
  1029. end;
  1030. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1031. procedure TutlCustomMap.DeleteAt(const aIndex: Integer);
  1032. begin
  1033. fHashSet.Delete(aIndex);
  1034. end;
  1035. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1036. procedure TutlCustomMap.Clear;
  1037. begin
  1038. fHashSet.Clear;
  1039. end;
  1040. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1041. function TutlCustomMap.GetEnumerator: TValueEnumerator;
  1042. begin
  1043. result := TValueEnumerator.Create(fHashSet);
  1044. end;
  1045. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1046. constructor TutlCustomMap.Create(aComparer: IComparer; const aOwnsObjects: Boolean);
  1047. begin
  1048. inherited Create;
  1049. fComparer := aComparer;
  1050. fHashSet := THashSet.Create(TKVPComparer.Create(fComparer), aOwnsObjects);
  1051. fKeyWrapper := TKeyWrapper.Create(fHashSet);
  1052. fKeyValuePairWrapper := TKeyValuePairWrapper.Create(fHashSet);
  1053. end;
  1054. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1055. destructor TutlCustomMap.Destroy;
  1056. begin
  1057. FreeAndNil(fKeyValuePairWrapper);
  1058. FreeAndNil(fKeyWrapper);
  1059. FreeAndNil(fHashSet);
  1060. fComparer := nil;
  1061. inherited Destroy;
  1062. end;
  1063. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1064. //TutlMap///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1065. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1066. constructor TutlMap.Create(const aOwnsObjects: Boolean);
  1067. begin
  1068. inherited Create(TComparer.Create, aOwnsObjects);
  1069. end;
  1070. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1071. //TutlInterfaceList.TInterfaceEnumerator////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1072. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1073. function TutlInterfaceList.TInterfaceEnumerator.GetCurrent: T;
  1074. begin
  1075. result := T(fList[fPos]);
  1076. end;
  1077. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1078. function TutlInterfaceList.TInterfaceEnumerator.MoveNext: Boolean;
  1079. begin
  1080. inc(fPos);
  1081. result := (fPos < fList.Count);
  1082. end;
  1083. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1084. constructor TutlInterfaceList.TInterfaceEnumerator.Create(const aList: TInterfaceList);
  1085. begin
  1086. inherited Create;
  1087. fPos := -1;
  1088. fList := aList;
  1089. end;
  1090. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1091. //TutlInterfaceList/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1092. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1093. function TutlInterfaceList.Get(i : Integer): T;
  1094. begin
  1095. result := T(inherited Get(i));
  1096. end;
  1097. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1098. procedure TutlInterfaceList.Put(i : Integer; aItem : T);
  1099. begin
  1100. inherited Put(i, aItem);
  1101. end;
  1102. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1103. function TutlInterfaceList.First: T;
  1104. begin
  1105. result := T(inherited First);
  1106. end;
  1107. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1108. function TutlInterfaceList.IndexOf(aItem : T): Integer;
  1109. begin
  1110. result := inherited IndexOf(aItem);
  1111. end;
  1112. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1113. function TutlInterfaceList.Add(aItem : IUnknown): Integer;
  1114. begin
  1115. result := inherited Add(aItem);
  1116. end;
  1117. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1118. procedure TutlInterfaceList.Insert(i : Integer; aItem : T);
  1119. begin
  1120. inherited Insert(i, aItem);
  1121. end;
  1122. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1123. function TutlInterfaceList.Last : T;
  1124. begin
  1125. result := T(inherited Last);
  1126. end;
  1127. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1128. function TutlInterfaceList.Remove(aItem : T): Integer;
  1129. begin
  1130. result := inherited Remove(aItem);
  1131. end;
  1132. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1133. function TutlInterfaceList.GetEnumerator: TInterfaceEnumerator;
  1134. begin
  1135. result := TInterfaceEnumerator.Create(self);
  1136. end;
  1137. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1138. //TutlEnumHelper////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1139. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1140. class function TutlEnumHelper.ToString(aValue: T): String;
  1141. Var
  1142. PS: PShortString;
  1143. TI: PTypeInfo;
  1144. PT: PTypeData;
  1145. num: Integer;
  1146. begin
  1147. TI := TypeInfo(T);
  1148. PT := GetTypeData(TI);
  1149. if TI^.Kind = tkBool then begin
  1150. case Integer(aValue) of
  1151. 0,1:
  1152. Result:=BooleanIdents[Boolean(aValue)];
  1153. else
  1154. Result:='';
  1155. end;
  1156. end else begin
  1157. num := Integer(aValue);
  1158. if (num >= PT^.MinValue) and (num <= PT^.MaxValue) then begin
  1159. PS := @PT^.NameList;
  1160. dec(num, PT^.MinValue);
  1161. while num > 0 do begin
  1162. PS := PShortString(pointer(PS) + PByte(PS)^ + 1);
  1163. Dec(Num);
  1164. end;
  1165. Result := PS^;
  1166. end else
  1167. Result := '';
  1168. end;
  1169. end;
  1170. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1171. class function TutlEnumHelper.TryToEnum(aStr: String; out aValue: T): Boolean;
  1172. Var
  1173. PS: PShortString;
  1174. PT: PTypeData;
  1175. Count: longint;
  1176. sName: shortstring;
  1177. TI: PTypeInfo;
  1178. begin
  1179. TI := TypeInfo(T);
  1180. PT := GetTypeData(TI);
  1181. Result := False;
  1182. if Length(aStr) = 0 then
  1183. exit;
  1184. sName := aStr;
  1185. if TI^.Kind = tkBool then begin
  1186. If CompareText(BooleanIdents[false], aStr) = 0 then
  1187. aValue := T(0)
  1188. else if CompareText(BooleanIdents[true], aStr) = 0 then
  1189. aValue := T(1);
  1190. Result := true;
  1191. end else begin
  1192. PS := @PT^.NameList;
  1193. Count := 0;
  1194. While (PByte(PS)^ <> 0) do begin
  1195. If ShortCompareText(PS^, sName) = 0 then begin
  1196. aValue := T(Count + PT^.MinValue);
  1197. exit(true);
  1198. end;
  1199. PS := PShortString(pointer(PS) + PByte(PS)^ + 1);
  1200. Inc(Count);
  1201. end;
  1202. end;
  1203. end;
  1204. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1205. class function TutlEnumHelper.ToEnum(aStr: String): T;
  1206. begin
  1207. if not TryToEnum(aStr, result) then
  1208. raise EConvertError.CreateFmt('"%s" is an invalid %s',[aStr, PTypeInfo(TypeInfo(T))^.Name]);
  1209. end;
  1210. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1211. class function TutlEnumHelper.ToEnum(aStr: String; const aDefault: T): T;
  1212. begin
  1213. if not TryToEnum(aStr, result) then
  1214. result := aDefault;
  1215. end;
  1216. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1217. class function TutlEnumHelper.Values: TValueArray;
  1218. Var
  1219. TI: PTypeInfo;
  1220. PT: PTypeData;
  1221. i,j: integer;
  1222. begin
  1223. TI := TypeInfo(T);
  1224. PT := GetTypeData(TI);
  1225. if TI^.Kind = tkBool then begin
  1226. SetLength(Result, 2);
  1227. Result[0]:= T(true);
  1228. Result[1]:= T(false);
  1229. end else begin
  1230. SetLength(Result, PT^.MaxValue - PT^.MinValue + 1);
  1231. j:= 0;
  1232. for i:= PT^.MinValue to PT^.MaxValue do begin
  1233. Result[j]:= T(i);
  1234. inc(j);
  1235. end;
  1236. end;
  1237. end;
  1238. end.