Nie możesz wybrać więcej, niż 25 tematów Tematy muszą się zaczynać od litery lub cyfry, mogą zawierać myślniki ('-') i mogą mieć do 35 znaków.

1227 wiersze
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. end else begin
  755. result := -1;
  756. aIndex := aMin;
  757. end;
  758. end;
  759. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  760. function TutlCustomHashSet.Add(const aItem: T): Boolean;
  761. var
  762. i: Integer;
  763. begin
  764. result := (SearchItem(0, List.Count-1, aItem, i) < 0);
  765. if result then
  766. InsertIntern(i, aItem);
  767. end;
  768. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  769. function TutlCustomHashSet.Contains(const aItem: T): Boolean;
  770. var
  771. tmp: Integer;
  772. begin
  773. result := (SearchItem(0, List.Count-1, aItem, tmp) >= 0);
  774. end;
  775. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  776. function TutlCustomHashSet.IndexOf(const aItem: T): Integer;
  777. var
  778. tmp: Integer;
  779. begin
  780. result := SearchItem(0, List.Count-1, aItem, tmp);
  781. end;
  782. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  783. function TutlCustomHashSet.Remove(const aItem: T): Boolean;
  784. var
  785. i, tmp: Integer;
  786. begin
  787. i := SearchItem(0, List.Count-1, aItem, tmp);
  788. result := (i >= 0);
  789. if result then
  790. DeleteIntern(i);
  791. end;
  792. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  793. procedure TutlCustomHashSet.Delete(const aIndex: Integer);
  794. begin
  795. DeleteIntern(aIndex);
  796. end;
  797. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  798. constructor TutlCustomHashSet.Create(aComparer: IComparer; const aOwnsObjects: Boolean);
  799. begin
  800. inherited Create(aOwnsObjects);
  801. fComparer := aComparer;
  802. end;
  803. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  804. destructor TutlCustomHashSet.Destroy;
  805. begin
  806. fComparer := nil;
  807. inherited Destroy;
  808. end;
  809. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  810. //TutlHashSet///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  811. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  812. constructor TutlHashSet.Create(const aOwnsObjects: Boolean);
  813. begin
  814. inherited Create(TComparer.Create, aOwnsObjects);
  815. end;
  816. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  817. //TutlCustomMap.THashSet////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  818. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  819. procedure TutlCustomMap.THashSet.DestroyItem(const aItem: PListItem; const aFreeItem: Boolean);
  820. begin
  821. // never free objects used as keys, but do finalize strings, interfaces etc.
  822. utlFreeOrFinalize(aItem^.data.key, TypeInfo(aItem^.data.key), false);
  823. utlFreeOrFinalize(aItem^.data.value, TypeInfo(aItem^.data.value), aFreeItem and OwnsObjects);
  824. inherited DestroyItem(aItem, aFreeItem);
  825. end;
  826. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  827. //TutlCustomMap.TKVPComparer////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  828. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  829. function TutlCustomMap.TKVPComparer.Compare(const i1, i2: TKeyValuePair): Integer;
  830. begin
  831. result := fComparer.Compare(i1.Key, i2.Key);
  832. end;
  833. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  834. constructor TutlCustomMap.TKVPComparer.Create(aComparer: IComparer);
  835. begin
  836. inherited Create;
  837. fComparer := aComparer;
  838. end;
  839. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  840. destructor TutlCustomMap.TKVPComparer.Destroy;
  841. begin
  842. fComparer := nil;
  843. inherited Destroy;
  844. end;
  845. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  846. //TutlCustomMap.TValueEnumerator////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  847. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  848. function TutlCustomMap.TValueEnumerator.GetCurrent: TValue;
  849. begin
  850. result := fHashSet[fPos].Value;
  851. end;
  852. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  853. function TutlCustomMap.TValueEnumerator.MoveNext: Boolean;
  854. begin
  855. inc(fPos);
  856. result := (fPos < fHashSet.Count);
  857. end;
  858. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  859. constructor TutlCustomMap.TValueEnumerator.Create(const aHashSet: THashSet);
  860. begin
  861. inherited Create;
  862. fHashSet := aHashSet;
  863. fPos := -1;
  864. end;
  865. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  866. //TutlCustomMap.TKeyEnumerator//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  867. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  868. function TutlCustomMap.TKeyEnumerator.GetCurrent: TKey;
  869. begin
  870. result := fHashSet[fPos].Key;
  871. end;
  872. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  873. function TutlCustomMap.TKeyEnumerator.MoveNext: Boolean;
  874. begin
  875. inc(fPos);
  876. result := (fPos < fHashSet.Count);
  877. end;
  878. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  879. constructor TutlCustomMap.TKeyEnumerator.Create(const aHashSet: THashSet);
  880. begin
  881. inherited Create;
  882. fHashSet := aHashSet;
  883. fPos := -1;
  884. end;
  885. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  886. //TutlCustomMap.TKeyValuePairEnumerator/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  887. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  888. function TutlCustomMap.TKeyValuePairEnumerator.GetCurrent: TKeyValuePair;
  889. begin
  890. result := fHashSet[fPos];
  891. end;
  892. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  893. function TutlCustomMap.TKeyValuePairEnumerator.MoveNext: Boolean;
  894. begin
  895. inc(fPos);
  896. result := (fPos < fHashSet.Count);
  897. end;
  898. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  899. constructor TutlCustomMap.TKeyValuePairEnumerator.Create(const aHashSet: THashSet);
  900. begin
  901. inherited Create;
  902. fHashSet := aHashSet;
  903. fPos := -1;
  904. end;
  905. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  906. //TutlCustomMap.TKeyWrapper/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  907. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  908. function TutlCustomMap.TKeyWrapper.GetItem(const aIndex: Integer): TKey;
  909. begin
  910. result := fHashSet[aIndex].Key;
  911. end;
  912. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  913. function TutlCustomMap.TKeyWrapper.GetCount: Integer;
  914. begin
  915. result := fHashSet.Count;
  916. end;
  917. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  918. function TutlCustomMap.TKeyWrapper.GetEnumerator: TKeyEnumerator;
  919. begin
  920. result := TKeyEnumerator.Create(fHashSet);
  921. end;
  922. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  923. constructor TutlCustomMap.TKeyWrapper.Create(const aHashSet: THashSet);
  924. begin
  925. inherited Create;
  926. fHashSet := aHashSet;
  927. end;
  928. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  929. //TutlCustomMap.TKeyValuePairWrapper////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  930. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  931. function TutlCustomMap.TKeyValuePairWrapper.GetItem(const aIndex: Integer): TKeyValuePair;
  932. begin
  933. result := fHashSet[aIndex];
  934. end;
  935. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  936. function TutlCustomMap.TKeyValuePairWrapper.GetCount: Integer;
  937. begin
  938. result := fHashSet.Count;
  939. end;
  940. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  941. function TutlCustomMap.TKeyValuePairWrapper.GetEnumerator: TKeyValuePairEnumerator;
  942. begin
  943. result := TKeyValuePairEnumerator.Create(fHashSet);
  944. end;
  945. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  946. constructor TutlCustomMap.TKeyValuePairWrapper.Create(const aHashSet: THashSet);
  947. begin
  948. inherited Create;
  949. fHashSet := aHashSet;
  950. end;
  951. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  952. //TutlCustomMap/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  953. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  954. function TutlCustomMap.GetValues(const aKey: TKey): TValue;
  955. var
  956. i: Integer;
  957. kvp: TKeyValuePair;
  958. begin
  959. kvp.Key := aKey;
  960. i := fHashSet.IndexOf(kvp);
  961. if (i < 0) then
  962. FillByte(result{%H-}, SizeOf(result), 0)
  963. else
  964. result := fHashSet[i].Value;
  965. end;
  966. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  967. function TutlCustomMap.GetValueAt(const aIndex: Integer): TValue;
  968. begin
  969. result := fHashSet[aIndex].Value;
  970. end;
  971. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  972. function TutlCustomMap.GetCount: Integer;
  973. begin
  974. result := fHashSet.Count;
  975. end;
  976. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  977. procedure TutlCustomMap.SetValues(const aKey: TKey; aValue: TValue);
  978. var
  979. i: Integer;
  980. kvp: TKeyValuePair;
  981. begin
  982. kvp.Key := aKey;
  983. kvp.Value := aValue;
  984. i := fHashSet.IndexOf(kvp);
  985. if (i < 0) then
  986. raise EutlMap.Create('key not found');
  987. fHashSet[i] := kvp;
  988. end;
  989. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  990. procedure TutlCustomMap.SetValueAt(const aIndex: Integer; aValue: TValue);
  991. var
  992. kvp: TKeyValuePair;
  993. begin
  994. kvp := fHashSet[aIndex];
  995. kvp.Value := aValue;
  996. fHashSet[aIndex] := kvp;
  997. end;
  998. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  999. procedure TutlCustomMap.Add(const aKey: TKey; const aValue: TValue);
  1000. var
  1001. kvp: TKeyValuePair;
  1002. begin
  1003. kvp.Key := aKey;
  1004. kvp.Value := aValue;
  1005. if not fHashSet.Add(kvp) then
  1006. raise EutlMapKeyAlreadyExists.Create();
  1007. end;
  1008. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1009. function TutlCustomMap.IndexOf(const aKey: TKey): Integer;
  1010. var
  1011. kvp: TKeyValuePair;
  1012. begin
  1013. kvp.Key := aKey;
  1014. result := fHashSet.IndexOf(kvp);
  1015. end;
  1016. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1017. function TutlCustomMap.Contains(const aKey: TKey): Boolean;
  1018. var
  1019. kvp: TKeyValuePair;
  1020. begin
  1021. kvp.Key := aKey;
  1022. result := (fHashSet.IndexOf(kvp) >= 0);
  1023. end;
  1024. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1025. procedure TutlCustomMap.Delete(const aKey: TKey);
  1026. var
  1027. kvp: TKeyValuePair;
  1028. begin
  1029. kvp.Key := aKey;
  1030. if not fHashSet.Remove(kvp) then
  1031. raise EutlMapKeyNotFound.Create;
  1032. end;
  1033. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1034. procedure TutlCustomMap.DeleteAt(const aIndex: Integer);
  1035. begin
  1036. fHashSet.Delete(aIndex);
  1037. end;
  1038. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1039. procedure TutlCustomMap.Clear;
  1040. begin
  1041. fHashSet.Clear;
  1042. end;
  1043. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1044. function TutlCustomMap.GetEnumerator: TValueEnumerator;
  1045. begin
  1046. result := TValueEnumerator.Create(fHashSet);
  1047. end;
  1048. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1049. constructor TutlCustomMap.Create(aComparer: IComparer; const aOwnsObjects: Boolean);
  1050. begin
  1051. inherited Create;
  1052. fComparer := aComparer;
  1053. fHashSet := THashSet.Create(TKVPComparer.Create(fComparer), aOwnsObjects);
  1054. fKeyWrapper := TKeyWrapper.Create(fHashSet);
  1055. fKeyValuePairWrapper := TKeyValuePairWrapper.Create(fHashSet);
  1056. end;
  1057. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1058. destructor TutlCustomMap.Destroy;
  1059. begin
  1060. FreeAndNil(fKeyValuePairWrapper);
  1061. FreeAndNil(fKeyWrapper);
  1062. FreeAndNil(fHashSet);
  1063. fComparer := nil;
  1064. inherited Destroy;
  1065. end;
  1066. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1067. //TutlMap///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1068. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1069. constructor TutlMap.Create(const aOwnsObjects: Boolean);
  1070. begin
  1071. inherited Create(TComparer.Create, aOwnsObjects);
  1072. end;
  1073. end.