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.

1229 lines
51 KiB

  1. unit uengShaderFileGenerics;
  2. {$mode objfpc}{$H+}
  3. {$modeswitch nestedprocvars}
  4. interface
  5. uses
  6. Classes, SysUtils, typinfo;
  7. type
  8. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  9. generic IutlEqualityComparer<T> = interface
  10. function EqualityCompare(const i1, i2: T): Boolean;
  11. end;
  12. generic TutlEqualityComparer<T> = class(TInterfacedObject, specialize IutlEqualityComparer<T>)
  13. public
  14. function EqualityCompare(const i1, i2: T): Boolean;
  15. end;
  16. generic TutlEventEqualityComparer<T> = class(TInterfacedObject, specialize IutlEqualityComparer<T>)
  17. public type
  18. TEqualityEvent = function(const i1, i2: T): Boolean;
  19. TEqualityEventO = function(const i1, i2: T): Boolean of object;
  20. TEqualityEventN = function(const i1, i2: T): Boolean is nested;
  21. private type
  22. TEqualityEventType = (eetNormal, eetObject, eetNested);
  23. private
  24. fEvent: TEqualityEvent;
  25. fEventO: TEqualityEventO;
  26. fEventN: TEqualityEventN;
  27. fEventType: TEqualityEventType;
  28. public
  29. function EqualityCompare(const i1, i2: T): Boolean;
  30. constructor Create(const aEvent: TEqualityEvent); overload;
  31. constructor Create(const aEvent: TEqualityEventO); overload;
  32. constructor Create(const aEvent: TEqualityEventN); overload;
  33. { HINT: you need to activate "$modeswitch nestedprocvars" when you want to use nested callbacks }
  34. end;
  35. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  36. generic IutlComparer<T> = interface
  37. function Compare(const i1, i2: T): Integer;
  38. end;
  39. generic TutlComparer<T> = class(TInterfacedObject, specialize IutlComparer<T>)
  40. public
  41. function Compare(const i1, i2: T): Integer;
  42. end;
  43. generic TutlEventComparer<T> = class(TInterfacedObject, specialize IutlComparer<T>)
  44. public type
  45. TEvent = function(const i1, i2: T): Integer;
  46. TEventO = function(const i1, i2: T): Integer of object;
  47. TEventN = function(const i1, i2: T): Integer is nested;
  48. private type
  49. TEventType = (etNormal, etObject, etNested);
  50. private
  51. fEvent: TEvent;
  52. fEventO: TEventO;
  53. fEventN: TEventN;
  54. fEventType: TEventType;
  55. public
  56. function Compare(const i1, i2: T): Integer;
  57. constructor Create(const aEvent: TEvent); overload;
  58. constructor Create(const aEvent: TEventO); overload;
  59. constructor Create(const aEvent: TEventN); overload;
  60. { HINT: you need to activate "$modeswitch nestedprocvars" when you want to use nested callbacks }
  61. end;
  62. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  63. generic TutlListBase<T> = class(TObject)
  64. private type
  65. TListItem = packed record
  66. data: T;
  67. end;
  68. PListItem = ^TListItem;
  69. public type
  70. TEnumerator = class(TObject)
  71. private
  72. fReverse: Boolean;
  73. fList: TFPList;
  74. fPosition: Integer;
  75. function GetCurrent: T;
  76. public
  77. property Current: T read GetCurrent;
  78. function GetEnumerator: TEnumerator;
  79. function MoveNext: Boolean;
  80. constructor Create(const aList: TFPList; const aReverse: Boolean = false);
  81. end;
  82. private
  83. fList: TFPList;
  84. fOwnsObjects: Boolean;
  85. protected
  86. property List: TFPList read fList;
  87. function GetCount: Integer;
  88. function GetItem(const aIndex: Integer): T;
  89. procedure SetCount(const aValue: Integer);
  90. procedure SetItem(const aIndex: Integer; const aItem: T);
  91. function CreateItem: PListItem; virtual;
  92. procedure DestroyItem(const aItem: PListItem; const aFreeItem: Boolean = true); virtual;
  93. procedure InsertIntern(const aIndex: Integer; const aItem: T); virtual;
  94. procedure DeleteIntern(const aIndex: Integer; const aFreeItem: Boolean = true);
  95. public
  96. property OwnsObjects: Boolean read fOwnsObjects write fOwnsObjects;
  97. function GetEnumerator: TEnumerator;
  98. function GetReverseEnumerator: 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. EutlMapKeyNotFound = class(EutlMap)
  176. public
  177. constructor Create;
  178. end;
  179. EutlMapKeyAlreadyExists = class(EutlMap)
  180. public
  181. constructor Create;
  182. end;
  183. generic TutlCustomMap<TKey, TValue> = class(TObject)
  184. public type
  185. IComparer = specialize IutlComparer<TKey>;
  186. TKeyValuePair = packed record
  187. Key: TKey;
  188. Value: TValue;
  189. end;
  190. private type
  191. THashSetBase = specialize TutlCustomHashSet<TKeyValuePair>;
  192. THashSet = class(THashSetBase)
  193. protected
  194. procedure DestroyItem(const aItem: PListItem; const aFreeItem: Boolean = true); override;
  195. public
  196. property Items[const aIndex: Integer]: TKeyValuePair read GetItem write SetItem; default;
  197. end;
  198. TKVPComparer = class(TInterfacedObject, THashSet.IComparer)
  199. private
  200. fComparer: IComparer;
  201. public
  202. function Compare(const i1, i2: TKeyValuePair): Integer;
  203. constructor Create(aComparer: IComparer);
  204. destructor Destroy; override;
  205. end;
  206. TValueEnumerator = class(TObject)
  207. private
  208. fHashSet: THashSet;
  209. fPos: Integer;
  210. function GetCurrent: TValue;
  211. public
  212. property Current: TValue read GetCurrent;
  213. function MoveNext: Boolean;
  214. constructor Create(const aHashSet: THashSet);
  215. end;
  216. TKeyEnumerator = class(TObject)
  217. private
  218. fHashSet: THashSet;
  219. fPos: Integer;
  220. function GetCurrent: TKey;
  221. public
  222. property Current: TKey read GetCurrent;
  223. function MoveNext: Boolean;
  224. constructor Create(const aHashSet: THashSet);
  225. end;
  226. TKeyValuePairEnumerator = class(TObject)
  227. private
  228. fHashSet: THashSet;
  229. fPos: Integer;
  230. function GetCurrent: TKeyValuePair;
  231. public
  232. property Current: TKeyValuePair read GetCurrent;
  233. function MoveNext: Boolean;
  234. constructor Create(const aHashSet: THashSet);
  235. end;
  236. TKeyWrapper = class(TObject)
  237. private
  238. fHashSet: THashSet;
  239. function GetItem(const aIndex: Integer): TKey;
  240. function GetCount: Integer;
  241. public
  242. property Items[const aIndex: Integer]: TKey read GetItem; default;
  243. property Count: Integer read GetCount;
  244. function GetEnumerator: TKeyEnumerator;
  245. constructor Create(const aHashSet: THashSet);
  246. end;
  247. TKeyValuePairWrapper = class(TObject)
  248. private
  249. fHashSet: THashSet;
  250. function GetItem(const aIndex: Integer): TKeyValuePair;
  251. function GetCount: Integer;
  252. public
  253. property Items[const aIndex: Integer]: TKeyValuePair read GetItem; default;
  254. property Count: Integer read GetCount;
  255. function GetEnumerator: TKeyValuePairEnumerator;
  256. constructor Create(const aHashSet: THashSet);
  257. end;
  258. private
  259. fComparer: IComparer;
  260. fHashSet: THashSet;
  261. fKeyWrapper: TKeyWrapper;
  262. fKeyValuePairWrapper: TKeyValuePairWrapper;
  263. function GetValues(const aKey: TKey): TValue;
  264. function GetValueAt(const aIndex: Integer): TValue;
  265. function GetCount: Integer;
  266. procedure SetValueAt(const aIndex: Integer; aValue: TValue);
  267. procedure SetValues(const aKey: TKey; aValue: TValue);
  268. public
  269. property Values [const aKey: TKey]: TValue read GetValues write SetValues; default;
  270. property ValueAt[const aIndex: Integer]: TValue read GetValueAt write SetValueAt;
  271. property Keys: TKeyWrapper read fKeyWrapper;
  272. property KeyValuePairs: TKeyValuePairWrapper read fKeyValuePairWrapper;
  273. property Count: Integer read GetCount;
  274. procedure Add(const aKey: TKey; const aValue: TValue);
  275. function IndexOf(const aKey: TKey): Integer;
  276. function Contains(const aKey: TKey): Boolean;
  277. procedure Delete(const aKey: TKey);
  278. procedure DeleteAt(const aIndex: Integer);
  279. procedure Clear;
  280. function GetEnumerator: TValueEnumerator;
  281. constructor Create(aComparer: IComparer; const aOwnsObjects: Boolean = true);
  282. destructor Destroy; override;
  283. end;
  284. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  285. generic TutlMap<TKey, TValue> = class(specialize TutlCustomMap<TKey, TValue>)
  286. public type
  287. TComparer = specialize TutlComparer<TKey>;
  288. public
  289. constructor Create(const aOwnsObjects: Boolean = true);
  290. end;
  291. function utlFreeOrFinalize(var obj; const aTypeInfo: PTypeInfo; const aFreeObj: Boolean = true): Boolean;
  292. implementation
  293. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  294. //Helper////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  295. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  296. operator < (const i1, i2: TObject): Boolean; inline;
  297. begin
  298. result := PtrUInt(i1) < PtrUInt(i2);
  299. end;
  300. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  301. operator > (const i1, i2: TObject): Boolean; inline;
  302. begin
  303. result := PtrUInt(i1) > PtrUInt(i2);
  304. end;
  305. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  306. function utlFreeOrFinalize(var obj; const aTypeInfo: PTypeInfo; const aFreeObj: Boolean = true): Boolean;
  307. var
  308. o: TObject;
  309. begin
  310. result := true;
  311. case aTypeInfo^.Kind of
  312. tkClass: begin
  313. if (aFreeObj) then begin
  314. o := TObject(obj);
  315. Pointer(obj) := nil;
  316. o.Free;
  317. end;
  318. end;
  319. tkInterface: begin
  320. IUnknown(obj) := nil;
  321. end;
  322. tkAString: begin
  323. AnsiString(Obj) := '';
  324. end;
  325. tkUString: begin
  326. UnicodeString(Obj) := '';
  327. end;
  328. tkString: begin
  329. String(Obj) := '';
  330. end;
  331. else
  332. result := false;
  333. end;
  334. end;
  335. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  336. //EutlMapKeyNotFound////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  337. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  338. constructor EutlMapKeyNotFound.Create;
  339. begin
  340. inherited Create('key not found');
  341. end;
  342. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  343. //EutlMapKeyAlreadyExists///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  344. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  345. constructor EutlMapKeyAlreadyExists.Create;
  346. begin
  347. inherited Create('key already exists');
  348. end;
  349. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  350. //TutlEqualityComparer//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  351. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  352. function TutlEqualityComparer.EqualityCompare(const i1, i2: T): Boolean;
  353. begin
  354. result := (i1 = i2);
  355. end;
  356. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  357. function TutlEventEqualityComparer.EqualityCompare(const i1, i2: T): Boolean;
  358. begin
  359. case fEventType of
  360. eetNormal: result := fEvent(i1, i2);
  361. eetObject: result := fEventO(i1, i2);
  362. eetNested: result := fEventN(i1, i2);
  363. end;
  364. end;
  365. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  366. constructor TutlEventEqualityComparer.Create(const aEvent: TEqualityEvent);
  367. begin
  368. inherited Create;
  369. fEvent := aEvent;
  370. fEventType := eetNormal;
  371. end;
  372. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  373. constructor TutlEventEqualityComparer.Create(const aEvent: TEqualityEventO);
  374. begin
  375. inherited Create;
  376. fEventO := aEvent;
  377. fEventType := eetObject;
  378. end;
  379. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  380. constructor TutlEventEqualityComparer.Create(const aEvent: TEqualityEventN);
  381. begin
  382. inherited Create;
  383. fEventN := aEvent;
  384. fEventType := eetNested;
  385. end;
  386. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  387. //TutlComparer//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  388. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  389. function TutlComparer.Compare(const i1, i2: T): Integer;
  390. begin
  391. if (i1 < i2) then
  392. result := -1
  393. else if (i1 > i2) then
  394. result := 1
  395. else
  396. result := 0;
  397. end;
  398. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  399. function TutlEventComparer.Compare(const i1, i2: T): Integer;
  400. begin
  401. case fEventType of
  402. etNormal: result := fEvent(i1, i2);
  403. etObject: result := fEventO(i1, i2);
  404. etNested: result := fEventN(i1, i2);
  405. end;
  406. end;
  407. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  408. constructor TutlEventComparer.Create(const aEvent: TEvent);
  409. begin
  410. inherited Create;
  411. fEvent := aEvent;
  412. fEventType := etNormal;
  413. end;
  414. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  415. constructor TutlEventComparer.Create(const aEvent: TEventO);
  416. begin
  417. inherited Create;
  418. fEventO := aEvent;
  419. fEventType := etObject;
  420. end;
  421. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  422. constructor TutlEventComparer.Create(const aEvent: TEventN);
  423. begin
  424. inherited Create;
  425. fEventN := aEvent;
  426. fEventType := etNested;
  427. end;
  428. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  429. //TutlListBase//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  430. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  431. function TutlListBase.TEnumerator.GetCurrent: T;
  432. begin
  433. result := PListItem(fList[fPosition])^.data;
  434. end;
  435. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  436. function TutlListBase.TEnumerator.GetEnumerator: TEnumerator;
  437. begin
  438. result := self;
  439. end;
  440. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  441. function TutlListBase.TEnumerator.MoveNext: Boolean;
  442. begin
  443. if fReverse then begin
  444. dec(fPosition);
  445. result := (fPosition >= 0);
  446. end else begin
  447. inc(fPosition);
  448. result := (fPosition < fList.Count)
  449. end;
  450. end;
  451. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  452. constructor TutlListBase.TEnumerator.Create(const aList: TFPList; const aReverse: Boolean);
  453. begin
  454. inherited Create;
  455. fList := aList;
  456. fReverse := aReverse;
  457. if fReverse then
  458. fPosition := fList.Count
  459. else
  460. fPosition := -1;
  461. end;
  462. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  463. //TutlListBase//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  464. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  465. function TutlListBase.GetCount: Integer;
  466. begin
  467. result := fList.Count;
  468. end;
  469. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  470. function TutlListBase.GetItem(const aIndex: Integer): T;
  471. begin
  472. if (aIndex >= 0) and (aIndex < fList.Count) then
  473. result := PListItem(fList[aIndex])^.data
  474. else
  475. raise Exception.CreateFmt('index (%d) out of range [%d:%d]', [aIndex, 0, fList.Count-1]);
  476. end;
  477. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  478. procedure TutlListBase.SetCount(const aValue: Integer);
  479. var
  480. item: PListItem;
  481. begin
  482. if (aValue < 0) then
  483. raise Exception.Create('new value for count must be positiv');
  484. while (aValue > fList.Count) do begin
  485. item := CreateItem;
  486. FillByte(item^, SizeOf(item^), 0);
  487. fList.Add(item);
  488. end;
  489. while (aValue < fList.Count) do
  490. DeleteIntern(fList.Count-1);
  491. end;
  492. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  493. procedure TutlListBase.SetItem(const aIndex: Integer; const aItem: T);
  494. var
  495. item: PListItem;
  496. begin
  497. if (aIndex >= 0) and (aIndex < fList.Count) then begin
  498. item := PListItem(fList[aIndex]);
  499. utlFreeOrFinalize(item^, TypeInfo(item^), fOwnsObjects);
  500. item^.data := aItem;
  501. end else
  502. raise Exception.CreateFmt('index (%d) out of range [%d:%d]', [aIndex, 0, fList.Count-1]);
  503. end;
  504. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  505. function TutlListBase.CreateItem: PListItem;
  506. begin
  507. new(result);
  508. end;
  509. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  510. procedure TutlListBase.DestroyItem(const aItem: PListItem; const aFreeItem: Boolean);
  511. begin
  512. utlFreeOrFinalize(aItem^.data, TypeInfo(aItem^.data), fOwnsObjects and aFreeItem);
  513. Dispose(aItem);
  514. end;
  515. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  516. procedure TutlListBase.InsertIntern(const aIndex: Integer; const aItem: T);
  517. var
  518. item: PListItem;
  519. begin
  520. item := CreateItem;
  521. try
  522. item^.data := aItem;
  523. fList.Insert(aIndex, item);
  524. except
  525. DestroyItem(item, false);
  526. raise;
  527. end;
  528. end;
  529. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  530. procedure TutlListBase.DeleteIntern(const aIndex: Integer; const aFreeItem: Boolean);
  531. var
  532. item: PListItem;
  533. begin
  534. if (aIndex >= 0) and (aIndex < fList.Count) then begin
  535. item := PListItem(fList[aIndex]);
  536. fList.Delete(aIndex);
  537. DestroyItem(item, aFreeItem);
  538. end else
  539. raise Exception.CreateFmt('index (%d) out of range [%d:%d]', [aIndex, 0, fList.Count-1]);
  540. end;
  541. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  542. function TutlListBase.GetEnumerator: TEnumerator;
  543. begin
  544. result := TEnumerator.Create(fList, false);
  545. end;
  546. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  547. function TutlListBase.GetReverseEnumerator: TEnumerator;
  548. begin
  549. result := TEnumerator.Create(fList, true);
  550. end;
  551. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  552. procedure TutlListBase.Clear;
  553. begin
  554. while (fList.Count > 0) do
  555. DeleteIntern(fList.Count-1);
  556. end;
  557. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  558. constructor TutlListBase.Create(const aOwnsObjects: Boolean);
  559. begin
  560. inherited Create;
  561. fOwnsObjects := aOwnsObjects;
  562. fList := TFPList.Create;
  563. end;
  564. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  565. destructor TutlListBase.Destroy;
  566. begin
  567. Clear;
  568. FreeAndNil(fList);
  569. inherited Destroy;
  570. end;
  571. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  572. //TutlSimpleList////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  573. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  574. function TutlSimpleList.Split(aComparer: IComparer; const aDirection: TSortDirection; const aLeft, aRight: Integer): Integer;
  575. var
  576. i, j: Integer;
  577. pivot: T;
  578. begin
  579. i := aLeft;
  580. j := aRight - 1;
  581. pivot := GetItem(aRight);
  582. repeat
  583. while ((aDirection = sdAscending) and (aComparer.Compare(GetItem(i), pivot) <= 0) or
  584. (aDirection = sdDescending) and (aComparer.Compare(GetItem(i), pivot) >= 0)) and
  585. (i < aRight) do inc(i);
  586. while ((aDirection = sdAscending) and (aComparer.Compare(GetItem(j), pivot) >= 0) or
  587. (aDirection = sdDescending) and (aComparer.Compare(GetItem(j), pivot) <= 0)) and
  588. (j > aLeft) do dec(j);
  589. if (i < j) then
  590. Exchange(i, j);
  591. until (i >= j);
  592. if ((aDirection = sdAscending) and (aComparer.Compare(GetItem(i), pivot) > 0)) or
  593. ((aDirection = sdDescending) and (aComparer.Compare(GetItem(i), pivot) < 0)) then
  594. Exchange(i, aRight);
  595. result := i;
  596. end;
  597. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  598. procedure TutlSimpleList.QuickSort(aComparer: IComparer; const aDirection: TSortDirection; const aLeft, aRight: Integer);
  599. var
  600. s: Integer;
  601. begin
  602. if (aLeft < aRight) then begin
  603. s := Split(aComparer, aDirection, aLeft, aRight);
  604. QuickSort(aComparer, aDirection, aLeft, s - 1);
  605. QuickSort(aComparer, aDirection, s + 1, aRight);
  606. end;
  607. end;
  608. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  609. function TutlSimpleList.Add(const aItem: T): Integer;
  610. begin
  611. result := Count;
  612. InsertIntern(result, aItem);
  613. end;
  614. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  615. procedure TutlSimpleList.Insert(const aIndex: Integer; const aItem: T);
  616. begin
  617. InsertIntern(aIndex, aItem);
  618. end;
  619. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  620. procedure TutlSimpleList.Exchange(const aIndex1, aIndex2: Integer);
  621. begin
  622. if (aIndex1 < 0) or (aIndex1 >= Count) then
  623. raise Exception.CreateFmt('index (%d) out of range [%d:%d]', [aIndex1, 0, fList.Count-1]);
  624. if (aIndex2 < 0) or (aIndex2 >= Count) then
  625. raise Exception.CreateFmt('index (%d) out of range [%d:%d]', [aIndex2, 0, fList.Count-1]);
  626. fList.Exchange(aIndex1, aIndex2);
  627. end;
  628. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  629. procedure TutlSimpleList.Move(const aCurIndex, aNewIndex: Integer);
  630. begin
  631. if (aCurIndex < 0) or (aCurIndex >= Count) then
  632. raise Exception.CreateFmt('index (%d) out of range [%d:%d]', [aCurIndex, 0, fList.Count-1]);
  633. if (aNewIndex < 0) or (aNewIndex >= Count) then
  634. raise Exception.CreateFmt('index (%d) out of range [%d:%d]', [aNewIndex, 0, fList.Count-1]);
  635. fList.Move(aCurIndex, aNewIndex);
  636. end;
  637. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  638. procedure TutlSimpleList.Sort(aComparer: IComparer; const aDirection: TSortDirection);
  639. begin
  640. QuickSort(aComparer, aDirection, 0, fList.Count-1);
  641. end;
  642. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  643. procedure TutlSimpleList.Delete(const aIndex: Integer);
  644. begin
  645. DeleteIntern(aIndex);
  646. end;
  647. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  648. function TutlSimpleList.First: T;
  649. begin
  650. result := Items[0];
  651. end;
  652. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  653. procedure TutlSimpleList.PushFirst(const aItem: T);
  654. begin
  655. InsertIntern(0, aItem);
  656. end;
  657. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  658. function TutlSimpleList.PopFirst(const aFreeItem: Boolean): T;
  659. begin
  660. if aFreeItem then
  661. FillByte(result{%H-}, SizeOf(result), 0)
  662. else
  663. result := First;
  664. DeleteIntern(0, aFreeItem);
  665. end;
  666. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  667. function TutlSimpleList.Last: T;
  668. begin
  669. result := Items[Count-1];
  670. end;
  671. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  672. procedure TutlSimpleList.PushLast(const aItem: T);
  673. begin
  674. InsertIntern(Count, aItem);
  675. end;
  676. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  677. function TutlSimpleList.PopLast(const aFreeItem: Boolean): T;
  678. begin
  679. if aFreeItem then
  680. FillByte(result{%H-}, SizeOf(result), 0)
  681. else
  682. result := Last;
  683. DeleteIntern(Count-1, aFreeItem);
  684. end;
  685. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  686. //TutlCustomList////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  687. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  688. function TutlCustomList.IndexOf(const aItem: T): Integer;
  689. var
  690. c: Integer;
  691. begin
  692. c := List.Count;
  693. result := 0;
  694. while (result < c) and
  695. not fEqualityComparer.EqualityCompare(PListItem(List[result])^.data, aItem) do
  696. inc(result);
  697. if (result >= c) then
  698. result := -1;
  699. end;
  700. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  701. function TutlCustomList.Extract(const aItem: T; const aDefault: T): T;
  702. var
  703. i: Integer;
  704. begin
  705. i := IndexOf(aItem);
  706. if (i >= 0) then begin
  707. result := Items[i];
  708. DeleteIntern(i, false);
  709. end else
  710. result := aDefault;
  711. end;
  712. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  713. function TutlCustomList.Remove(const aItem: T): Integer;
  714. begin
  715. result := IndexOf(aItem);
  716. if (result >= 0) then
  717. DeleteIntern(result);
  718. end;
  719. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  720. constructor TutlCustomList.Create(aEqualityComparer: IEqualityComparer; const aOwnsObjects: Boolean);
  721. begin
  722. inherited Create(aOwnsObjects);
  723. fEqualityComparer := aEqualityComparer;
  724. end;
  725. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  726. destructor TutlCustomList.Destroy;
  727. begin
  728. fEqualityComparer := nil;
  729. inherited Destroy;
  730. end;
  731. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  732. //TutlList//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  733. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  734. constructor TutlList.Create(const aOwnsObjects: Boolean);
  735. begin
  736. inherited Create(TEqualityComparer.Create, aOwnsObjects);
  737. end;
  738. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  739. //TutlCustomHashSet/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  740. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  741. function TutlCustomHashSet.SearchItem(const aMin, aMax: Integer; const aItem: T; out aIndex: Integer): Integer;
  742. var
  743. i, cmp: Integer;
  744. begin
  745. if (aMin <= aMax) then begin
  746. i := aMin + Trunc((aMax - aMin) / 2);
  747. cmp := fComparer.Compare(aItem, GetItem(i));
  748. if (cmp = 0) then
  749. result := i
  750. else if (cmp < 0) then
  751. result := SearchItem(aMin, i-1, aItem, aIndex)
  752. else if (cmp > 0) then
  753. result := SearchItem(i+1, aMax, aItem, aIndex)
  754. else
  755. result := -1;
  756. end else begin
  757. result := -1;
  758. aIndex := aMin;
  759. end;
  760. end;
  761. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  762. function TutlCustomHashSet.Add(const aItem: T): Boolean;
  763. var
  764. i: Integer;
  765. begin
  766. result := (SearchItem(0, List.Count-1, aItem, i) < 0);
  767. if result then
  768. InsertIntern(i, aItem);
  769. end;
  770. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  771. function TutlCustomHashSet.Contains(const aItem: T): Boolean;
  772. var
  773. tmp: Integer;
  774. begin
  775. result := (SearchItem(0, List.Count-1, aItem, tmp) >= 0);
  776. end;
  777. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  778. function TutlCustomHashSet.IndexOf(const aItem: T): Integer;
  779. var
  780. tmp: Integer;
  781. begin
  782. result := SearchItem(0, List.Count-1, aItem, tmp);
  783. end;
  784. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  785. function TutlCustomHashSet.Remove(const aItem: T): Boolean;
  786. var
  787. i, tmp: Integer;
  788. begin
  789. i := SearchItem(0, List.Count-1, aItem, tmp);
  790. result := (i >= 0);
  791. if result then
  792. DeleteIntern(i);
  793. end;
  794. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  795. procedure TutlCustomHashSet.Delete(const aIndex: Integer);
  796. begin
  797. DeleteIntern(aIndex);
  798. end;
  799. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  800. constructor TutlCustomHashSet.Create(aComparer: IComparer; const aOwnsObjects: Boolean);
  801. begin
  802. inherited Create(aOwnsObjects);
  803. fComparer := aComparer;
  804. end;
  805. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  806. destructor TutlCustomHashSet.Destroy;
  807. begin
  808. fComparer := nil;
  809. inherited Destroy;
  810. end;
  811. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  812. //TutlHashSet///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  813. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  814. constructor TutlHashSet.Create(const aOwnsObjects: Boolean);
  815. begin
  816. inherited Create(TComparer.Create, aOwnsObjects);
  817. end;
  818. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  819. //TutlCustomMap.THashSet////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  820. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  821. procedure TutlCustomMap.THashSet.DestroyItem(const aItem: PListItem; const aFreeItem: Boolean);
  822. begin
  823. // never free objects used as keys, but do finalize strings, interfaces etc.
  824. utlFreeOrFinalize(aItem^.data.key, TypeInfo(aItem^.data.key), false);
  825. utlFreeOrFinalize(aItem^.data.value, TypeInfo(aItem^.data.value), aFreeItem and OwnsObjects);
  826. inherited DestroyItem(aItem, aFreeItem);
  827. end;
  828. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  829. //TutlCustomMap.TKVPComparer////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  830. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  831. function TutlCustomMap.TKVPComparer.Compare(const i1, i2: TKeyValuePair): Integer;
  832. begin
  833. result := fComparer.Compare(i1.Key, i2.Key);
  834. end;
  835. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  836. constructor TutlCustomMap.TKVPComparer.Create(aComparer: IComparer);
  837. begin
  838. inherited Create;
  839. fComparer := aComparer;
  840. end;
  841. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  842. destructor TutlCustomMap.TKVPComparer.Destroy;
  843. begin
  844. fComparer := nil;
  845. inherited Destroy;
  846. end;
  847. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  848. //TutlCustomMap.TValueEnumerator////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  849. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  850. function TutlCustomMap.TValueEnumerator.GetCurrent: TValue;
  851. begin
  852. result := fHashSet[fPos].Value;
  853. end;
  854. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  855. function TutlCustomMap.TValueEnumerator.MoveNext: Boolean;
  856. begin
  857. inc(fPos);
  858. result := (fPos < fHashSet.Count);
  859. end;
  860. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  861. constructor TutlCustomMap.TValueEnumerator.Create(const aHashSet: THashSet);
  862. begin
  863. inherited Create;
  864. fHashSet := aHashSet;
  865. fPos := -1;
  866. end;
  867. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  868. //TutlCustomMap.TKeyEnumerator//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  869. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  870. function TutlCustomMap.TKeyEnumerator.GetCurrent: TKey;
  871. begin
  872. result := fHashSet[fPos].Key;
  873. end;
  874. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  875. function TutlCustomMap.TKeyEnumerator.MoveNext: Boolean;
  876. begin
  877. inc(fPos);
  878. result := (fPos < fHashSet.Count);
  879. end;
  880. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  881. constructor TutlCustomMap.TKeyEnumerator.Create(const aHashSet: THashSet);
  882. begin
  883. inherited Create;
  884. fHashSet := aHashSet;
  885. fPos := -1;
  886. end;
  887. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  888. //TutlCustomMap.TKeyValuePairEnumerator/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  889. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  890. function TutlCustomMap.TKeyValuePairEnumerator.GetCurrent: TKeyValuePair;
  891. begin
  892. result := fHashSet[fPos];
  893. end;
  894. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  895. function TutlCustomMap.TKeyValuePairEnumerator.MoveNext: Boolean;
  896. begin
  897. inc(fPos);
  898. result := (fPos < fHashSet.Count);
  899. end;
  900. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  901. constructor TutlCustomMap.TKeyValuePairEnumerator.Create(const aHashSet: THashSet);
  902. begin
  903. inherited Create;
  904. fHashSet := aHashSet;
  905. fPos := -1;
  906. end;
  907. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  908. //TutlCustomMap.TKeyWrapper/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  909. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  910. function TutlCustomMap.TKeyWrapper.GetItem(const aIndex: Integer): TKey;
  911. begin
  912. result := fHashSet[aIndex].Key;
  913. end;
  914. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  915. function TutlCustomMap.TKeyWrapper.GetCount: Integer;
  916. begin
  917. result := fHashSet.Count;
  918. end;
  919. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  920. function TutlCustomMap.TKeyWrapper.GetEnumerator: TKeyEnumerator;
  921. begin
  922. result := TKeyEnumerator.Create(fHashSet);
  923. end;
  924. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  925. constructor TutlCustomMap.TKeyWrapper.Create(const aHashSet: THashSet);
  926. begin
  927. inherited Create;
  928. fHashSet := aHashSet;
  929. end;
  930. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  931. //TutlCustomMap.TKeyValuePairWrapper////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  932. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  933. function TutlCustomMap.TKeyValuePairWrapper.GetItem(const aIndex: Integer): TKeyValuePair;
  934. begin
  935. result := fHashSet[aIndex];
  936. end;
  937. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  938. function TutlCustomMap.TKeyValuePairWrapper.GetCount: Integer;
  939. begin
  940. result := fHashSet.Count;
  941. end;
  942. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  943. function TutlCustomMap.TKeyValuePairWrapper.GetEnumerator: TKeyValuePairEnumerator;
  944. begin
  945. result := TKeyValuePairEnumerator.Create(fHashSet);
  946. end;
  947. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  948. constructor TutlCustomMap.TKeyValuePairWrapper.Create(const aHashSet: THashSet);
  949. begin
  950. inherited Create;
  951. fHashSet := aHashSet;
  952. end;
  953. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  954. //TutlCustomMap/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  955. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  956. function TutlCustomMap.GetValues(const aKey: TKey): TValue;
  957. var
  958. i: Integer;
  959. kvp: TKeyValuePair;
  960. begin
  961. kvp.Key := aKey;
  962. i := fHashSet.IndexOf(kvp);
  963. if (i < 0) then
  964. FillByte(result{%H-}, SizeOf(result), 0)
  965. else
  966. result := fHashSet[i].Value;
  967. end;
  968. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  969. function TutlCustomMap.GetValueAt(const aIndex: Integer): TValue;
  970. begin
  971. result := fHashSet[aIndex].Value;
  972. end;
  973. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  974. function TutlCustomMap.GetCount: Integer;
  975. begin
  976. result := fHashSet.Count;
  977. end;
  978. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  979. procedure TutlCustomMap.SetValues(const aKey: TKey; aValue: TValue);
  980. var
  981. i: Integer;
  982. kvp: TKeyValuePair;
  983. begin
  984. kvp.Key := aKey;
  985. kvp.Value := aValue;
  986. i := fHashSet.IndexOf(kvp);
  987. if (i < 0) then
  988. raise EutlMap.Create('key not found');
  989. fHashSet[i] := kvp;
  990. end;
  991. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  992. procedure TutlCustomMap.SetValueAt(const aIndex: Integer; aValue: TValue);
  993. var
  994. kvp: TKeyValuePair;
  995. begin
  996. kvp := fHashSet[aIndex];
  997. kvp.Value := aValue;
  998. fHashSet[aIndex] := kvp;
  999. end;
  1000. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1001. procedure TutlCustomMap.Add(const aKey: TKey; const aValue: TValue);
  1002. var
  1003. kvp: TKeyValuePair;
  1004. begin
  1005. kvp.Key := aKey;
  1006. kvp.Value := aValue;
  1007. if not fHashSet.Add(kvp) then
  1008. raise EutlMapKeyAlreadyExists.Create();
  1009. end;
  1010. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1011. function TutlCustomMap.IndexOf(const aKey: TKey): Integer;
  1012. var
  1013. kvp: TKeyValuePair;
  1014. begin
  1015. kvp.Key := aKey;
  1016. result := fHashSet.IndexOf(kvp);
  1017. end;
  1018. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1019. function TutlCustomMap.Contains(const aKey: TKey): Boolean;
  1020. var
  1021. kvp: TKeyValuePair;
  1022. begin
  1023. kvp.Key := aKey;
  1024. result := (fHashSet.IndexOf(kvp) >= 0);
  1025. end;
  1026. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1027. procedure TutlCustomMap.Delete(const aKey: TKey);
  1028. var
  1029. kvp: TKeyValuePair;
  1030. begin
  1031. kvp.Key := aKey;
  1032. if not fHashSet.Remove(kvp) then
  1033. raise EutlMapKeyNotFound.Create;
  1034. end;
  1035. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1036. procedure TutlCustomMap.DeleteAt(const aIndex: Integer);
  1037. begin
  1038. fHashSet.Delete(aIndex);
  1039. end;
  1040. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1041. procedure TutlCustomMap.Clear;
  1042. begin
  1043. fHashSet.Clear;
  1044. end;
  1045. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1046. function TutlCustomMap.GetEnumerator: TValueEnumerator;
  1047. begin
  1048. result := TValueEnumerator.Create(fHashSet);
  1049. end;
  1050. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1051. constructor TutlCustomMap.Create(aComparer: IComparer; const aOwnsObjects: Boolean);
  1052. begin
  1053. inherited Create;
  1054. fComparer := aComparer;
  1055. fHashSet := THashSet.Create(TKVPComparer.Create(fComparer), aOwnsObjects);
  1056. fKeyWrapper := TKeyWrapper.Create(fHashSet);
  1057. fKeyValuePairWrapper := TKeyValuePairWrapper.Create(fHashSet);
  1058. end;
  1059. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1060. destructor TutlCustomMap.Destroy;
  1061. begin
  1062. FreeAndNil(fKeyValuePairWrapper);
  1063. FreeAndNil(fKeyWrapper);
  1064. FreeAndNil(fHashSet);
  1065. fComparer := nil;
  1066. inherited Destroy;
  1067. end;
  1068. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1069. //TutlMap///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1070. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1071. constructor TutlMap.Create(const aOwnsObjects: Boolean);
  1072. begin
  1073. inherited Create(TComparer.Create, aOwnsObjects);
  1074. end;
  1075. end.