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.

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