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.

2134 rivejä
85 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. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  376. generic TutlPagedDataFiFo<TData> = class
  377. private type
  378. PPage = ^TPage;
  379. TPage = packed record
  380. Next: PPage;
  381. Data: array of TData;
  382. ReadPos: Integer;
  383. WritePos: Integer;
  384. end;
  385. public type
  386. PData = ^TData;
  387. IDataProvider = interface(IUnknown)
  388. function Give(const aBuffer: PData; aCount: Integer): Integer;
  389. end;
  390. IDataConsumer = interface(IUnknown)
  391. function Take(const aBuffer: PData; aCount: Integer): Integer;
  392. end;
  393. // read from buffer, write to fifo
  394. TDataProvider = class(TInterfacedObject, IDataProvider)
  395. private
  396. fData: PData;
  397. fPos: Integer;
  398. fCount: Integer;
  399. public
  400. function Give(const aBuffer: PData; aCount: Integer): Integer;
  401. constructor Create(const aData: PData; const aCount: Integer);
  402. end;
  403. // read from fifo, write to buffer
  404. TDataConsumer = class(TInterfacedObject, IDataConsumer)
  405. private
  406. fData: PData;
  407. fPos: Integer;
  408. fCount: Integer;
  409. public
  410. function Take(const aBuffer: PData; aCount: Integer): Integer;
  411. constructor Create(const aData: PData; const aCount: Integer);
  412. end;
  413. // read from nested callback, write to fifo
  414. TDataCallback = function(const aBuffer: PData; aCount: Integer): Integer is nested;
  415. TNestedDataProvider = class(TInterfacedObject, IDataProvider)
  416. private
  417. fCallback: TDataCallback;
  418. public
  419. function Give(const aBuffer: PData; aCount: Integer): Integer;
  420. constructor Create(const aCallback: TDataCallback);
  421. end;
  422. // read from fifo, write to nested callback
  423. TNestedDataConsumer = class(TInterfacedObject, IDataConsumer)
  424. private
  425. fCallback: TDataCallback;
  426. public
  427. function Take(const aBuffer: PData; aCount: Integer): Integer;
  428. constructor Create(const aCallback: TDataCallback);
  429. end;
  430. // read from stream, write to fifo
  431. TStreamDataProvider = class(TInterfacedObject, IDataProvider)
  432. private
  433. fStream: TStream;
  434. public
  435. function Give(const aBuffer: PData; aCount: Integer): Integer;
  436. constructor Create(const aStream: TStream);
  437. end;
  438. // read from fifo, write to stream
  439. TStreamDataConsumer = class(TInterfacedObject, IDataConsumer)
  440. private
  441. fStream: TStream;
  442. public
  443. function Take(const aBuffer: PData; aCount: Integer): Integer;
  444. constructor Create(const aStream: TStream);
  445. end;
  446. private
  447. fPageSize: Integer;
  448. fReadPage: PPage;
  449. fWritePage: PPage;
  450. fSize: Integer;
  451. protected
  452. function WriteIntern(const aProvider: IDataProvider; aCount: Integer): Integer; virtual;
  453. function ReadIntern(const aConsumer: IDataConsumer; aCount: Integer; const aMoveReadPos: Boolean): Integer; virtual;
  454. public
  455. property Size: Integer read fSize;
  456. property PageSize: Integer read fPageSize;
  457. function Write(const aProvider: IDataProvider; const aCount: Integer): Integer; overload;
  458. function Write(const aData: PData; const aCount: Integer): Integer; overload;
  459. function Read(const aConsumer: IDataConsumer; const aCount: Integer): Integer; overload;
  460. function Read(const aData: PData; const aCount: Integer): Integer; overload;
  461. function Peek(const aConsumer: IDataConsumer; const aCount: Integer): Integer; overload;
  462. function Peek(const aData: PData; const aCount: Integer): Integer; overload;
  463. function Discard(const aCount: Integer): Integer;
  464. procedure Clear;
  465. constructor Create(const aPageSize: Integer = 2048);
  466. destructor Destroy; override;
  467. end;
  468. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  469. generic TutlSyncPagedDataFiFo<TData> = class(specialize TutlPagedDataFiFo<TData>)
  470. private
  471. fLock: TutlSpinLock;
  472. protected
  473. function WriteIntern(const aProvider: IDataProvider; aCount: Integer): Integer; override;
  474. function ReadIntern(const aConsumer: IDataConsumer; aCount: Integer; const aMoveReadPos: Boolean): Integer; override;
  475. public
  476. constructor Create(const aPageSize: Integer = 2048);
  477. destructor Destroy; override;
  478. end;
  479. function utlFreeOrFinalize(var obj; const aTypeInfo: PTypeInfo; const aFreeObj: Boolean = true): Boolean;
  480. implementation
  481. uses
  482. uutlExceptions, syncobjs;
  483. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  484. //Helper////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  485. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  486. operator < (const i1, i2: TObject): Boolean; inline;
  487. begin
  488. result := PtrUInt(i1) < PtrUInt(i2);
  489. end;
  490. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  491. operator > (const i1, i2: TObject): Boolean; inline;
  492. begin
  493. result := PtrUInt(i1) > PtrUInt(i2);
  494. end;
  495. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  496. function utlFreeOrFinalize(var obj; const aTypeInfo: PTypeInfo; const aFreeObj: Boolean = true): Boolean;
  497. var
  498. o: TObject;
  499. begin
  500. result := true;
  501. case aTypeInfo^.Kind of
  502. tkClass: begin
  503. if (aFreeObj) then begin
  504. o := TObject(obj);
  505. Pointer(obj) := nil;
  506. o.Free;
  507. end;
  508. end;
  509. tkInterface: begin
  510. IUnknown(obj) := nil;
  511. end;
  512. tkAString: begin
  513. AnsiString(Obj) := '';
  514. end;
  515. tkUString: begin
  516. UnicodeString(Obj) := '';
  517. end;
  518. tkString: begin
  519. String(Obj) := '';
  520. end;
  521. else
  522. result := false;
  523. end;
  524. end;
  525. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  526. //TutlEqualityComparer//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  527. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  528. function TutlEqualityComparer.EqualityCompare(const i1, i2: T): Boolean;
  529. begin
  530. result := (i1 = i2);
  531. end;
  532. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  533. function TutlEventEqualityComparer.EqualityCompare(const i1, i2: T): Boolean;
  534. begin
  535. case fEventType of
  536. eetNormal: result := fEvent(i1, i2);
  537. eetObject: result := fEventO(i1, i2);
  538. eetNested: result := fEventN(i1, i2);
  539. end;
  540. end;
  541. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  542. constructor TutlEventEqualityComparer.Create(const aEvent: TEqualityEvent);
  543. begin
  544. inherited Create;
  545. fEvent := aEvent;
  546. fEventType := eetNormal;
  547. end;
  548. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  549. constructor TutlEventEqualityComparer.Create(const aEvent: TEqualityEventO);
  550. begin
  551. inherited Create;
  552. fEventO := aEvent;
  553. fEventType := eetObject;
  554. end;
  555. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  556. constructor TutlEventEqualityComparer.Create(const aEvent: TEqualityEventN);
  557. begin
  558. inherited Create;
  559. fEventN := aEvent;
  560. fEventType := eetNested;
  561. end;
  562. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  563. //TutlComparer//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  564. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  565. function TutlComparer.Compare(const i1, i2: T): Integer;
  566. begin
  567. if (i1 < i2) then
  568. result := -1
  569. else if (i1 > i2) then
  570. result := 1
  571. else
  572. result := 0;
  573. end;
  574. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  575. function TutlEventComparer.Compare(const i1, i2: T): Integer;
  576. begin
  577. case fEventType of
  578. etNormal: result := fEvent(i1, i2);
  579. etObject: result := fEventO(i1, i2);
  580. etNested: result := fEventN(i1, i2);
  581. end;
  582. end;
  583. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  584. constructor TutlEventComparer.Create(const aEvent: TEvent);
  585. begin
  586. inherited Create;
  587. fEvent := aEvent;
  588. fEventType := etNormal;
  589. end;
  590. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  591. constructor TutlEventComparer.Create(const aEvent: TEventO);
  592. begin
  593. inherited Create;
  594. fEventO := aEvent;
  595. fEventType := etObject;
  596. end;
  597. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  598. constructor TutlEventComparer.Create(const aEvent: TEventN);
  599. begin
  600. inherited Create;
  601. fEventN := aEvent;
  602. fEventType := etNested;
  603. end;
  604. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  605. //TutlListBase//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  606. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  607. function TutlListBase.TEnumerator.GetCurrent: T;
  608. begin
  609. result := PListItem(fList[fPosition])^.data;
  610. end;
  611. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  612. function TutlListBase.TEnumerator.MoveNext: Boolean;
  613. begin
  614. inc(fPosition);
  615. result := (fPosition < fList.Count)
  616. end;
  617. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  618. constructor TutlListBase.TEnumerator.Create(const aList: TFPList);
  619. begin
  620. inherited Create;
  621. fList := aList;
  622. fPosition := -1;
  623. end;
  624. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  625. //TutlListBase//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  626. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  627. function TutlListBase.GetCount: Integer;
  628. begin
  629. result := fList.Count;
  630. end;
  631. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  632. function TutlListBase.GetItem(const aIndex: Integer): T;
  633. begin
  634. if (aIndex >= 0) and (aIndex < fList.Count) then
  635. result := PListItem(fList[aIndex])^.data
  636. else
  637. raise EOutOfRange.Create(aIndex, 0, fList.Count-1);
  638. end;
  639. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  640. procedure TutlListBase.SetCount(const aValue: Integer);
  641. var
  642. item: PListItem;
  643. begin
  644. if (aValue < 0) then
  645. raise EArgument.Create('new value for count must be positiv');
  646. while (aValue > fList.Count) do begin
  647. item := CreateItem;
  648. FillByte(item^, SizeOf(item^), 0);
  649. fList.Add(item);
  650. end;
  651. while (aValue < fList.Count) do
  652. DeleteIntern(fList.Count-1);
  653. end;
  654. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  655. procedure TutlListBase.SetItem(const aIndex: Integer; const aItem: T);
  656. var
  657. item: PListItem;
  658. begin
  659. if (aIndex >= 0) and (aIndex < fList.Count) then begin
  660. item := PListItem(fList[aIndex]);
  661. utlFreeOrFinalize(item^, TypeInfo(item^), fOwnsObjects);
  662. item^.data := aItem;
  663. end else
  664. raise EOutOfRange.Create(aIndex, 0, fList.Count-1);
  665. end;
  666. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  667. function TutlListBase.CreateItem: PListItem;
  668. begin
  669. new(result);
  670. end;
  671. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  672. procedure TutlListBase.DestroyItem(const aItem: PListItem; const aFreeItem: Boolean);
  673. begin
  674. utlFreeOrFinalize(aItem^.data, TypeInfo(aItem^.data), fOwnsObjects and aFreeItem);
  675. Dispose(aItem);
  676. end;
  677. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  678. procedure TutlListBase.InsertIntern(const aIndex: Integer; const aItem: T);
  679. var
  680. item: PListItem;
  681. begin
  682. item := CreateItem;
  683. try
  684. item^.data := aItem;
  685. fList.Insert(aIndex, item);
  686. except
  687. DestroyItem(item, false);
  688. raise;
  689. end;
  690. end;
  691. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  692. procedure TutlListBase.DeleteIntern(const aIndex: Integer; const aFreeItem: Boolean);
  693. var
  694. item: PListItem;
  695. begin
  696. if (aIndex >= 0) and (aIndex < fList.Count) then begin
  697. item := PListItem(fList[aIndex]);
  698. fList.Delete(aIndex);
  699. DestroyItem(item, aFreeItem);
  700. end else
  701. raise EOutOfRange.Create(aIndex, 0, fList.Count-1);
  702. end;
  703. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  704. function TutlListBase.GetEnumerator: TEnumerator;
  705. begin
  706. result := TEnumerator.Create(fList);
  707. end;
  708. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  709. procedure TutlListBase.Clear;
  710. begin
  711. while (fList.Count > 0) do
  712. DeleteIntern(fList.Count-1);
  713. end;
  714. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  715. constructor TutlListBase.Create(const aOwnsObjects: Boolean);
  716. begin
  717. inherited Create;
  718. fOwnsObjects := aOwnsObjects;
  719. fList := TFPList.Create;
  720. end;
  721. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  722. destructor TutlListBase.Destroy;
  723. begin
  724. Clear;
  725. FreeAndNil(fList);
  726. inherited Destroy;
  727. end;
  728. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  729. //TutlSimpleList////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  730. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  731. function TutlSimpleList.Split(aComparer: IComparer; const aDirection: TSortDirection; const aLeft, aRight: Integer): Integer;
  732. var
  733. i, j: Integer;
  734. pivot: T;
  735. begin
  736. i := aLeft;
  737. j := aRight - 1;
  738. pivot := GetItem(aRight);
  739. repeat
  740. while ((aDirection = sdAscending) and (aComparer.Compare(GetItem(i), pivot) <= 0) or
  741. (aDirection = sdDescending) and (aComparer.Compare(GetItem(i), pivot) >= 0)) and
  742. (i < aRight) do inc(i);
  743. while ((aDirection = sdAscending) and (aComparer.Compare(GetItem(j), pivot) >= 0) or
  744. (aDirection = sdDescending) and (aComparer.Compare(GetItem(j), pivot) <= 0)) and
  745. (j > aLeft) do dec(j);
  746. if (i < j) then
  747. Exchange(i, j);
  748. until (i >= j);
  749. if ((aDirection = sdAscending) and (aComparer.Compare(GetItem(i), pivot) > 0)) or
  750. ((aDirection = sdDescending) and (aComparer.Compare(GetItem(i), pivot) < 0)) then
  751. Exchange(i, aRight);
  752. result := i;
  753. end;
  754. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  755. procedure TutlSimpleList.QuickSort(aComparer: IComparer; const aDirection: TSortDirection; const aLeft, aRight: Integer);
  756. var
  757. s: Integer;
  758. begin
  759. if (aLeft < aRight) then begin
  760. s := Split(aComparer, aDirection, aLeft, aRight);
  761. QuickSort(aComparer, aDirection, aLeft, s - 1);
  762. QuickSort(aComparer, aDirection, s + 1, aRight);
  763. end;
  764. end;
  765. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  766. function TutlSimpleList.Add(const aItem: T): Integer;
  767. begin
  768. result := Count;
  769. InsertIntern(result, aItem);
  770. end;
  771. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  772. procedure TutlSimpleList.Insert(const aIndex: Integer; const aItem: T);
  773. begin
  774. InsertIntern(aIndex, aItem);
  775. end;
  776. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  777. procedure TutlSimpleList.Exchange(const aIndex1, aIndex2: Integer);
  778. begin
  779. if (aIndex1 < 0) or (aIndex1 >= Count) then
  780. raise EOutOfRange.Create(aIndex1, 0, Count-1);
  781. if (aIndex2 < 0) or (aIndex2 >= Count) then
  782. raise EOutOfRange.Create(aIndex2, 0, Count-1);
  783. fList.Exchange(aIndex1, aIndex2);
  784. end;
  785. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  786. procedure TutlSimpleList.Move(const aCurIndex, aNewIndex: Integer);
  787. begin
  788. if (aCurIndex < 0) or (aCurIndex >= Count) then
  789. raise EOutOfRange.Create(aCurIndex, 0, Count-1);
  790. if (aNewIndex < 0) or (aNewIndex >= Count) then
  791. raise EOutOfRange.Create(aNewIndex, 0, Count-1);
  792. fList.Move(aCurIndex, aNewIndex);
  793. end;
  794. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  795. procedure TutlSimpleList.Sort(aComparer: IComparer; const aDirection: TSortDirection);
  796. begin
  797. QuickSort(aComparer, aDirection, 0, fList.Count-1);
  798. end;
  799. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  800. procedure TutlSimpleList.Delete(const aIndex: Integer);
  801. begin
  802. DeleteIntern(aIndex);
  803. end;
  804. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  805. function TutlSimpleList.First: T;
  806. begin
  807. result := Items[0];
  808. end;
  809. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  810. procedure TutlSimpleList.PushFirst(const aItem: T);
  811. begin
  812. InsertIntern(0, aItem);
  813. end;
  814. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  815. function TutlSimpleList.PopFirst(const aFreeItem: Boolean): T;
  816. begin
  817. if aFreeItem then
  818. FillByte(result{%H-}, SizeOf(result), 0)
  819. else
  820. result := First;
  821. DeleteIntern(0, aFreeItem);
  822. end;
  823. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  824. function TutlSimpleList.Last: T;
  825. begin
  826. result := Items[Count-1];
  827. end;
  828. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  829. procedure TutlSimpleList.PushLast(const aItem: T);
  830. begin
  831. InsertIntern(Count, aItem);
  832. end;
  833. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  834. function TutlSimpleList.PopLast(const aFreeItem: Boolean): T;
  835. begin
  836. if aFreeItem then
  837. FillByte(result{%H-}, SizeOf(result), 0)
  838. else
  839. result := Last;
  840. DeleteIntern(Count-1, aFreeItem);
  841. end;
  842. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  843. //TutlCustomList////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  844. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  845. function TutlCustomList.IndexOf(const aItem: T): Integer;
  846. var
  847. c: Integer;
  848. begin
  849. c := List.Count;
  850. result := 0;
  851. while (result < c) and
  852. not fEqualityComparer.EqualityCompare(PListItem(List[result])^.data, aItem) do
  853. inc(result);
  854. if (result >= c) then
  855. result := -1;
  856. end;
  857. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  858. function TutlCustomList.Extract(const aItem: T; const aDefault: T): T;
  859. var
  860. i: Integer;
  861. begin
  862. i := IndexOf(aItem);
  863. if (i >= 0) then begin
  864. result := Items[i];
  865. DeleteIntern(i, false);
  866. end else
  867. result := aDefault;
  868. end;
  869. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  870. function TutlCustomList.Remove(const aItem: T): Integer;
  871. begin
  872. result := IndexOf(aItem);
  873. if (result >= 0) then
  874. DeleteIntern(result);
  875. end;
  876. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  877. constructor TutlCustomList.Create(aEqualityComparer: IEqualityComparer; const aOwnsObjects: Boolean);
  878. begin
  879. inherited Create(aOwnsObjects);
  880. fEqualityComparer := aEqualityComparer;
  881. end;
  882. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  883. destructor TutlCustomList.Destroy;
  884. begin
  885. fEqualityComparer := nil;
  886. inherited Destroy;
  887. end;
  888. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  889. //TutlList//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  890. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  891. constructor TutlList.Create(const aOwnsObjects: Boolean);
  892. begin
  893. inherited Create(TEqualityComparer.Create, aOwnsObjects);
  894. end;
  895. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  896. //TutlCustomHashSet/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  897. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  898. function TutlCustomHashSet.SearchItem(const aMin, aMax: Integer; const aItem: T; out aIndex: Integer): Integer;
  899. var
  900. i, cmp: Integer;
  901. begin
  902. if (aMin <= aMax) then begin
  903. i := aMin + Trunc((aMax - aMin) / 2);
  904. cmp := fComparer.Compare(aItem, GetItem(i));
  905. if (cmp = 0) then
  906. result := i
  907. else if (cmp < 0) then
  908. result := SearchItem(aMin, i-1, aItem, aIndex)
  909. else if (cmp > 0) then
  910. result := SearchItem(i+1, aMax, aItem, aIndex);
  911. end else begin
  912. result := -1;
  913. aIndex := aMin;
  914. end;
  915. end;
  916. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  917. function TutlCustomHashSet.Add(const aItem: T): Boolean;
  918. var
  919. i: Integer;
  920. begin
  921. result := (SearchItem(0, List.Count-1, aItem, i) < 0);
  922. if result then
  923. InsertIntern(i, aItem);
  924. end;
  925. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  926. function TutlCustomHashSet.Contains(const aItem: T): Boolean;
  927. var
  928. tmp: Integer;
  929. begin
  930. result := (SearchItem(0, List.Count-1, aItem, tmp) >= 0);
  931. end;
  932. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  933. function TutlCustomHashSet.IndexOf(const aItem: T): Integer;
  934. var
  935. tmp: Integer;
  936. begin
  937. result := SearchItem(0, List.Count-1, aItem, tmp);
  938. end;
  939. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  940. function TutlCustomHashSet.Remove(const aItem: T): Boolean;
  941. var
  942. i, tmp: Integer;
  943. begin
  944. i := SearchItem(0, List.Count-1, aItem, tmp);
  945. result := (i >= 0);
  946. if result then
  947. DeleteIntern(i);
  948. end;
  949. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  950. procedure TutlCustomHashSet.Delete(const aIndex: Integer);
  951. begin
  952. DeleteIntern(aIndex);
  953. end;
  954. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  955. constructor TutlCustomHashSet.Create(aComparer: IComparer; const aOwnsObjects: Boolean);
  956. begin
  957. inherited Create(aOwnsObjects);
  958. fComparer := aComparer;
  959. end;
  960. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  961. destructor TutlCustomHashSet.Destroy;
  962. begin
  963. fComparer := nil;
  964. inherited Destroy;
  965. end;
  966. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  967. //TutlHashSet///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  968. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  969. constructor TutlHashSet.Create(const aOwnsObjects: Boolean);
  970. begin
  971. inherited Create(TComparer.Create, aOwnsObjects);
  972. end;
  973. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  974. //TutlCustomMap.THashSet////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  975. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  976. procedure TutlCustomMap.THashSet.DestroyItem(const aItem: PListItem; const aFreeItem: Boolean);
  977. begin
  978. // never free objects used as keys, but do finalize strings, interfaces etc.
  979. utlFreeOrFinalize(aItem^.data.key, TypeInfo(aItem^.data.key), false);
  980. utlFreeOrFinalize(aItem^.data.value, TypeInfo(aItem^.data.value), aFreeItem and OwnsObjects);
  981. inherited DestroyItem(aItem, aFreeItem);
  982. end;
  983. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  984. //TutlCustomMap.TKVPComparer////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  985. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  986. function TutlCustomMap.TKVPComparer.Compare(const i1, i2: TKeyValuePair): Integer;
  987. begin
  988. result := fComparer.Compare(i1.Key, i2.Key);
  989. end;
  990. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  991. constructor TutlCustomMap.TKVPComparer.Create(aComparer: IComparer);
  992. begin
  993. inherited Create;
  994. fComparer := aComparer;
  995. end;
  996. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  997. destructor TutlCustomMap.TKVPComparer.Destroy;
  998. begin
  999. fComparer := nil;
  1000. inherited Destroy;
  1001. end;
  1002. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1003. //TutlCustomMap.TValueEnumerator////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1004. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1005. function TutlCustomMap.TValueEnumerator.GetCurrent: TValue;
  1006. begin
  1007. result := fHashSet[fPos].Value;
  1008. end;
  1009. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1010. function TutlCustomMap.TValueEnumerator.MoveNext: Boolean;
  1011. begin
  1012. inc(fPos);
  1013. result := (fPos < fHashSet.Count);
  1014. end;
  1015. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1016. constructor TutlCustomMap.TValueEnumerator.Create(const aHashSet: THashSet);
  1017. begin
  1018. inherited Create;
  1019. fHashSet := aHashSet;
  1020. fPos := -1;
  1021. end;
  1022. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1023. //TutlCustomMap.TKeyEnumerator//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1024. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1025. function TutlCustomMap.TKeyEnumerator.GetCurrent: TKey;
  1026. begin
  1027. result := fHashSet[fPos].Key;
  1028. end;
  1029. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1030. function TutlCustomMap.TKeyEnumerator.MoveNext: Boolean;
  1031. begin
  1032. inc(fPos);
  1033. result := (fPos < fHashSet.Count);
  1034. end;
  1035. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1036. constructor TutlCustomMap.TKeyEnumerator.Create(const aHashSet: THashSet);
  1037. begin
  1038. inherited Create;
  1039. fHashSet := aHashSet;
  1040. fPos := -1;
  1041. end;
  1042. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1043. //TutlCustomMap.TKeyValuePairEnumerator/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1044. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1045. function TutlCustomMap.TKeyValuePairEnumerator.GetCurrent: TKeyValuePair;
  1046. begin
  1047. result := fHashSet[fPos];
  1048. end;
  1049. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1050. function TutlCustomMap.TKeyValuePairEnumerator.MoveNext: Boolean;
  1051. begin
  1052. inc(fPos);
  1053. result := (fPos < fHashSet.Count);
  1054. end;
  1055. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1056. constructor TutlCustomMap.TKeyValuePairEnumerator.Create(const aHashSet: THashSet);
  1057. begin
  1058. inherited Create;
  1059. fHashSet := aHashSet;
  1060. fPos := -1;
  1061. end;
  1062. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1063. //TutlCustomMap.TKeyWrapper/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1064. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1065. function TutlCustomMap.TKeyWrapper.GetItem(const aIndex: Integer): TKey;
  1066. begin
  1067. result := fHashSet[aIndex].Key;
  1068. end;
  1069. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1070. function TutlCustomMap.TKeyWrapper.GetCount: Integer;
  1071. begin
  1072. result := fHashSet.Count;
  1073. end;
  1074. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1075. function TutlCustomMap.TKeyWrapper.GetEnumerator: TKeyEnumerator;
  1076. begin
  1077. result := TKeyEnumerator.Create(fHashSet);
  1078. end;
  1079. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1080. constructor TutlCustomMap.TKeyWrapper.Create(const aHashSet: THashSet);
  1081. begin
  1082. inherited Create;
  1083. fHashSet := aHashSet;
  1084. end;
  1085. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1086. //TutlCustomMap.TKeyValuePairWrapper////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1087. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1088. function TutlCustomMap.TKeyValuePairWrapper.GetItem(const aIndex: Integer): TKeyValuePair;
  1089. begin
  1090. result := fHashSet[aIndex];
  1091. end;
  1092. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1093. function TutlCustomMap.TKeyValuePairWrapper.GetCount: Integer;
  1094. begin
  1095. result := fHashSet.Count;
  1096. end;
  1097. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1098. function TutlCustomMap.TKeyValuePairWrapper.GetEnumerator: TKeyValuePairEnumerator;
  1099. begin
  1100. result := TKeyValuePairEnumerator.Create(fHashSet);
  1101. end;
  1102. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1103. constructor TutlCustomMap.TKeyValuePairWrapper.Create(const aHashSet: THashSet);
  1104. begin
  1105. inherited Create;
  1106. fHashSet := aHashSet;
  1107. end;
  1108. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1109. //TutlCustomMap/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1110. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1111. function TutlCustomMap.GetValues(const aKey: TKey): TValue;
  1112. var
  1113. i: Integer;
  1114. kvp: TKeyValuePair;
  1115. begin
  1116. kvp.Key := aKey;
  1117. i := fHashSet.IndexOf(kvp);
  1118. if (i < 0) then
  1119. FillByte(result{%H-}, SizeOf(result), 0)
  1120. else
  1121. result := fHashSet[i].Value;
  1122. end;
  1123. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1124. function TutlCustomMap.GetValueAt(const aIndex: Integer): TValue;
  1125. begin
  1126. result := fHashSet[aIndex].Value;
  1127. end;
  1128. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1129. function TutlCustomMap.GetCount: Integer;
  1130. begin
  1131. result := fHashSet.Count;
  1132. end;
  1133. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1134. procedure TutlCustomMap.SetValues(const aKey: TKey; aValue: TValue);
  1135. var
  1136. i: Integer;
  1137. kvp: TKeyValuePair;
  1138. begin
  1139. kvp.Key := aKey;
  1140. kvp.Value := aValue;
  1141. i := fHashSet.IndexOf(kvp);
  1142. if (i < 0) then
  1143. raise EutlMap.Create('key not found');
  1144. fHashSet[i] := kvp;
  1145. end;
  1146. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1147. procedure TutlCustomMap.SetValueAt(const aIndex: Integer; aValue: TValue);
  1148. var
  1149. kvp: TKeyValuePair;
  1150. begin
  1151. kvp := fHashSet[aIndex];
  1152. kvp.Value := aValue;
  1153. fHashSet[aIndex] := kvp;
  1154. end;
  1155. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1156. procedure TutlCustomMap.Add(const aKey: TKey; const aValue: TValue);
  1157. var
  1158. kvp: TKeyValuePair;
  1159. begin
  1160. kvp.Key := aKey;
  1161. kvp.Value := aValue;
  1162. if not fHashSet.Add(kvp) then
  1163. raise EutlMap.Create('key is already in list');
  1164. end;
  1165. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1166. function TutlCustomMap.IndexOf(const aKey: TKey): Integer;
  1167. var
  1168. kvp: TKeyValuePair;
  1169. begin
  1170. kvp.Key := aKey;
  1171. result := fHashSet.IndexOf(kvp);
  1172. end;
  1173. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1174. function TutlCustomMap.Contains(const aKey: TKey): Boolean;
  1175. var
  1176. kvp: TKeyValuePair;
  1177. begin
  1178. kvp.Key := aKey;
  1179. result := (fHashSet.IndexOf(kvp) >= 0);
  1180. end;
  1181. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1182. procedure TutlCustomMap.Delete(const aKey: TKey);
  1183. var
  1184. kvp: TKeyValuePair;
  1185. begin
  1186. kvp.Key := aKey;
  1187. if not fHashSet.Remove(kvp) then
  1188. raise EutlMap.Create('key not found');
  1189. end;
  1190. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1191. procedure TutlCustomMap.DeleteAt(const aIndex: Integer);
  1192. begin
  1193. fHashSet.Delete(aIndex);
  1194. end;
  1195. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1196. procedure TutlCustomMap.Clear;
  1197. begin
  1198. fHashSet.Clear;
  1199. end;
  1200. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1201. function TutlCustomMap.GetEnumerator: TValueEnumerator;
  1202. begin
  1203. result := TValueEnumerator.Create(fHashSet);
  1204. end;
  1205. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1206. constructor TutlCustomMap.Create(aComparer: IComparer; const aOwnsObjects: Boolean);
  1207. begin
  1208. inherited Create;
  1209. fComparer := aComparer;
  1210. fHashSet := THashSet.Create(TKVPComparer.Create(fComparer), aOwnsObjects);
  1211. fKeyWrapper := TKeyWrapper.Create(fHashSet);
  1212. fKeyValuePairWrapper := TKeyValuePairWrapper.Create(fHashSet);
  1213. end;
  1214. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1215. destructor TutlCustomMap.Destroy;
  1216. begin
  1217. FreeAndNil(fKeyValuePairWrapper);
  1218. FreeAndNil(fKeyWrapper);
  1219. FreeAndNil(fHashSet);
  1220. fComparer := nil;
  1221. inherited Destroy;
  1222. end;
  1223. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1224. //TutlMap///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1225. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1226. constructor TutlMap.Create(const aOwnsObjects: Boolean);
  1227. begin
  1228. inherited Create(TComparer.Create, aOwnsObjects);
  1229. end;
  1230. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1231. //TutlQueue/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1232. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1233. function TutlQueue.GetCount: Integer;
  1234. begin
  1235. InterLockedExchange(result{%H-}, fCount);
  1236. end;
  1237. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1238. procedure TutlQueue.Push(const aItem: T);
  1239. var
  1240. p: PListItem;
  1241. begin
  1242. new(p);
  1243. p^.data := aItem;
  1244. p^.next := nil;
  1245. fLast^.next := p;
  1246. fLast := fLast^.next;
  1247. InterLockedIncrement(fCount);
  1248. end;
  1249. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1250. function TutlQueue.Pop(out aItem: T): Boolean;
  1251. var
  1252. old: PListItem;
  1253. begin
  1254. result := false;
  1255. FillByte(aItem{%H-}, SizeOf(aItem), 0);
  1256. if (Count <= 0) then
  1257. exit;
  1258. result := true;
  1259. old := fFirst;
  1260. fFirst := fFirst^.next;
  1261. aItem := fFirst^.data;
  1262. InterLockedDecrement(fCount);
  1263. Dispose(old);
  1264. end;
  1265. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1266. function TutlQueue.Pop: Boolean;
  1267. var
  1268. tmp: T;
  1269. begin
  1270. result := Pop(tmp);
  1271. utlFreeOrFinalize(tmp, TypeInfo(tmp), fOwnsObjects);
  1272. end;
  1273. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1274. procedure TutlQueue.Clear;
  1275. begin
  1276. while Pop do;
  1277. end;
  1278. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1279. constructor TutlQueue.Create(const aOwnsObjects: Boolean);
  1280. begin
  1281. inherited Create;
  1282. new(fFirst);
  1283. FillByte(fFirst^, SizeOf(fFirst^), 0);
  1284. fLast := fFirst;
  1285. fCount := 0;
  1286. fOwnsObjects := aOwnsObjects;
  1287. end;
  1288. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1289. destructor TutlQueue.Destroy;
  1290. begin
  1291. Clear;
  1292. if Assigned(fLast) then begin
  1293. Dispose(fLast);
  1294. fLast := nil;
  1295. end;
  1296. inherited Destroy;
  1297. end;
  1298. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1299. //TutlSyncQueue/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1300. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1301. procedure TutlSyncQueue.Push(const aItem: T);
  1302. begin
  1303. fPushLock.Enter;
  1304. try
  1305. inherited Push(aItem);
  1306. finally
  1307. fPushLock.Leave;
  1308. end;
  1309. end;
  1310. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1311. function TutlSyncQueue.Pop(out aItem: T): Boolean;
  1312. begin
  1313. fPopLock.Enter;
  1314. try
  1315. result := inherited Pop(aItem);
  1316. finally
  1317. fPopLock.Leave;
  1318. end;
  1319. end;
  1320. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1321. constructor TutlSyncQueue.Create(const aOwnsObjects: Boolean);
  1322. begin
  1323. inherited Create(aOwnsObjects);
  1324. fPushLock := TutlSpinLock.Create;
  1325. fPopLock := TutlSpinLock.Create;
  1326. end;
  1327. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1328. destructor TutlSyncQueue.Destroy;
  1329. begin
  1330. inherited Destroy; //inherited will pop all remaining items, so do not destroy spinlock before!
  1331. FreeAndNil(fPushLock);
  1332. FreeAndNil(fPopLock);
  1333. end;
  1334. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1335. //TutlInterfaceList.TInterfaceEnumerator////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1336. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1337. function TutlInterfaceList.TInterfaceEnumerator.GetCurrent: T;
  1338. begin
  1339. result := T(fList[fPos]);
  1340. end;
  1341. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1342. function TutlInterfaceList.TInterfaceEnumerator.MoveNext: Boolean;
  1343. begin
  1344. inc(fPos);
  1345. result := (fPos < fList.Count);
  1346. end;
  1347. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1348. constructor TutlInterfaceList.TInterfaceEnumerator.Create(const aList: TInterfaceList);
  1349. begin
  1350. inherited Create;
  1351. fPos := -1;
  1352. fList := aList;
  1353. end;
  1354. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1355. //TutlInterfaceList/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1356. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1357. function TutlInterfaceList.Get(i : Integer): T;
  1358. begin
  1359. result := T(inherited Get(i));
  1360. end;
  1361. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1362. procedure TutlInterfaceList.Put(i : Integer; aItem : T);
  1363. begin
  1364. inherited Put(i, aItem);
  1365. end;
  1366. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1367. function TutlInterfaceList.First: T;
  1368. begin
  1369. result := T(inherited First);
  1370. end;
  1371. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1372. function TutlInterfaceList.IndexOf(aItem : T): Integer;
  1373. begin
  1374. result := inherited IndexOf(aItem);
  1375. end;
  1376. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1377. function TutlInterfaceList.Add(aItem : IUnknown): Integer;
  1378. begin
  1379. result := inherited Add(aItem);
  1380. end;
  1381. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1382. procedure TutlInterfaceList.Insert(i : Integer; aItem : T);
  1383. begin
  1384. inherited Insert(i, aItem);
  1385. end;
  1386. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1387. function TutlInterfaceList.Last : T;
  1388. begin
  1389. result := T(inherited Last);
  1390. end;
  1391. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1392. function TutlInterfaceList.Remove(aItem : T): Integer;
  1393. begin
  1394. result := inherited Remove(aItem);
  1395. end;
  1396. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1397. function TutlInterfaceList.GetEnumerator: TInterfaceEnumerator;
  1398. begin
  1399. result := TInterfaceEnumerator.Create(self);
  1400. end;
  1401. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1402. //TutlEnumHelper////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1403. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1404. class function TutlEnumHelper.ToString(aValue: T): String;
  1405. Var
  1406. PS: PShortString;
  1407. TI: PTypeInfo;
  1408. PT: PTypeData;
  1409. num: Integer;
  1410. begin
  1411. TI := TypeInfo(T);
  1412. PT := GetTypeData(TI);
  1413. if TI^.Kind = tkBool then begin
  1414. case Integer(aValue) of
  1415. 0,1:
  1416. Result:=BooleanIdents[Boolean(aValue)];
  1417. else
  1418. Result:='';
  1419. end;
  1420. end else begin
  1421. num := Integer(aValue);
  1422. if (num >= PT^.MinValue) and (num <= PT^.MaxValue) then begin
  1423. PS := @PT^.NameList;
  1424. dec(num, PT^.MinValue);
  1425. while num > 0 do begin
  1426. PS := PShortString(pointer(PS) + PByte(PS)^ + 1);
  1427. Dec(Num);
  1428. end;
  1429. Result := PS^;
  1430. end else
  1431. Result := '';
  1432. end;
  1433. end;
  1434. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1435. class function TutlEnumHelper.TryToEnum(aStr: String; out aValue: T): Boolean;
  1436. Var
  1437. PS: PShortString;
  1438. PT: PTypeData;
  1439. Count: longint;
  1440. sName: shortstring;
  1441. TI: PTypeInfo;
  1442. begin
  1443. TI := TypeInfo(T);
  1444. PT := GetTypeData(TI);
  1445. Result := False;
  1446. if Length(aStr) = 0 then
  1447. exit;
  1448. sName := aStr;
  1449. if TI^.Kind = tkBool then begin
  1450. If CompareText(BooleanIdents[false], aStr) = 0 then
  1451. aValue := T(0)
  1452. else if CompareText(BooleanIdents[true], aStr) = 0 then
  1453. aValue := T(1);
  1454. Result := true;
  1455. end else begin
  1456. PS := @PT^.NameList;
  1457. Count := 0;
  1458. While (PByte(PS)^ <> 0) do begin
  1459. If ShortCompareText(PS^, sName) = 0 then begin
  1460. aValue := T(Count + PT^.MinValue);
  1461. exit(true);
  1462. end;
  1463. PS := PShortString(pointer(PS) + PByte(PS)^ + 1);
  1464. Inc(Count);
  1465. end;
  1466. end;
  1467. end;
  1468. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1469. class function TutlEnumHelper.ToEnum(aStr: String): T;
  1470. begin
  1471. if not TryToEnum(aStr, result) then
  1472. raise EConvertError.CreateFmt('"%s" is an invalid %s',[aStr, PTypeInfo(TypeInfo(T))^.Name]);
  1473. end;
  1474. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1475. class function TutlEnumHelper.ToEnum(aStr: String; const aDefault: T): T;
  1476. begin
  1477. if not TryToEnum(aStr, result) then
  1478. result := aDefault;
  1479. end;
  1480. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1481. class function TutlEnumHelper.Values: TValueArray;
  1482. Var
  1483. TI: PTypeInfo;
  1484. PT: PTypeData;
  1485. i,j: integer;
  1486. begin
  1487. TI := TypeInfo(T);
  1488. PT := GetTypeData(TI);
  1489. if TI^.Kind = tkBool then begin
  1490. SetLength(Result, 2);
  1491. Result[0]:= T(true);
  1492. Result[1]:= T(false);
  1493. end else begin
  1494. SetLength(Result, PT^.MaxValue - PT^.MinValue + 1);
  1495. j:= 0;
  1496. for i:= PT^.MinValue to PT^.MaxValue do begin
  1497. Result[j]:= T(i);
  1498. inc(j);
  1499. end;
  1500. end;
  1501. end;
  1502. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1503. //TutlRingBuffer////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1504. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1505. constructor TutlRingBuffer.Create(const Elements: Integer);
  1506. begin
  1507. inherited Create;
  1508. fAborted:= false;
  1509. fDataLen:= Elements;
  1510. fDataSize:= SizeOf(T);
  1511. SetLength(fData, fDataLen);
  1512. fWritePtr:= 1;
  1513. fReadPtr:= 0;
  1514. fFillState:= 0;
  1515. fReadEvent:= TutlAutoResetEvent.Create;
  1516. fWrittenEvent:= TutlAutoResetEvent.Create;
  1517. end;
  1518. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1519. destructor TutlRingBuffer.Destroy;
  1520. begin
  1521. BreakPipe;
  1522. FreeAndNil(fReadEvent);
  1523. FreeAndNil(fWrittenEvent);
  1524. SetLength(fData, 0);
  1525. inherited Destroy;
  1526. end;
  1527. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1528. function TutlRingBuffer.Read(Buf: Pointer; Items: integer; BlockUntilAvail: boolean): integer;
  1529. var
  1530. wp, c, r: Integer;
  1531. begin
  1532. Result:= 0;
  1533. while Items > 0 do begin
  1534. if fAborted then
  1535. exit;
  1536. InterLockedExchange(wp{%H-}, fWritePtr);
  1537. r:= (fReadPtr + 1) mod fDataLen;
  1538. if wp < r then
  1539. wp:= fDataLen;
  1540. c:= wp - r;
  1541. if c > Items then
  1542. c:= Items;
  1543. if c > 0 then begin
  1544. Move(fData[r], Buf^, c * fDataSize);
  1545. Dec(Items, c);
  1546. inc(Result, c);
  1547. dec(fFillState, c);
  1548. inc(PByte(Buf), c * fDataSize);
  1549. InterLockedExchange(fReadPtr, (fReadPtr + c) mod fDataLen);
  1550. fReadEvent.SetEvent;
  1551. end else begin
  1552. if not BlockUntilAvail then
  1553. break;
  1554. fWrittenEvent.WaitFor(INFINITE);
  1555. end;
  1556. end;
  1557. end;
  1558. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1559. function TutlRingBuffer.Write(Buf: Pointer; Items: integer; BlockUntilDone: boolean): integer;
  1560. var
  1561. rp, c: integer;
  1562. begin
  1563. Result:= 0;
  1564. while Items > 0 do begin
  1565. if fAborted then
  1566. exit;
  1567. InterLockedExchange(rp{%H-}, fReadPtr);
  1568. if rp < fWritePtr then
  1569. rp:= fDataLen;
  1570. c:= rp - fWritePtr;
  1571. if c > Items then
  1572. c:= Items;
  1573. if c > 0 then begin
  1574. Move(Buf^, fData[fWritePtr], c * fDataSize);
  1575. dec(Items, c);
  1576. inc(Result, c);
  1577. inc(fFillState, c);
  1578. inc(PByte(Buf), c * fDataSize);
  1579. InterLockedExchange(fWritePtr, (fWritePtr + c) mod fDataLen);
  1580. fWrittenEvent.SetEvent;
  1581. end else begin
  1582. if not BlockUntilDone then
  1583. Break;
  1584. fReadEvent.WaitFor(INFINITE);
  1585. end;
  1586. end;
  1587. end;
  1588. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1589. procedure TutlRingBuffer.BreakPipe;
  1590. begin
  1591. fAborted:= true;
  1592. fWrittenEvent.SetEvent;
  1593. fReadEvent.SetEvent;
  1594. end;
  1595. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1596. //TutlPagedDataFiFo.TDataProvider///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1597. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1598. function TutlPagedDataFiFo.TDataProvider.Give(const aBuffer: PData; aCount: Integer): Integer;
  1599. begin
  1600. result := 0;
  1601. if (aCount > fCount - fPos) then
  1602. aCount := fCount - fPos;
  1603. if (aCount <= 0) then
  1604. exit;
  1605. Move((fData + fPos)^, aBuffer^, aCount * SizeOf(TData));
  1606. inc(fPos, aCount);
  1607. result := aCount;
  1608. end;
  1609. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1610. constructor TutlPagedDataFiFo.TDataProvider.Create(const aData: PData; const aCount: Integer);
  1611. begin
  1612. inherited Create;
  1613. fData := aData;
  1614. fCount := aCount;
  1615. fPos := 0;
  1616. end;
  1617. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1618. //TutlPagedDataFiFo.TDataConsumer///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1619. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1620. function TutlPagedDataFiFo.TDataConsumer.Take(const aBuffer: PData; aCount: Integer): Integer;
  1621. begin
  1622. result := 0;
  1623. if (aCount > fCount - fPos) then
  1624. aCount := fCount - fPos;
  1625. if (aCount <= 0) then
  1626. exit;
  1627. Move(aBuffer^, (fData + fPos)^, aCount * SizeOf(TData));
  1628. inc(fPos, aCount);
  1629. result := aCount;
  1630. end;
  1631. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1632. constructor TutlPagedDataFiFo.TDataConsumer.Create(const aData: PData; const aCount: Integer);
  1633. begin
  1634. inherited Create;
  1635. fData := aData;
  1636. fCount := aCount;
  1637. fPos := 0;
  1638. end;
  1639. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1640. //TutlPagedDataFiFo.TNestedDataProvider/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1641. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1642. function TutlPagedDataFiFo.TNestedDataProvider.Give(const aBuffer: PData; aCount: Integer): Integer;
  1643. begin
  1644. result := fCallback(aBuffer, aCount);
  1645. end;
  1646. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1647. constructor TutlPagedDataFiFo.TNestedDataProvider.Create(const aCallback: TDataCallback);
  1648. begin
  1649. inherited Create;
  1650. fCallback := aCallback;
  1651. end;
  1652. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1653. //TutlPagedDataFiFo.TNestedDataConsumer/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1654. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1655. function TutlPagedDataFiFo.TNestedDataConsumer.Take(const aBuffer: PData; aCount: Integer): Integer;
  1656. begin
  1657. result := fCallback(aBuffer, aCount);
  1658. end;
  1659. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1660. constructor TutlPagedDataFiFo.TNestedDataConsumer.Create(const aCallback: TDataCallback);
  1661. begin
  1662. inherited Create;
  1663. fCallback := aCallback;
  1664. end;
  1665. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1666. //TutlPagedDataFiFo.TStreamDataProvider/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1667. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1668. function TutlPagedDataFiFo.TStreamDataProvider.Give(const aBuffer: PData; aCount: Integer): Integer;
  1669. begin
  1670. result := fStream.Read(aBuffer^, aCount);
  1671. end;
  1672. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1673. constructor TutlPagedDataFiFo.TStreamDataProvider.Create(const aStream: TStream);
  1674. begin
  1675. inherited Create;
  1676. fStream := aStream;
  1677. end;
  1678. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1679. //TutlPagedDataFiFo.TStreamDataConsumer/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1680. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1681. function TutlPagedDataFiFo.TStreamDataConsumer.Take(const aBuffer: PData; aCount: Integer): Integer;
  1682. begin
  1683. result := fStream.Write(aBuffer^, aCount);
  1684. end;
  1685. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1686. constructor TutlPagedDataFiFo.TStreamDataConsumer.Create(const aStream: TStream);
  1687. begin
  1688. inherited Create;
  1689. fStream := aStream;
  1690. end;
  1691. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1692. //TutlPagedDataFiFo/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1693. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1694. function TutlPagedDataFiFo.WriteIntern(const aProvider: IDataProvider; aCount: Integer): Integer;
  1695. var
  1696. c, r: Integer;
  1697. p: PPage;
  1698. begin
  1699. if not Assigned(aProvider) then
  1700. raise EArgumentNil.Create('aProvider');
  1701. result := 0;
  1702. while (aCount > 0) do begin
  1703. if not Assigned(fWritePage) or (fWritePage^.WritePos >= fPageSize) then begin
  1704. new(p);
  1705. p^.ReadPos := 0;
  1706. p^.WritePos := 0;
  1707. p^.Next := nil;
  1708. SetLength(p^.Data, fPageSize);
  1709. if Assigned(fWritePage) then
  1710. fWritePage^.Next := p;
  1711. fWritePage := p;
  1712. if not Assigned(fReadPage) then
  1713. fReadPage := fWritePage;
  1714. end;
  1715. c := fPageSize - fWritePage^.WritePos;
  1716. if (c > aCount) then
  1717. c := aCount;
  1718. r := aProvider.Give(@fWritePage^.Data[fWritePage^.WritePos], c);
  1719. if (r = 0) then
  1720. exit;
  1721. inc(result, r);
  1722. inc(fWritePage^.WritePos, r);
  1723. inc(fSize, r);
  1724. dec(aCount, r);
  1725. end;
  1726. end;
  1727. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1728. function TutlPagedDataFiFo.ReadIntern(const aConsumer: IDataConsumer; aCount: Integer; const aMoveReadPos: Boolean): Integer;
  1729. var
  1730. ReadPage: PPage;
  1731. DummyPage: TPage;
  1732. c, r: Integer;
  1733. begin
  1734. result := 0;
  1735. if not Assigned(fReadPage) then
  1736. exit;
  1737. //init read page
  1738. if not aMoveReadPos then begin
  1739. DummyPage := fReadPage^; // copy page (data is not copied, because it's a dynamic array)
  1740. ReadPage := @DummyPage;
  1741. end else
  1742. ReadPage := fReadPage;
  1743. while (aCount > 0) do begin
  1744. if (ReadPage^.ReadPos >= fPageSize) then begin
  1745. if not Assigned(ReadPage^.Next) then
  1746. exit;
  1747. if aMoveReadPos then begin
  1748. if (fReadPage = fWritePage) then // write finished with page end, so reset WritePage wenn disposing ReadPage
  1749. fWritePage := nil;
  1750. fReadPage := fReadPage^.Next;
  1751. Dispose(ReadPage);
  1752. ReadPage := fReadPage;
  1753. end else
  1754. ReadPage^ := ReadPage^.Next^;
  1755. end;
  1756. c := ReadPage^.WritePos - ReadPage^.ReadPos;
  1757. if (c = 0) then
  1758. exit;
  1759. if (c > aCount) then
  1760. c := aCount;
  1761. if Assigned(aConsumer) then begin
  1762. r := aConsumer.Take(@ReadPage^.Data[ReadPage^.ReadPos], c);
  1763. if (r = 0) then
  1764. exit;
  1765. end else
  1766. r := c;
  1767. inc(result, r);
  1768. inc(ReadPage^.ReadPos, r);
  1769. dec(aCount, r);
  1770. if aMoveReadPos then
  1771. dec(fSize, r);
  1772. end;
  1773. end;
  1774. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1775. function TutlPagedDataFiFo.Write(const aProvider: IDataProvider; const aCount: Integer): Integer;
  1776. begin
  1777. result := WriteIntern(aProvider, aCount);
  1778. end;
  1779. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1780. function TutlPagedDataFiFo.Write(const aData: PData; const aCount: Integer): Integer;
  1781. var
  1782. provider: IDataProvider;
  1783. begin
  1784. provider := TDataProvider.Create(aData, aCount);
  1785. result := WriteIntern(provider, aCount);
  1786. end;
  1787. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1788. function TutlPagedDataFiFo.Read(const aConsumer: IDataConsumer; const aCount: Integer): Integer;
  1789. begin
  1790. result := ReadIntern(aConsumer, aCount, true);
  1791. end;
  1792. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1793. function TutlPagedDataFiFo.Read(const aData: PData; const aCount: Integer): Integer;
  1794. var
  1795. consumer: IDataConsumer;
  1796. begin
  1797. consumer := TDataConsumer.Create(aData, aCount);
  1798. result := ReadIntern(consumer, aCount, true);
  1799. end;
  1800. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1801. function TutlPagedDataFiFo.Peek(const aConsumer: IDataConsumer; const aCount: Integer): Integer;
  1802. begin
  1803. result := ReadIntern(aConsumer, aCount, false);
  1804. end;
  1805. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1806. function TutlPagedDataFiFo.Peek(const aData: PData; const aCount: Integer): Integer;
  1807. var
  1808. consumer: IDataConsumer;
  1809. begin
  1810. consumer := TDataConsumer.Create(aData, aCount);
  1811. result := ReadIntern(consumer, aCount, false);
  1812. end;
  1813. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1814. function TutlPagedDataFiFo.Discard(const aCount: Integer): Integer;
  1815. begin
  1816. result := ReadIntern(nil, aCount, true);
  1817. end;
  1818. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1819. procedure TutlPagedDataFiFo.Clear;
  1820. var
  1821. tmp: PPage;
  1822. begin
  1823. while Assigned(fReadPage) do begin
  1824. tmp := fReadPage;
  1825. fReadPage := tmp^.Next;
  1826. Dispose(tmp);
  1827. end;
  1828. fReadPage := nil;
  1829. fWritePage := nil;
  1830. end;
  1831. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1832. constructor TutlPagedDataFiFo.Create(const aPageSize: Integer);
  1833. begin
  1834. inherited Create;
  1835. fReadPage := nil;
  1836. fWritePage := nil;
  1837. fPageSize := aPageSize;
  1838. end;
  1839. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1840. destructor TutlPagedDataFiFo.Destroy;
  1841. begin
  1842. Clear;
  1843. inherited Destroy;
  1844. end;
  1845. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1846. //TutlSyncPagedDataFiFo/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1847. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1848. function TutlSyncPagedDataFiFo.WriteIntern(const aProvider: IDataProvider; aCount: Integer): Integer;
  1849. begin
  1850. fLock.Enter;
  1851. try
  1852. result := inherited WriteIntern(aProvider, aCount);
  1853. finally
  1854. fLock.Leave;
  1855. end;
  1856. end;
  1857. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1858. function TutlSyncPagedDataFiFo.ReadIntern(const aConsumer: IDataConsumer; aCount: Integer; const aMoveReadPos: Boolean): Integer;
  1859. begin
  1860. fLock.Enter;
  1861. try
  1862. result := inherited ReadIntern(aConsumer, aCount, aMoveReadPos);
  1863. finally
  1864. fLock.Leave;
  1865. end;
  1866. end;
  1867. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1868. constructor TutlSyncPagedDataFiFo.Create(const aPageSize: Integer);
  1869. begin
  1870. inherited Create(aPageSize);
  1871. fLock := TutlSpinLock.Create;
  1872. end;
  1873. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1874. destructor TutlSyncPagedDataFiFo.Destroy;
  1875. begin
  1876. inherited Destroy;
  1877. FreeAndNil(fLock);
  1878. end;
  1879. end.