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.

1536 lines
62 KiB

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