Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

1658 rader
66 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, syncobjs;
  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. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  349. generic TutlRingBuffer<T> = class
  350. private
  351. fAborted: boolean;
  352. fData: packed array of T;
  353. fDataLen: Integer;
  354. fDataSize: integer;
  355. fFillState: integer;
  356. fWritePtr, fReadPtr: integer;
  357. fWrittenEvent,
  358. fReadEvent: TEvent;
  359. public
  360. constructor Create(const Elements: Integer);
  361. destructor Destroy; override;
  362. function Read(Buf: Pointer; Items: integer; BlockUntilAvail: boolean): integer;
  363. function Write(Buf: Pointer; Items: integer; BlockUntilDone: boolean): integer;
  364. procedure BreakPipe;
  365. property FillState: Integer read fFillState;
  366. property Size: integer read fDataLen;
  367. end;
  368. function utlFreeOrFinalize(var obj; const aTypeInfo: PTypeInfo; const aFreeObj: Boolean = true): Boolean;
  369. implementation
  370. uses
  371. uutlExceptions, uutlThreads;
  372. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  373. //Helper////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  374. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  375. operator < (const i1, i2: TObject): Boolean; inline;
  376. begin
  377. result := PtrUInt(i1) < PtrUInt(i2);
  378. end;
  379. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  380. operator > (const i1, i2: TObject): Boolean; inline;
  381. begin
  382. result := PtrUInt(i1) > PtrUInt(i2);
  383. end;
  384. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  385. function utlFreeOrFinalize(var obj; const aTypeInfo: PTypeInfo; const aFreeObj: Boolean = true): Boolean;
  386. var
  387. o: TObject;
  388. begin
  389. result := true;
  390. case aTypeInfo^.Kind of
  391. tkClass: begin
  392. if (aFreeObj) then begin
  393. o := TObject(obj);
  394. Pointer(obj) := nil;
  395. o.Free;
  396. end;
  397. end;
  398. tkInterface: begin
  399. IUnknown(obj) := nil;
  400. end;
  401. tkAString: begin
  402. AnsiString(Obj) := '';
  403. end;
  404. tkUString: begin
  405. UnicodeString(Obj) := '';
  406. end;
  407. tkString: begin
  408. String(Obj) := '';
  409. end;
  410. else
  411. result := false;
  412. end;
  413. end;
  414. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  415. //TutlEqualityComparer//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  416. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  417. function TutlEqualityComparer.EqualityCompare(const i1, i2: T): Boolean;
  418. begin
  419. result := (i1 = i2);
  420. end;
  421. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  422. function TutlEventEqualityComparer.EqualityCompare(const i1, i2: T): Boolean;
  423. begin
  424. case fEventType of
  425. eetNormal: result := fEvent(i1, i2);
  426. eetObject: result := fEventO(i1, i2);
  427. eetNested: result := fEventN(i1, i2);
  428. end;
  429. end;
  430. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  431. constructor TutlEventEqualityComparer.Create(const aEvent: TEqualityEvent);
  432. begin
  433. inherited Create;
  434. fEvent := aEvent;
  435. fEventType := eetNormal;
  436. end;
  437. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  438. constructor TutlEventEqualityComparer.Create(const aEvent: TEqualityEventO);
  439. begin
  440. inherited Create;
  441. fEventO := aEvent;
  442. fEventType := eetObject;
  443. end;
  444. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  445. constructor TutlEventEqualityComparer.Create(const aEvent: TEqualityEventN);
  446. begin
  447. inherited Create;
  448. fEventN := aEvent;
  449. fEventType := eetNested;
  450. end;
  451. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  452. //TutlComparer//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  453. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  454. function TutlComparer.Compare(const i1, i2: T): Integer;
  455. begin
  456. if (i1 < i2) then
  457. result := -1
  458. else if (i1 > i2) then
  459. result := 1
  460. else
  461. result := 0;
  462. end;
  463. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  464. function TutlEventComparer.Compare(const i1, i2: T): Integer;
  465. begin
  466. case fEventType of
  467. etNormal: result := fEvent(i1, i2);
  468. etObject: result := fEventO(i1, i2);
  469. etNested: result := fEventN(i1, i2);
  470. end;
  471. end;
  472. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  473. constructor TutlEventComparer.Create(const aEvent: TEvent);
  474. begin
  475. inherited Create;
  476. fEvent := aEvent;
  477. fEventType := etNormal;
  478. end;
  479. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  480. constructor TutlEventComparer.Create(const aEvent: TEventO);
  481. begin
  482. inherited Create;
  483. fEventO := aEvent;
  484. fEventType := etObject;
  485. end;
  486. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  487. constructor TutlEventComparer.Create(const aEvent: TEventN);
  488. begin
  489. inherited Create;
  490. fEventN := aEvent;
  491. fEventType := etNested;
  492. end;
  493. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  494. //TutlListBase//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  495. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  496. function TutlListBase.TEnumerator.GetCurrent: T;
  497. begin
  498. result := PListItem(fList[fPosition])^.data;
  499. end;
  500. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  501. function TutlListBase.TEnumerator.MoveNext: Boolean;
  502. begin
  503. inc(fPosition);
  504. result := (fPosition < fList.Count)
  505. end;
  506. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  507. constructor TutlListBase.TEnumerator.Create(const aList: TFPList);
  508. begin
  509. inherited Create;
  510. fList := aList;
  511. fPosition := -1;
  512. end;
  513. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  514. //TutlListBase//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  515. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  516. function TutlListBase.GetCount: Integer;
  517. begin
  518. result := fList.Count;
  519. end;
  520. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  521. function TutlListBase.GetItem(const aIndex: Integer): T;
  522. begin
  523. if (aIndex >= 0) and (aIndex < fList.Count) then
  524. result := PListItem(fList[aIndex])^.data
  525. else
  526. raise EOutOfRange.Create(aIndex, 0, fList.Count-1);
  527. end;
  528. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  529. procedure TutlListBase.SetCount(const aValue: Integer);
  530. var
  531. item: PListItem;
  532. begin
  533. if (aValue < 0) then
  534. raise EArgument.Create('new value for count must be positiv');
  535. while (aValue > fList.Count) do begin
  536. item := CreateItem;
  537. FillByte(item^, SizeOf(item^), 0);
  538. fList.Add(item);
  539. end;
  540. while (aValue < fList.Count) do
  541. DeleteIntern(fList.Count-1);
  542. end;
  543. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  544. procedure TutlListBase.SetItem(const aIndex: Integer; const aItem: T);
  545. var
  546. item: PListItem;
  547. begin
  548. if (aIndex >= 0) and (aIndex < fList.Count) then begin
  549. item := PListItem(fList[aIndex]);
  550. utlFreeOrFinalize(item^, TypeInfo(item^), fOwnsObjects);
  551. item^.data := aItem;
  552. end else
  553. raise EOutOfRange.Create(aIndex, 0, fList.Count-1);
  554. end;
  555. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  556. function TutlListBase.CreateItem: PListItem;
  557. begin
  558. new(result);
  559. end;
  560. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  561. procedure TutlListBase.DestroyItem(const aItem: PListItem; const aFreeItem: Boolean);
  562. begin
  563. utlFreeOrFinalize(aItem^.data, TypeInfo(aItem^.data), fOwnsObjects and aFreeItem);
  564. Dispose(aItem);
  565. end;
  566. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  567. procedure TutlListBase.InsertIntern(const aIndex: Integer; const aItem: T);
  568. var
  569. item: PListItem;
  570. begin
  571. item := CreateItem;
  572. try
  573. item^.data := aItem;
  574. fList.Insert(aIndex, item);
  575. except
  576. DestroyItem(item, false);
  577. raise;
  578. end;
  579. end;
  580. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  581. procedure TutlListBase.DeleteIntern(const aIndex: Integer; const aFreeItem: Boolean);
  582. var
  583. item: PListItem;
  584. begin
  585. if (aIndex >= 0) and (aIndex < fList.Count) then begin
  586. item := PListItem(fList[aIndex]);
  587. fList.Delete(aIndex);
  588. DestroyItem(item, aFreeItem);
  589. end else
  590. raise EOutOfRange.Create(aIndex, 0, fList.Count-1);
  591. end;
  592. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  593. function TutlListBase.GetEnumerator: TEnumerator;
  594. begin
  595. result := TEnumerator.Create(fList);
  596. end;
  597. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  598. procedure TutlListBase.Clear;
  599. begin
  600. while (fList.Count > 0) do
  601. DeleteIntern(fList.Count-1);
  602. end;
  603. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  604. constructor TutlListBase.Create(const aOwnsObjects: Boolean);
  605. begin
  606. inherited Create;
  607. fOwnsObjects := aOwnsObjects;
  608. fList := TFPList.Create;
  609. end;
  610. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  611. destructor TutlListBase.Destroy;
  612. begin
  613. Clear;
  614. FreeAndNil(fList);
  615. inherited Destroy;
  616. end;
  617. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  618. //TutlSimpleList////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  619. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  620. function TutlSimpleList.Split(aComparer: IComparer; const aDirection: TSortDirection; const aLeft, aRight: Integer): Integer;
  621. var
  622. i, j: Integer;
  623. pivot: T;
  624. begin
  625. i := aLeft;
  626. j := aRight - 1;
  627. pivot := GetItem(aRight);
  628. repeat
  629. while ((aDirection = sdAscending) and (aComparer.Compare(GetItem(i), pivot) <= 0) or
  630. (aDirection = sdDescending) and (aComparer.Compare(GetItem(i), pivot) >= 0)) and
  631. (i < aRight) do inc(i);
  632. while ((aDirection = sdAscending) and (aComparer.Compare(GetItem(j), pivot) >= 0) or
  633. (aDirection = sdDescending) and (aComparer.Compare(GetItem(j), pivot) <= 0)) and
  634. (j > aLeft) do dec(j);
  635. if (i < j) then
  636. Exchange(i, j);
  637. until (i >= j);
  638. if ((aDirection = sdAscending) and (aComparer.Compare(GetItem(i), pivot) > 0)) or
  639. ((aDirection = sdDescending) and (aComparer.Compare(GetItem(i), pivot) < 0)) then
  640. Exchange(i, aRight);
  641. result := i;
  642. end;
  643. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  644. procedure TutlSimpleList.QuickSort(aComparer: IComparer; const aDirection: TSortDirection; const aLeft, aRight: Integer);
  645. var
  646. s: Integer;
  647. begin
  648. if (aLeft < aRight) then begin
  649. s := Split(aComparer, aDirection, aLeft, aRight);
  650. QuickSort(aComparer, aDirection, aLeft, s - 1);
  651. QuickSort(aComparer, aDirection, s + 1, aRight);
  652. end;
  653. end;
  654. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  655. function TutlSimpleList.Add(const aItem: T): Integer;
  656. begin
  657. result := Count;
  658. InsertIntern(result, aItem);
  659. end;
  660. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  661. procedure TutlSimpleList.Insert(const aIndex: Integer; const aItem: T);
  662. begin
  663. InsertIntern(aIndex, aItem);
  664. end;
  665. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  666. procedure TutlSimpleList.Exchange(const aIndex1, aIndex2: Integer);
  667. begin
  668. if (aIndex1 < 0) or (aIndex1 >= Count) then
  669. raise EOutOfRange.Create(aIndex1, 0, Count-1);
  670. if (aIndex2 < 0) or (aIndex2 >= Count) then
  671. raise EOutOfRange.Create(aIndex2, 0, Count-1);
  672. fList.Exchange(aIndex1, aIndex2);
  673. end;
  674. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  675. procedure TutlSimpleList.Move(const aCurIndex, aNewIndex: Integer);
  676. begin
  677. if (aCurIndex < 0) or (aCurIndex >= Count) then
  678. raise EOutOfRange.Create(aCurIndex, 0, Count-1);
  679. if (aNewIndex < 0) or (aNewIndex >= Count) then
  680. raise EOutOfRange.Create(aNewIndex, 0, Count-1);
  681. fList.Move(aCurIndex, aNewIndex);
  682. end;
  683. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  684. procedure TutlSimpleList.Sort(aComparer: IComparer; const aDirection: TSortDirection);
  685. begin
  686. QuickSort(aComparer, aDirection, 0, fList.Count-1);
  687. end;
  688. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  689. procedure TutlSimpleList.Delete(const aIndex: Integer);
  690. begin
  691. DeleteIntern(aIndex);
  692. end;
  693. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  694. function TutlSimpleList.First: T;
  695. begin
  696. result := Items[0];
  697. end;
  698. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  699. procedure TutlSimpleList.PushFirst(const aItem: T);
  700. begin
  701. InsertIntern(0, aItem);
  702. end;
  703. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  704. function TutlSimpleList.PopFirst(const aFreeItem: Boolean): T;
  705. begin
  706. if aFreeItem then
  707. FillByte(result{%H-}, SizeOf(result), 0)
  708. else
  709. result := First;
  710. DeleteIntern(0, aFreeItem);
  711. end;
  712. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  713. function TutlSimpleList.Last: T;
  714. begin
  715. result := Items[Count-1];
  716. end;
  717. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  718. procedure TutlSimpleList.PushLast(const aItem: T);
  719. begin
  720. InsertIntern(Count, aItem);
  721. end;
  722. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  723. function TutlSimpleList.PopLast(const aFreeItem: Boolean): T;
  724. begin
  725. if aFreeItem then
  726. FillByte(result{%H-}, SizeOf(result), 0)
  727. else
  728. result := Last;
  729. DeleteIntern(Count-1, aFreeItem);
  730. end;
  731. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  732. //TutlCustomList////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  733. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  734. function TutlCustomList.IndexOf(const aItem: T): Integer;
  735. var
  736. c: Integer;
  737. begin
  738. c := List.Count;
  739. result := 0;
  740. while (result < c) and
  741. not fEqualityComparer.EqualityCompare(PListItem(List[result])^.data, aItem) do
  742. inc(result);
  743. if (result >= c) then
  744. result := -1;
  745. end;
  746. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  747. function TutlCustomList.Extract(const aItem: T; const aDefault: T): T;
  748. var
  749. i: Integer;
  750. begin
  751. i := IndexOf(aItem);
  752. if (i >= 0) then begin
  753. result := Items[i];
  754. DeleteIntern(i, false);
  755. end else
  756. result := aDefault;
  757. end;
  758. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  759. function TutlCustomList.Remove(const aItem: T): Integer;
  760. begin
  761. result := IndexOf(aItem);
  762. if (result >= 0) then
  763. DeleteIntern(result);
  764. end;
  765. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  766. constructor TutlCustomList.Create(aEqualityComparer: IEqualityComparer; const aOwnsObjects: Boolean);
  767. begin
  768. inherited Create(aOwnsObjects);
  769. fEqualityComparer := aEqualityComparer;
  770. end;
  771. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  772. destructor TutlCustomList.Destroy;
  773. begin
  774. fEqualityComparer := nil;
  775. inherited Destroy;
  776. end;
  777. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  778. //TutlList//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  779. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  780. constructor TutlList.Create(const aOwnsObjects: Boolean);
  781. begin
  782. inherited Create(TEqualityComparer.Create, aOwnsObjects);
  783. end;
  784. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  785. //TutlCustomHashSet/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  786. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  787. function TutlCustomHashSet.SearchItem(const aMin, aMax: Integer; const aItem: T; out aIndex: Integer): Integer;
  788. var
  789. i, cmp: Integer;
  790. begin
  791. if (aMin <= aMax) then begin
  792. i := aMin + Trunc((aMax - aMin) / 2);
  793. cmp := fComparer.Compare(aItem, GetItem(i));
  794. if (cmp = 0) then
  795. result := i
  796. else if (cmp < 0) then
  797. result := SearchItem(aMin, i-1, aItem, aIndex)
  798. else if (cmp > 0) then
  799. result := SearchItem(i+1, aMax, aItem, aIndex);
  800. end else begin
  801. result := -1;
  802. aIndex := aMin;
  803. end;
  804. end;
  805. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  806. function TutlCustomHashSet.Add(const aItem: T): Boolean;
  807. var
  808. i: Integer;
  809. begin
  810. result := (SearchItem(0, List.Count-1, aItem, i) < 0);
  811. if result then
  812. InsertIntern(i, aItem);
  813. end;
  814. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  815. function TutlCustomHashSet.Contains(const aItem: T): Boolean;
  816. var
  817. tmp: Integer;
  818. begin
  819. result := (SearchItem(0, List.Count-1, aItem, tmp) >= 0);
  820. end;
  821. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  822. function TutlCustomHashSet.IndexOf(const aItem: T): Integer;
  823. var
  824. tmp: Integer;
  825. begin
  826. result := SearchItem(0, List.Count-1, aItem, tmp);
  827. end;
  828. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  829. function TutlCustomHashSet.Remove(const aItem: T): Boolean;
  830. var
  831. i, tmp: Integer;
  832. begin
  833. i := SearchItem(0, List.Count-1, aItem, tmp);
  834. result := (i >= 0);
  835. if result then
  836. DeleteIntern(i);
  837. end;
  838. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  839. procedure TutlCustomHashSet.Delete(const aIndex: Integer);
  840. begin
  841. DeleteIntern(aIndex);
  842. end;
  843. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  844. constructor TutlCustomHashSet.Create(aComparer: IComparer; const aOwnsObjects: Boolean);
  845. begin
  846. inherited Create(aOwnsObjects);
  847. fComparer := aComparer;
  848. end;
  849. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  850. destructor TutlCustomHashSet.Destroy;
  851. begin
  852. fComparer := nil;
  853. inherited Destroy;
  854. end;
  855. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  856. //TutlHashSet///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  857. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  858. constructor TutlHashSet.Create(const aOwnsObjects: Boolean);
  859. begin
  860. inherited Create(TComparer.Create, aOwnsObjects);
  861. end;
  862. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  863. //TutlCustomMap.THashSet////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  864. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  865. procedure TutlCustomMap.THashSet.DestroyItem(const aItem: PListItem; const aFreeItem: Boolean);
  866. begin
  867. utlFreeOrFinalize(aItem^.data.key, TypeInfo(aItem^.data.key), aFreeItem and OwnsObjects);
  868. utlFreeOrFinalize(aItem^.data.value, TypeInfo(aItem^.data.value), aFreeItem and OwnsObjects);
  869. inherited DestroyItem(aItem, aFreeItem);
  870. end;
  871. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  872. //TutlCustomMap.TKVPComparer////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  873. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  874. function TutlCustomMap.TKVPComparer.Compare(const i1, i2: TKeyValuePair): Integer;
  875. begin
  876. result := fComparer.Compare(i1.Key, i2.Key);
  877. end;
  878. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  879. constructor TutlCustomMap.TKVPComparer.Create(aComparer: IComparer);
  880. begin
  881. inherited Create;
  882. fComparer := aComparer;
  883. end;
  884. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  885. destructor TutlCustomMap.TKVPComparer.Destroy;
  886. begin
  887. fComparer := nil;
  888. inherited Destroy;
  889. end;
  890. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  891. //TutlCustomMap.TValueEnumerator////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  892. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  893. function TutlCustomMap.TValueEnumerator.GetCurrent: TValue;
  894. begin
  895. result := fHashSet[fPos].Value;
  896. end;
  897. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  898. function TutlCustomMap.TValueEnumerator.MoveNext: Boolean;
  899. begin
  900. inc(fPos);
  901. result := (fPos < fHashSet.Count);
  902. end;
  903. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  904. constructor TutlCustomMap.TValueEnumerator.Create(const aHashSet: THashSet);
  905. begin
  906. inherited Create;
  907. fHashSet := aHashSet;
  908. fPos := -1;
  909. end;
  910. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  911. //TutlCustomMap.TKeyEnumerator//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  912. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  913. function TutlCustomMap.TKeyEnumerator.GetCurrent: TKey;
  914. begin
  915. result := fHashSet[fPos].Key;
  916. end;
  917. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  918. function TutlCustomMap.TKeyEnumerator.MoveNext: Boolean;
  919. begin
  920. inc(fPos);
  921. result := (fPos < fHashSet.Count);
  922. end;
  923. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  924. constructor TutlCustomMap.TKeyEnumerator.Create(const aHashSet: THashSet);
  925. begin
  926. inherited Create;
  927. fHashSet := aHashSet;
  928. fPos := -1;
  929. end;
  930. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  931. //TutlCustomMap.TKeyValuePairEnumerator/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  932. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  933. function TutlCustomMap.TKeyValuePairEnumerator.GetCurrent: TKeyValuePair;
  934. begin
  935. result := fHashSet[fPos];
  936. end;
  937. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  938. function TutlCustomMap.TKeyValuePairEnumerator.MoveNext: Boolean;
  939. begin
  940. inc(fPos);
  941. result := (fPos < fHashSet.Count);
  942. end;
  943. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  944. constructor TutlCustomMap.TKeyValuePairEnumerator.Create(const aHashSet: THashSet);
  945. begin
  946. inherited Create;
  947. fHashSet := aHashSet;
  948. fPos := -1;
  949. end;
  950. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  951. //TutlCustomMap.TKeyWrapper/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  952. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  953. function TutlCustomMap.TKeyWrapper.GetItem(const aIndex: Integer): TKey;
  954. begin
  955. result := fHashSet[aIndex].Key;
  956. end;
  957. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  958. function TutlCustomMap.TKeyWrapper.GetCount: Integer;
  959. begin
  960. result := fHashSet.Count;
  961. end;
  962. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  963. function TutlCustomMap.TKeyWrapper.GetEnumerator: TKeyEnumerator;
  964. begin
  965. result := TKeyEnumerator.Create(fHashSet);
  966. end;
  967. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  968. constructor TutlCustomMap.TKeyWrapper.Create(const aHashSet: THashSet);
  969. begin
  970. inherited Create;
  971. fHashSet := aHashSet;
  972. end;
  973. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  974. //TutlCustomMap.TKeyValuePairWrapper////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  975. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  976. function TutlCustomMap.TKeyValuePairWrapper.GetItem(const aIndex: Integer): TKeyValuePair;
  977. begin
  978. result := fHashSet[aIndex];
  979. end;
  980. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  981. function TutlCustomMap.TKeyValuePairWrapper.GetCount: Integer;
  982. begin
  983. result := fHashSet.Count;
  984. end;
  985. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  986. function TutlCustomMap.TKeyValuePairWrapper.GetEnumerator: TKeyValuePairEnumerator;
  987. begin
  988. result := TKeyValuePairEnumerator.Create(fHashSet);
  989. end;
  990. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  991. constructor TutlCustomMap.TKeyValuePairWrapper.Create(const aHashSet: THashSet);
  992. begin
  993. inherited Create;
  994. fHashSet := aHashSet;
  995. end;
  996. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  997. //TutlCustomMap/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  998. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  999. function TutlCustomMap.GetValues(const aKey: TKey): TValue;
  1000. var
  1001. i: Integer;
  1002. kvp: TKeyValuePair;
  1003. begin
  1004. kvp.Key := aKey;
  1005. i := fHashSet.IndexOf(kvp);
  1006. if (i < 0) then
  1007. FillByte(result{%H-}, SizeOf(result), 0)
  1008. else
  1009. result := fHashSet[i].Value;
  1010. end;
  1011. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1012. function TutlCustomMap.GetValueAt(const aIndex: Integer): TValue;
  1013. begin
  1014. result := fHashSet[aIndex].Value;
  1015. end;
  1016. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1017. function TutlCustomMap.GetCount: Integer;
  1018. begin
  1019. result := fHashSet.Count;
  1020. end;
  1021. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1022. procedure TutlCustomMap.SetValues(const aKey: TKey; aValue: TValue);
  1023. var
  1024. i: Integer;
  1025. kvp: TKeyValuePair;
  1026. begin
  1027. kvp.Key := aKey;
  1028. kvp.Value := aValue;
  1029. i := fHashSet.IndexOf(kvp);
  1030. if (i < 0) then
  1031. raise EutlMap.Create('key not found');
  1032. fHashSet[i] := kvp;
  1033. end;
  1034. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1035. procedure TutlCustomMap.SetValueAt(const aIndex: Integer; aValue: TValue);
  1036. var
  1037. kvp: TKeyValuePair;
  1038. begin
  1039. kvp := fHashSet[aIndex];
  1040. kvp.Value := aValue;
  1041. fHashSet[aIndex] := kvp;
  1042. end;
  1043. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1044. procedure TutlCustomMap.Add(const aKey: TKey; const aValue: TValue);
  1045. var
  1046. kvp: TKeyValuePair;
  1047. begin
  1048. kvp.Key := aKey;
  1049. kvp.Value := aValue;
  1050. if not fHashSet.Add(kvp) then
  1051. raise EutlMap.Create('key is already in list');
  1052. end;
  1053. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1054. function TutlCustomMap.IndexOf(const aKey: TKey): Integer;
  1055. var
  1056. kvp: TKeyValuePair;
  1057. begin
  1058. kvp.Key := aKey;
  1059. result := fHashSet.IndexOf(kvp);
  1060. end;
  1061. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1062. function TutlCustomMap.Contains(const aKey: TKey): Boolean;
  1063. var
  1064. kvp: TKeyValuePair;
  1065. begin
  1066. kvp.Key := aKey;
  1067. result := (fHashSet.IndexOf(kvp) >= 0);
  1068. end;
  1069. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1070. procedure TutlCustomMap.Delete(const aKey: TKey);
  1071. var
  1072. kvp: TKeyValuePair;
  1073. begin
  1074. kvp.Key := aKey;
  1075. if not fHashSet.Remove(kvp) then
  1076. raise EutlMap.Create('key not found');
  1077. end;
  1078. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1079. procedure TutlCustomMap.DeleteAt(const aIndex: Integer);
  1080. begin
  1081. fHashSet.Delete(aIndex);
  1082. end;
  1083. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1084. procedure TutlCustomMap.Clear;
  1085. begin
  1086. fHashSet.Clear;
  1087. end;
  1088. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1089. function TutlCustomMap.GetEnumerator: TValueEnumerator;
  1090. begin
  1091. result := TValueEnumerator.Create(fHashSet);
  1092. end;
  1093. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1094. constructor TutlCustomMap.Create(aComparer: IComparer; const aOwnsObjects: Boolean);
  1095. begin
  1096. inherited Create;
  1097. fComparer := aComparer;
  1098. fHashSet := THashSet.Create(TKVPComparer.Create(fComparer), aOwnsObjects);
  1099. fKeyWrapper := TKeyWrapper.Create(fHashSet);
  1100. fKeyValuePairWrapper := TKeyValuePairWrapper.Create(fHashSet);
  1101. end;
  1102. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1103. destructor TutlCustomMap.Destroy;
  1104. begin
  1105. FreeAndNil(fKeyValuePairWrapper);
  1106. FreeAndNil(fKeyWrapper);
  1107. FreeAndNil(fHashSet);
  1108. fComparer := nil;
  1109. inherited Destroy;
  1110. end;
  1111. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1112. //TutlMap///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1113. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1114. constructor TutlMap.Create(const aOwnsObjects: Boolean);
  1115. begin
  1116. inherited Create(TComparer.Create, aOwnsObjects);
  1117. end;
  1118. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1119. //TutlQueue/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1120. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1121. function TutlQueue.GetCount: Integer;
  1122. begin
  1123. InterLockedExchange(result{%H-}, fCount);
  1124. end;
  1125. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1126. procedure TutlQueue.Push(const aItem: T);
  1127. var
  1128. p: PListItem;
  1129. begin
  1130. // do as much as possible outside of the lock
  1131. new(p);
  1132. p^.data := aItem;
  1133. p^.next := nil;
  1134. while (InterLockedExchange(fLastLock, 1) <> 0) do;
  1135. try
  1136. fLast^.next := p; // is protected by fCount (if fCount = 0 then fLast = fFirst,
  1137. fLast := fLast^.next; // so pop must always check fCount, before touching fFirst)
  1138. InterLockedIncrement(fCount);
  1139. finally
  1140. InterLockedExchange(fLastLock, 0);
  1141. end;
  1142. end;
  1143. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1144. function TutlQueue.Pop(out aItem: T): Boolean;
  1145. var
  1146. old: PListItem;
  1147. begin
  1148. // do as much as possible outside of the lock
  1149. result := false;
  1150. FillByte(aItem{%H-}, SizeOf(aItem), 0);
  1151. while (InterLockedExchange(fFirstLock, 1) <> 0) do;
  1152. try
  1153. if (Count <= 0) then
  1154. exit;
  1155. result := true;
  1156. old := fFirst;
  1157. fFirst := fFirst^.next;
  1158. aItem := fFirst^.data;
  1159. InterLockedDecrement(fCount);
  1160. finally
  1161. InterLockedExchange(fFirstLock, 0);
  1162. end;
  1163. Dispose(old);
  1164. end;
  1165. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1166. function TutlQueue.Pop: Boolean;
  1167. var
  1168. tmp: T;
  1169. begin
  1170. result := Pop(tmp);
  1171. utlFreeOrFinalize(tmp, TypeInfo(tmp), fOwnsObjects);
  1172. end;
  1173. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1174. procedure TutlQueue.Clear;
  1175. begin
  1176. while Pop do;
  1177. end;
  1178. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1179. constructor TutlQueue.Create(const aOwnsObjects: Boolean);
  1180. begin
  1181. inherited Create;
  1182. new(fFirst);
  1183. FillByte(fFirst^, SizeOf(fFirst^), 0);
  1184. fLast := fFirst;
  1185. fFirstLock := 0;
  1186. fLastLock := 0;
  1187. fCount := 0;
  1188. fOwnsObjects := aOwnsObjects;
  1189. end;
  1190. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1191. destructor TutlQueue.Destroy;
  1192. begin
  1193. Clear;
  1194. if Assigned(fLast) then begin
  1195. Dispose(fLast);
  1196. fLast := nil;
  1197. end;
  1198. inherited Destroy;
  1199. end;
  1200. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1201. //TutlInterfaceList.TInterfaceEnumerator////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1202. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1203. function TutlInterfaceList.TInterfaceEnumerator.GetCurrent: T;
  1204. begin
  1205. result := T(fList[fPos]);
  1206. end;
  1207. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1208. function TutlInterfaceList.TInterfaceEnumerator.MoveNext: Boolean;
  1209. begin
  1210. inc(fPos);
  1211. result := (fPos < fList.Count);
  1212. end;
  1213. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1214. constructor TutlInterfaceList.TInterfaceEnumerator.Create(const aList: TInterfaceList);
  1215. begin
  1216. inherited Create;
  1217. fPos := -1;
  1218. fList := aList;
  1219. end;
  1220. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1221. //TutlInterfaceList/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1222. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1223. function TutlInterfaceList.Get(i : Integer): T;
  1224. begin
  1225. result := T(inherited Get(i));
  1226. end;
  1227. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1228. procedure TutlInterfaceList.Put(i : Integer; aItem : T);
  1229. begin
  1230. inherited Put(i, aItem);
  1231. end;
  1232. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1233. function TutlInterfaceList.First: T;
  1234. begin
  1235. result := T(inherited First);
  1236. end;
  1237. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1238. function TutlInterfaceList.IndexOf(aItem : T): Integer;
  1239. begin
  1240. result := inherited IndexOf(aItem);
  1241. end;
  1242. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1243. function TutlInterfaceList.Add(aItem : IUnknown): Integer;
  1244. begin
  1245. result := inherited Add(aItem);
  1246. end;
  1247. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1248. procedure TutlInterfaceList.Insert(i : Integer; aItem : T);
  1249. begin
  1250. inherited Insert(i, aItem);
  1251. end;
  1252. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1253. function TutlInterfaceList.Last : T;
  1254. begin
  1255. result := T(inherited Last);
  1256. end;
  1257. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1258. function TutlInterfaceList.Remove(aItem : T): Integer;
  1259. begin
  1260. result := inherited Remove(aItem);
  1261. end;
  1262. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1263. function TutlInterfaceList.GetEnumerator: TInterfaceEnumerator;
  1264. begin
  1265. result := TInterfaceEnumerator.Create(self);
  1266. end;
  1267. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1268. //TutlEnumHelper////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1269. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1270. class function TutlEnumHelper.ToString(aValue: T): String;
  1271. Var
  1272. PS: PShortString;
  1273. TI: PTypeInfo;
  1274. PT: PTypeData;
  1275. num: Integer;
  1276. begin
  1277. TI := TypeInfo(T);
  1278. PT := GetTypeData(TI);
  1279. if TI^.Kind = tkBool then begin
  1280. case Integer(aValue) of
  1281. 0,1:
  1282. Result:=BooleanIdents[Boolean(aValue)];
  1283. else
  1284. Result:='';
  1285. end;
  1286. end else begin
  1287. num := Integer(aValue);
  1288. if (num >= PT^.MinValue) and (num <= PT^.MaxValue) then begin
  1289. PS := @PT^.NameList;
  1290. dec(num, PT^.MinValue);
  1291. while num > 0 do begin
  1292. PS := PShortString(pointer(PS) + PByte(PS)^ + 1);
  1293. Dec(Num);
  1294. end;
  1295. Result := PS^;
  1296. end else
  1297. Result := '';
  1298. end;
  1299. end;
  1300. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1301. class function TutlEnumHelper.TryToEnum(aStr: String; out aValue: T): Boolean;
  1302. Var
  1303. PS: PShortString;
  1304. PT: PTypeData;
  1305. Count: longint;
  1306. sName: shortstring;
  1307. TI: PTypeInfo;
  1308. begin
  1309. TI := TypeInfo(T);
  1310. PT := GetTypeData(TI);
  1311. Result := False;
  1312. if Length(aStr) = 0 then
  1313. exit;
  1314. sName := aStr;
  1315. if TI^.Kind = tkBool then begin
  1316. If CompareText(BooleanIdents[false], aStr) = 0 then
  1317. aValue := T(0)
  1318. else if CompareText(BooleanIdents[true], aStr) = 0 then
  1319. aValue := T(1);
  1320. Result := true;
  1321. end else begin
  1322. PS := @PT^.NameList;
  1323. Count := 0;
  1324. While (PByte(PS)^ <> 0) do begin
  1325. If ShortCompareText(PS^, sName) = 0 then begin
  1326. aValue := T(Count + PT^.MinValue);
  1327. exit(true);
  1328. end;
  1329. PS := PShortString(pointer(PS) + PByte(PS)^ + 1);
  1330. Inc(Count);
  1331. end;
  1332. end;
  1333. end;
  1334. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1335. class function TutlEnumHelper.ToEnum(aStr: String): T;
  1336. begin
  1337. if not TryToEnum(aStr, result) then
  1338. raise EConvertError.CreateFmt('"%s" is an invalid %s',[aStr, PTypeInfo(TypeInfo(T))^.Name]);
  1339. end;
  1340. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1341. class function TutlEnumHelper.ToEnum(aStr: String; const aDefault: T): T;
  1342. begin
  1343. if not TryToEnum(aStr, result) then
  1344. result := aDefault;
  1345. end;
  1346. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1347. class function TutlEnumHelper.Values: TValueArray;
  1348. Var
  1349. TI: PTypeInfo;
  1350. PT: PTypeData;
  1351. i,j: integer;
  1352. begin
  1353. TI := TypeInfo(T);
  1354. PT := GetTypeData(TI);
  1355. if TI^.Kind = tkBool then begin
  1356. SetLength(Result, 2);
  1357. Result[0]:= T(true);
  1358. Result[1]:= T(false);
  1359. end else begin
  1360. SetLength(Result, PT^.MaxValue - PT^.MinValue + 1);
  1361. j:= 0;
  1362. for i:= PT^.MinValue to PT^.MaxValue do begin
  1363. Result[j]:= T(i);
  1364. inc(j);
  1365. end;
  1366. end;
  1367. end;
  1368. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1369. //TutlRingBuffer////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1370. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1371. constructor TutlRingBuffer.Create(const Elements: Integer);
  1372. begin
  1373. inherited Create;
  1374. fAborted:= false;
  1375. fDataLen:= Elements;
  1376. fDataSize:= SizeOf(T);
  1377. SetLength(fData, fDataLen);
  1378. fWritePtr:= 1;
  1379. fReadPtr:= 0;
  1380. fFillState:= 0;
  1381. fReadEvent:= TAutoResetEvent.Create;
  1382. fWrittenEvent:= TAutoResetEvent.Create;
  1383. end;
  1384. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1385. destructor TutlRingBuffer.Destroy;
  1386. begin
  1387. BreakPipe;
  1388. FreeAndNil(fReadEvent);
  1389. FreeAndNil(fWrittenEvent);
  1390. SetLength(fData, 0);
  1391. inherited Destroy;
  1392. end;
  1393. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1394. function TutlRingBuffer.Read(Buf: Pointer; Items: integer; BlockUntilAvail: boolean): integer;
  1395. var
  1396. wp, c, r: Integer;
  1397. begin
  1398. Result:= 0;
  1399. while Items > 0 do begin
  1400. if fAborted then
  1401. exit;
  1402. InterLockedExchange(wp{%H-}, fWritePtr);
  1403. r:= (fReadPtr + 1) mod fDataLen;
  1404. if wp < r then
  1405. wp:= fDataLen;
  1406. c:= wp - r;
  1407. if c > Items then
  1408. c:= Items;
  1409. if c > 0 then begin
  1410. Move(fData[r], Buf^, c * fDataSize);
  1411. Dec(Items, c);
  1412. inc(Result, c);
  1413. dec(fFillState, c);
  1414. inc(PByte(Buf), c * fDataSize);
  1415. InterLockedExchange(fReadPtr, (fReadPtr + c) mod fDataLen);
  1416. fReadEvent.SetEvent;
  1417. end else begin
  1418. if not BlockUntilAvail then
  1419. break;
  1420. fWrittenEvent.WaitFor(INFINITE);
  1421. end;
  1422. end;
  1423. end;
  1424. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1425. function TutlRingBuffer.Write(Buf: Pointer; Items: integer; BlockUntilDone: boolean): integer;
  1426. var
  1427. rp, c: integer;
  1428. begin
  1429. Result:= 0;
  1430. while Items > 0 do begin
  1431. if fAborted then
  1432. exit;
  1433. InterLockedExchange(rp{%H-}, fReadPtr);
  1434. if rp < fWritePtr then
  1435. rp:= fDataLen;
  1436. c:= rp - fWritePtr;
  1437. if c > Items then
  1438. c:= Items;
  1439. if c > 0 then begin
  1440. Move(Buf^, fData[fWritePtr], c * fDataSize);
  1441. dec(Items, c);
  1442. inc(Result, c);
  1443. inc(fFillState, c);
  1444. inc(PByte(Buf), c * fDataSize);
  1445. InterLockedExchange(fWritePtr, (fWritePtr + c) mod fDataLen);
  1446. fWrittenEvent.SetEvent;
  1447. end else begin
  1448. if not BlockUntilDone then
  1449. Break;
  1450. fReadEvent.WaitFor(INFINITE);
  1451. end;
  1452. end;
  1453. end;
  1454. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1455. procedure TutlRingBuffer.BreakPipe;
  1456. begin
  1457. fAborted:= true;
  1458. fWrittenEvent.SetEvent;
  1459. fReadEvent.SetEvent;
  1460. end;
  1461. end.