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.

2133 regels
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. utlFreeOrFinalize(aItem^.data.key, TypeInfo(aItem^.data.key), aFreeItem and OwnsObjects);
  979. utlFreeOrFinalize(aItem^.data.value, TypeInfo(aItem^.data.value), aFreeItem and OwnsObjects);
  980. inherited DestroyItem(aItem, aFreeItem);
  981. end;
  982. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  983. //TutlCustomMap.TKVPComparer////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  984. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  985. function TutlCustomMap.TKVPComparer.Compare(const i1, i2: TKeyValuePair): Integer;
  986. begin
  987. result := fComparer.Compare(i1.Key, i2.Key);
  988. end;
  989. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  990. constructor TutlCustomMap.TKVPComparer.Create(aComparer: IComparer);
  991. begin
  992. inherited Create;
  993. fComparer := aComparer;
  994. end;
  995. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  996. destructor TutlCustomMap.TKVPComparer.Destroy;
  997. begin
  998. fComparer := nil;
  999. inherited Destroy;
  1000. end;
  1001. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1002. //TutlCustomMap.TValueEnumerator////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1003. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1004. function TutlCustomMap.TValueEnumerator.GetCurrent: TValue;
  1005. begin
  1006. result := fHashSet[fPos].Value;
  1007. end;
  1008. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1009. function TutlCustomMap.TValueEnumerator.MoveNext: Boolean;
  1010. begin
  1011. inc(fPos);
  1012. result := (fPos < fHashSet.Count);
  1013. end;
  1014. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1015. constructor TutlCustomMap.TValueEnumerator.Create(const aHashSet: THashSet);
  1016. begin
  1017. inherited Create;
  1018. fHashSet := aHashSet;
  1019. fPos := -1;
  1020. end;
  1021. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1022. //TutlCustomMap.TKeyEnumerator//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1023. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1024. function TutlCustomMap.TKeyEnumerator.GetCurrent: TKey;
  1025. begin
  1026. result := fHashSet[fPos].Key;
  1027. end;
  1028. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1029. function TutlCustomMap.TKeyEnumerator.MoveNext: Boolean;
  1030. begin
  1031. inc(fPos);
  1032. result := (fPos < fHashSet.Count);
  1033. end;
  1034. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1035. constructor TutlCustomMap.TKeyEnumerator.Create(const aHashSet: THashSet);
  1036. begin
  1037. inherited Create;
  1038. fHashSet := aHashSet;
  1039. fPos := -1;
  1040. end;
  1041. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1042. //TutlCustomMap.TKeyValuePairEnumerator/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1043. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1044. function TutlCustomMap.TKeyValuePairEnumerator.GetCurrent: TKeyValuePair;
  1045. begin
  1046. result := fHashSet[fPos];
  1047. end;
  1048. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1049. function TutlCustomMap.TKeyValuePairEnumerator.MoveNext: Boolean;
  1050. begin
  1051. inc(fPos);
  1052. result := (fPos < fHashSet.Count);
  1053. end;
  1054. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1055. constructor TutlCustomMap.TKeyValuePairEnumerator.Create(const aHashSet: THashSet);
  1056. begin
  1057. inherited Create;
  1058. fHashSet := aHashSet;
  1059. fPos := -1;
  1060. end;
  1061. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1062. //TutlCustomMap.TKeyWrapper/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1063. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1064. function TutlCustomMap.TKeyWrapper.GetItem(const aIndex: Integer): TKey;
  1065. begin
  1066. result := fHashSet[aIndex].Key;
  1067. end;
  1068. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1069. function TutlCustomMap.TKeyWrapper.GetCount: Integer;
  1070. begin
  1071. result := fHashSet.Count;
  1072. end;
  1073. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1074. function TutlCustomMap.TKeyWrapper.GetEnumerator: TKeyEnumerator;
  1075. begin
  1076. result := TKeyEnumerator.Create(fHashSet);
  1077. end;
  1078. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1079. constructor TutlCustomMap.TKeyWrapper.Create(const aHashSet: THashSet);
  1080. begin
  1081. inherited Create;
  1082. fHashSet := aHashSet;
  1083. end;
  1084. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1085. //TutlCustomMap.TKeyValuePairWrapper////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1086. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1087. function TutlCustomMap.TKeyValuePairWrapper.GetItem(const aIndex: Integer): TKeyValuePair;
  1088. begin
  1089. result := fHashSet[aIndex];
  1090. end;
  1091. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1092. function TutlCustomMap.TKeyValuePairWrapper.GetCount: Integer;
  1093. begin
  1094. result := fHashSet.Count;
  1095. end;
  1096. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1097. function TutlCustomMap.TKeyValuePairWrapper.GetEnumerator: TKeyValuePairEnumerator;
  1098. begin
  1099. result := TKeyValuePairEnumerator.Create(fHashSet);
  1100. end;
  1101. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1102. constructor TutlCustomMap.TKeyValuePairWrapper.Create(const aHashSet: THashSet);
  1103. begin
  1104. inherited Create;
  1105. fHashSet := aHashSet;
  1106. end;
  1107. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1108. //TutlCustomMap/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1109. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1110. function TutlCustomMap.GetValues(const aKey: TKey): TValue;
  1111. var
  1112. i: Integer;
  1113. kvp: TKeyValuePair;
  1114. begin
  1115. kvp.Key := aKey;
  1116. i := fHashSet.IndexOf(kvp);
  1117. if (i < 0) then
  1118. FillByte(result{%H-}, SizeOf(result), 0)
  1119. else
  1120. result := fHashSet[i].Value;
  1121. end;
  1122. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1123. function TutlCustomMap.GetValueAt(const aIndex: Integer): TValue;
  1124. begin
  1125. result := fHashSet[aIndex].Value;
  1126. end;
  1127. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1128. function TutlCustomMap.GetCount: Integer;
  1129. begin
  1130. result := fHashSet.Count;
  1131. end;
  1132. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1133. procedure TutlCustomMap.SetValues(const aKey: TKey; aValue: TValue);
  1134. var
  1135. i: Integer;
  1136. kvp: TKeyValuePair;
  1137. begin
  1138. kvp.Key := aKey;
  1139. kvp.Value := aValue;
  1140. i := fHashSet.IndexOf(kvp);
  1141. if (i < 0) then
  1142. raise EutlMap.Create('key not found');
  1143. fHashSet[i] := kvp;
  1144. end;
  1145. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1146. procedure TutlCustomMap.SetValueAt(const aIndex: Integer; aValue: TValue);
  1147. var
  1148. kvp: TKeyValuePair;
  1149. begin
  1150. kvp := fHashSet[aIndex];
  1151. kvp.Value := aValue;
  1152. fHashSet[aIndex] := kvp;
  1153. end;
  1154. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1155. procedure TutlCustomMap.Add(const aKey: TKey; const aValue: TValue);
  1156. var
  1157. kvp: TKeyValuePair;
  1158. begin
  1159. kvp.Key := aKey;
  1160. kvp.Value := aValue;
  1161. if not fHashSet.Add(kvp) then
  1162. raise EutlMap.Create('key is already in list');
  1163. end;
  1164. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1165. function TutlCustomMap.IndexOf(const aKey: TKey): Integer;
  1166. var
  1167. kvp: TKeyValuePair;
  1168. begin
  1169. kvp.Key := aKey;
  1170. result := fHashSet.IndexOf(kvp);
  1171. end;
  1172. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1173. function TutlCustomMap.Contains(const aKey: TKey): Boolean;
  1174. var
  1175. kvp: TKeyValuePair;
  1176. begin
  1177. kvp.Key := aKey;
  1178. result := (fHashSet.IndexOf(kvp) >= 0);
  1179. end;
  1180. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1181. procedure TutlCustomMap.Delete(const aKey: TKey);
  1182. var
  1183. kvp: TKeyValuePair;
  1184. begin
  1185. kvp.Key := aKey;
  1186. if not fHashSet.Remove(kvp) then
  1187. raise EutlMap.Create('key not found');
  1188. end;
  1189. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1190. procedure TutlCustomMap.DeleteAt(const aIndex: Integer);
  1191. begin
  1192. fHashSet.Delete(aIndex);
  1193. end;
  1194. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1195. procedure TutlCustomMap.Clear;
  1196. begin
  1197. fHashSet.Clear;
  1198. end;
  1199. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1200. function TutlCustomMap.GetEnumerator: TValueEnumerator;
  1201. begin
  1202. result := TValueEnumerator.Create(fHashSet);
  1203. end;
  1204. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1205. constructor TutlCustomMap.Create(aComparer: IComparer; const aOwnsObjects: Boolean);
  1206. begin
  1207. inherited Create;
  1208. fComparer := aComparer;
  1209. fHashSet := THashSet.Create(TKVPComparer.Create(fComparer), aOwnsObjects);
  1210. fKeyWrapper := TKeyWrapper.Create(fHashSet);
  1211. fKeyValuePairWrapper := TKeyValuePairWrapper.Create(fHashSet);
  1212. end;
  1213. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1214. destructor TutlCustomMap.Destroy;
  1215. begin
  1216. FreeAndNil(fKeyValuePairWrapper);
  1217. FreeAndNil(fKeyWrapper);
  1218. FreeAndNil(fHashSet);
  1219. fComparer := nil;
  1220. inherited Destroy;
  1221. end;
  1222. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1223. //TutlMap///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1224. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1225. constructor TutlMap.Create(const aOwnsObjects: Boolean);
  1226. begin
  1227. inherited Create(TComparer.Create, aOwnsObjects);
  1228. end;
  1229. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1230. //TutlQueue/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1231. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1232. function TutlQueue.GetCount: Integer;
  1233. begin
  1234. InterLockedExchange(result{%H-}, fCount);
  1235. end;
  1236. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1237. procedure TutlQueue.Push(const aItem: T);
  1238. var
  1239. p: PListItem;
  1240. begin
  1241. new(p);
  1242. p^.data := aItem;
  1243. p^.next := nil;
  1244. fLast^.next := p;
  1245. fLast := fLast^.next;
  1246. InterLockedIncrement(fCount);
  1247. end;
  1248. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1249. function TutlQueue.Pop(out aItem: T): Boolean;
  1250. var
  1251. old: PListItem;
  1252. begin
  1253. result := false;
  1254. FillByte(aItem{%H-}, SizeOf(aItem), 0);
  1255. if (Count <= 0) then
  1256. exit;
  1257. result := true;
  1258. old := fFirst;
  1259. fFirst := fFirst^.next;
  1260. aItem := fFirst^.data;
  1261. InterLockedDecrement(fCount);
  1262. Dispose(old);
  1263. end;
  1264. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1265. function TutlQueue.Pop: Boolean;
  1266. var
  1267. tmp: T;
  1268. begin
  1269. result := Pop(tmp);
  1270. utlFreeOrFinalize(tmp, TypeInfo(tmp), fOwnsObjects);
  1271. end;
  1272. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1273. procedure TutlQueue.Clear;
  1274. begin
  1275. while Pop do;
  1276. end;
  1277. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1278. constructor TutlQueue.Create(const aOwnsObjects: Boolean);
  1279. begin
  1280. inherited Create;
  1281. new(fFirst);
  1282. FillByte(fFirst^, SizeOf(fFirst^), 0);
  1283. fLast := fFirst;
  1284. fCount := 0;
  1285. fOwnsObjects := aOwnsObjects;
  1286. end;
  1287. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1288. destructor TutlQueue.Destroy;
  1289. begin
  1290. Clear;
  1291. if Assigned(fLast) then begin
  1292. Dispose(fLast);
  1293. fLast := nil;
  1294. end;
  1295. inherited Destroy;
  1296. end;
  1297. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1298. //TutlSyncQueue/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1299. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1300. procedure TutlSyncQueue.Push(const aItem: T);
  1301. begin
  1302. fPushLock.Enter;
  1303. try
  1304. inherited Push(aItem);
  1305. finally
  1306. fPushLock.Leave;
  1307. end;
  1308. end;
  1309. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1310. function TutlSyncQueue.Pop(out aItem: T): Boolean;
  1311. begin
  1312. fPopLock.Enter;
  1313. try
  1314. result := inherited Pop(aItem);
  1315. finally
  1316. fPopLock.Leave;
  1317. end;
  1318. end;
  1319. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1320. constructor TutlSyncQueue.Create(const aOwnsObjects: Boolean);
  1321. begin
  1322. inherited Create(aOwnsObjects);
  1323. fPushLock := TutlSpinLock.Create;
  1324. fPopLock := TutlSpinLock.Create;
  1325. end;
  1326. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1327. destructor TutlSyncQueue.Destroy;
  1328. begin
  1329. inherited Destroy; //inherited will pop all remaining items, so do not destroy spinlock before!
  1330. FreeAndNil(fPushLock);
  1331. FreeAndNil(fPopLock);
  1332. end;
  1333. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1334. //TutlInterfaceList.TInterfaceEnumerator////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1335. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1336. function TutlInterfaceList.TInterfaceEnumerator.GetCurrent: T;
  1337. begin
  1338. result := T(fList[fPos]);
  1339. end;
  1340. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1341. function TutlInterfaceList.TInterfaceEnumerator.MoveNext: Boolean;
  1342. begin
  1343. inc(fPos);
  1344. result := (fPos < fList.Count);
  1345. end;
  1346. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1347. constructor TutlInterfaceList.TInterfaceEnumerator.Create(const aList: TInterfaceList);
  1348. begin
  1349. inherited Create;
  1350. fPos := -1;
  1351. fList := aList;
  1352. end;
  1353. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1354. //TutlInterfaceList/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1355. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1356. function TutlInterfaceList.Get(i : Integer): T;
  1357. begin
  1358. result := T(inherited Get(i));
  1359. end;
  1360. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1361. procedure TutlInterfaceList.Put(i : Integer; aItem : T);
  1362. begin
  1363. inherited Put(i, aItem);
  1364. end;
  1365. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1366. function TutlInterfaceList.First: T;
  1367. begin
  1368. result := T(inherited First);
  1369. end;
  1370. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1371. function TutlInterfaceList.IndexOf(aItem : T): Integer;
  1372. begin
  1373. result := inherited IndexOf(aItem);
  1374. end;
  1375. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1376. function TutlInterfaceList.Add(aItem : IUnknown): Integer;
  1377. begin
  1378. result := inherited Add(aItem);
  1379. end;
  1380. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1381. procedure TutlInterfaceList.Insert(i : Integer; aItem : T);
  1382. begin
  1383. inherited Insert(i, aItem);
  1384. end;
  1385. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1386. function TutlInterfaceList.Last : T;
  1387. begin
  1388. result := T(inherited Last);
  1389. end;
  1390. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1391. function TutlInterfaceList.Remove(aItem : T): Integer;
  1392. begin
  1393. result := inherited Remove(aItem);
  1394. end;
  1395. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1396. function TutlInterfaceList.GetEnumerator: TInterfaceEnumerator;
  1397. begin
  1398. result := TInterfaceEnumerator.Create(self);
  1399. end;
  1400. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1401. //TutlEnumHelper////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1402. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1403. class function TutlEnumHelper.ToString(aValue: T): String;
  1404. Var
  1405. PS: PShortString;
  1406. TI: PTypeInfo;
  1407. PT: PTypeData;
  1408. num: Integer;
  1409. begin
  1410. TI := TypeInfo(T);
  1411. PT := GetTypeData(TI);
  1412. if TI^.Kind = tkBool then begin
  1413. case Integer(aValue) of
  1414. 0,1:
  1415. Result:=BooleanIdents[Boolean(aValue)];
  1416. else
  1417. Result:='';
  1418. end;
  1419. end else begin
  1420. num := Integer(aValue);
  1421. if (num >= PT^.MinValue) and (num <= PT^.MaxValue) then begin
  1422. PS := @PT^.NameList;
  1423. dec(num, PT^.MinValue);
  1424. while num > 0 do begin
  1425. PS := PShortString(pointer(PS) + PByte(PS)^ + 1);
  1426. Dec(Num);
  1427. end;
  1428. Result := PS^;
  1429. end else
  1430. Result := '';
  1431. end;
  1432. end;
  1433. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1434. class function TutlEnumHelper.TryToEnum(aStr: String; out aValue: T): Boolean;
  1435. Var
  1436. PS: PShortString;
  1437. PT: PTypeData;
  1438. Count: longint;
  1439. sName: shortstring;
  1440. TI: PTypeInfo;
  1441. begin
  1442. TI := TypeInfo(T);
  1443. PT := GetTypeData(TI);
  1444. Result := False;
  1445. if Length(aStr) = 0 then
  1446. exit;
  1447. sName := aStr;
  1448. if TI^.Kind = tkBool then begin
  1449. If CompareText(BooleanIdents[false], aStr) = 0 then
  1450. aValue := T(0)
  1451. else if CompareText(BooleanIdents[true], aStr) = 0 then
  1452. aValue := T(1);
  1453. Result := true;
  1454. end else begin
  1455. PS := @PT^.NameList;
  1456. Count := 0;
  1457. While (PByte(PS)^ <> 0) do begin
  1458. If ShortCompareText(PS^, sName) = 0 then begin
  1459. aValue := T(Count + PT^.MinValue);
  1460. exit(true);
  1461. end;
  1462. PS := PShortString(pointer(PS) + PByte(PS)^ + 1);
  1463. Inc(Count);
  1464. end;
  1465. end;
  1466. end;
  1467. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1468. class function TutlEnumHelper.ToEnum(aStr: String): T;
  1469. begin
  1470. if not TryToEnum(aStr, result) then
  1471. raise EConvertError.CreateFmt('"%s" is an invalid %s',[aStr, PTypeInfo(TypeInfo(T))^.Name]);
  1472. end;
  1473. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1474. class function TutlEnumHelper.ToEnum(aStr: String; const aDefault: T): T;
  1475. begin
  1476. if not TryToEnum(aStr, result) then
  1477. result := aDefault;
  1478. end;
  1479. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1480. class function TutlEnumHelper.Values: TValueArray;
  1481. Var
  1482. TI: PTypeInfo;
  1483. PT: PTypeData;
  1484. i,j: integer;
  1485. begin
  1486. TI := TypeInfo(T);
  1487. PT := GetTypeData(TI);
  1488. if TI^.Kind = tkBool then begin
  1489. SetLength(Result, 2);
  1490. Result[0]:= T(true);
  1491. Result[1]:= T(false);
  1492. end else begin
  1493. SetLength(Result, PT^.MaxValue - PT^.MinValue + 1);
  1494. j:= 0;
  1495. for i:= PT^.MinValue to PT^.MaxValue do begin
  1496. Result[j]:= T(i);
  1497. inc(j);
  1498. end;
  1499. end;
  1500. end;
  1501. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1502. //TutlRingBuffer////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1503. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1504. constructor TutlRingBuffer.Create(const Elements: Integer);
  1505. begin
  1506. inherited Create;
  1507. fAborted:= false;
  1508. fDataLen:= Elements;
  1509. fDataSize:= SizeOf(T);
  1510. SetLength(fData, fDataLen);
  1511. fWritePtr:= 1;
  1512. fReadPtr:= 0;
  1513. fFillState:= 0;
  1514. fReadEvent:= TutlAutoResetEvent.Create;
  1515. fWrittenEvent:= TutlAutoResetEvent.Create;
  1516. end;
  1517. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1518. destructor TutlRingBuffer.Destroy;
  1519. begin
  1520. BreakPipe;
  1521. FreeAndNil(fReadEvent);
  1522. FreeAndNil(fWrittenEvent);
  1523. SetLength(fData, 0);
  1524. inherited Destroy;
  1525. end;
  1526. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1527. function TutlRingBuffer.Read(Buf: Pointer; Items: integer; BlockUntilAvail: boolean): integer;
  1528. var
  1529. wp, c, r: Integer;
  1530. begin
  1531. Result:= 0;
  1532. while Items > 0 do begin
  1533. if fAborted then
  1534. exit;
  1535. InterLockedExchange(wp{%H-}, fWritePtr);
  1536. r:= (fReadPtr + 1) mod fDataLen;
  1537. if wp < r then
  1538. wp:= fDataLen;
  1539. c:= wp - r;
  1540. if c > Items then
  1541. c:= Items;
  1542. if c > 0 then begin
  1543. Move(fData[r], Buf^, c * fDataSize);
  1544. Dec(Items, c);
  1545. inc(Result, c);
  1546. dec(fFillState, c);
  1547. inc(PByte(Buf), c * fDataSize);
  1548. InterLockedExchange(fReadPtr, (fReadPtr + c) mod fDataLen);
  1549. fReadEvent.SetEvent;
  1550. end else begin
  1551. if not BlockUntilAvail then
  1552. break;
  1553. fWrittenEvent.WaitFor(INFINITE);
  1554. end;
  1555. end;
  1556. end;
  1557. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1558. function TutlRingBuffer.Write(Buf: Pointer; Items: integer; BlockUntilDone: boolean): integer;
  1559. var
  1560. rp, c: integer;
  1561. begin
  1562. Result:= 0;
  1563. while Items > 0 do begin
  1564. if fAborted then
  1565. exit;
  1566. InterLockedExchange(rp{%H-}, fReadPtr);
  1567. if rp < fWritePtr then
  1568. rp:= fDataLen;
  1569. c:= rp - fWritePtr;
  1570. if c > Items then
  1571. c:= Items;
  1572. if c > 0 then begin
  1573. Move(Buf^, fData[fWritePtr], c * fDataSize);
  1574. dec(Items, c);
  1575. inc(Result, c);
  1576. inc(fFillState, c);
  1577. inc(PByte(Buf), c * fDataSize);
  1578. InterLockedExchange(fWritePtr, (fWritePtr + c) mod fDataLen);
  1579. fWrittenEvent.SetEvent;
  1580. end else begin
  1581. if not BlockUntilDone then
  1582. Break;
  1583. fReadEvent.WaitFor(INFINITE);
  1584. end;
  1585. end;
  1586. end;
  1587. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1588. procedure TutlRingBuffer.BreakPipe;
  1589. begin
  1590. fAborted:= true;
  1591. fWrittenEvent.SetEvent;
  1592. fReadEvent.SetEvent;
  1593. end;
  1594. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1595. //TutlPagedDataFiFo.TDataProvider///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1596. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1597. function TutlPagedDataFiFo.TDataProvider.Give(const aBuffer: PData; aCount: Integer): Integer;
  1598. begin
  1599. result := 0;
  1600. if (aCount > fCount - fPos) then
  1601. aCount := fCount - fPos;
  1602. if (aCount <= 0) then
  1603. exit;
  1604. Move((fData + fPos)^, aBuffer^, aCount * SizeOf(TData));
  1605. inc(fPos, aCount);
  1606. result := aCount;
  1607. end;
  1608. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1609. constructor TutlPagedDataFiFo.TDataProvider.Create(const aData: PData; const aCount: Integer);
  1610. begin
  1611. inherited Create;
  1612. fData := aData;
  1613. fCount := aCount;
  1614. fPos := 0;
  1615. end;
  1616. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1617. //TutlPagedDataFiFo.TDataConsumer///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1618. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1619. function TutlPagedDataFiFo.TDataConsumer.Take(const aBuffer: PData; aCount: Integer): Integer;
  1620. begin
  1621. result := 0;
  1622. if (aCount > fCount - fPos) then
  1623. aCount := fCount - fPos;
  1624. if (aCount <= 0) then
  1625. exit;
  1626. Move(aBuffer^, (fData + fPos)^, aCount * SizeOf(TData));
  1627. inc(fPos, aCount);
  1628. result := aCount;
  1629. end;
  1630. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1631. constructor TutlPagedDataFiFo.TDataConsumer.Create(const aData: PData; const aCount: Integer);
  1632. begin
  1633. inherited Create;
  1634. fData := aData;
  1635. fCount := aCount;
  1636. fPos := 0;
  1637. end;
  1638. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1639. //TutlPagedDataFiFo.TNestedDataProvider/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1640. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1641. function TutlPagedDataFiFo.TNestedDataProvider.Give(const aBuffer: PData; aCount: Integer): Integer;
  1642. begin
  1643. result := fCallback(aBuffer, aCount);
  1644. end;
  1645. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1646. constructor TutlPagedDataFiFo.TNestedDataProvider.Create(const aCallback: TDataCallback);
  1647. begin
  1648. inherited Create;
  1649. fCallback := aCallback;
  1650. end;
  1651. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1652. //TutlPagedDataFiFo.TNestedDataConsumer/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1653. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1654. function TutlPagedDataFiFo.TNestedDataConsumer.Take(const aBuffer: PData; aCount: Integer): Integer;
  1655. begin
  1656. result := fCallback(aBuffer, aCount);
  1657. end;
  1658. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1659. constructor TutlPagedDataFiFo.TNestedDataConsumer.Create(const aCallback: TDataCallback);
  1660. begin
  1661. inherited Create;
  1662. fCallback := aCallback;
  1663. end;
  1664. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1665. //TutlPagedDataFiFo.TStreamDataProvider/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1666. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1667. function TutlPagedDataFiFo.TStreamDataProvider.Give(const aBuffer: PData; aCount: Integer): Integer;
  1668. begin
  1669. result := fStream.Read(aBuffer^, aCount);
  1670. end;
  1671. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1672. constructor TutlPagedDataFiFo.TStreamDataProvider.Create(const aStream: TStream);
  1673. begin
  1674. inherited Create;
  1675. fStream := aStream;
  1676. end;
  1677. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1678. //TutlPagedDataFiFo.TStreamDataConsumer/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1679. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1680. function TutlPagedDataFiFo.TStreamDataConsumer.Take(const aBuffer: PData; aCount: Integer): Integer;
  1681. begin
  1682. result := fStream.Write(aBuffer^, aCount);
  1683. end;
  1684. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1685. constructor TutlPagedDataFiFo.TStreamDataConsumer.Create(const aStream: TStream);
  1686. begin
  1687. inherited Create;
  1688. fStream := aStream;
  1689. end;
  1690. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1691. //TutlPagedDataFiFo/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1692. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1693. function TutlPagedDataFiFo.WriteIntern(const aProvider: IDataProvider; aCount: Integer): Integer;
  1694. var
  1695. c, r: Integer;
  1696. p: PPage;
  1697. begin
  1698. if not Assigned(aProvider) then
  1699. raise EArgumentNil.Create('aProvider');
  1700. result := 0;
  1701. while (aCount > 0) do begin
  1702. if not Assigned(fWritePage) or (fWritePage^.WritePos >= fPageSize) then begin
  1703. new(p);
  1704. p^.ReadPos := 0;
  1705. p^.WritePos := 0;
  1706. p^.Next := nil;
  1707. SetLength(p^.Data, fPageSize);
  1708. if Assigned(fWritePage) then
  1709. fWritePage^.Next := p;
  1710. fWritePage := p;
  1711. if not Assigned(fReadPage) then
  1712. fReadPage := fWritePage;
  1713. end;
  1714. c := fPageSize - fWritePage^.WritePos;
  1715. if (c > aCount) then
  1716. c := aCount;
  1717. r := aProvider.Give(@fWritePage^.Data[fWritePage^.WritePos], c);
  1718. if (r = 0) then
  1719. exit;
  1720. inc(result, r);
  1721. inc(fWritePage^.WritePos, r);
  1722. inc(fSize, r);
  1723. dec(aCount, r);
  1724. end;
  1725. end;
  1726. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1727. function TutlPagedDataFiFo.ReadIntern(const aConsumer: IDataConsumer; aCount: Integer; const aMoveReadPos: Boolean): Integer;
  1728. var
  1729. ReadPage: PPage;
  1730. DummyPage: TPage;
  1731. c, r: Integer;
  1732. begin
  1733. result := 0;
  1734. if not Assigned(fReadPage) then
  1735. exit;
  1736. //init read page
  1737. if not aMoveReadPos then begin
  1738. DummyPage := fReadPage^; // copy page (data is not copied, because it's a dynamic array)
  1739. ReadPage := @DummyPage;
  1740. end else
  1741. ReadPage := fReadPage;
  1742. while (aCount > 0) do begin
  1743. if (ReadPage^.ReadPos >= fPageSize) then begin
  1744. if not Assigned(ReadPage^.Next) then
  1745. exit;
  1746. if aMoveReadPos then begin
  1747. if (fReadPage = fWritePage) then // write finished with page end, so reset WritePage wenn disposing ReadPage
  1748. fWritePage := nil;
  1749. fReadPage := fReadPage^.Next;
  1750. Dispose(ReadPage);
  1751. ReadPage := fReadPage;
  1752. end else
  1753. ReadPage^ := ReadPage^.Next^;
  1754. end;
  1755. c := ReadPage^.WritePos - ReadPage^.ReadPos;
  1756. if (c = 0) then
  1757. exit;
  1758. if (c > aCount) then
  1759. c := aCount;
  1760. if Assigned(aConsumer) then begin
  1761. r := aConsumer.Take(@ReadPage^.Data[ReadPage^.ReadPos], c);
  1762. if (r = 0) then
  1763. exit;
  1764. end else
  1765. r := c;
  1766. inc(result, r);
  1767. inc(ReadPage^.ReadPos, r);
  1768. dec(aCount, r);
  1769. if aMoveReadPos then
  1770. dec(fSize, r);
  1771. end;
  1772. end;
  1773. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1774. function TutlPagedDataFiFo.Write(const aProvider: IDataProvider; const aCount: Integer): Integer;
  1775. begin
  1776. result := WriteIntern(aProvider, aCount);
  1777. end;
  1778. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1779. function TutlPagedDataFiFo.Write(const aData: PData; const aCount: Integer): Integer;
  1780. var
  1781. provider: IDataProvider;
  1782. begin
  1783. provider := TDataProvider.Create(aData, aCount);
  1784. result := WriteIntern(provider, aCount);
  1785. end;
  1786. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1787. function TutlPagedDataFiFo.Read(const aConsumer: IDataConsumer; const aCount: Integer): Integer;
  1788. begin
  1789. result := ReadIntern(aConsumer, aCount, true);
  1790. end;
  1791. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1792. function TutlPagedDataFiFo.Read(const aData: PData; const aCount: Integer): Integer;
  1793. var
  1794. consumer: IDataConsumer;
  1795. begin
  1796. consumer := TDataConsumer.Create(aData, aCount);
  1797. result := ReadIntern(consumer, aCount, true);
  1798. end;
  1799. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1800. function TutlPagedDataFiFo.Peek(const aConsumer: IDataConsumer; const aCount: Integer): Integer;
  1801. begin
  1802. result := ReadIntern(aConsumer, aCount, false);
  1803. end;
  1804. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1805. function TutlPagedDataFiFo.Peek(const aData: PData; const aCount: Integer): Integer;
  1806. var
  1807. consumer: IDataConsumer;
  1808. begin
  1809. consumer := TDataConsumer.Create(aData, aCount);
  1810. result := ReadIntern(consumer, aCount, false);
  1811. end;
  1812. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1813. function TutlPagedDataFiFo.Discard(const aCount: Integer): Integer;
  1814. begin
  1815. result := ReadIntern(nil, aCount, true);
  1816. end;
  1817. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1818. procedure TutlPagedDataFiFo.Clear;
  1819. var
  1820. tmp: PPage;
  1821. begin
  1822. while Assigned(fReadPage) do begin
  1823. tmp := fReadPage;
  1824. fReadPage := tmp^.Next;
  1825. Dispose(tmp);
  1826. end;
  1827. fReadPage := nil;
  1828. fWritePage := nil;
  1829. end;
  1830. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1831. constructor TutlPagedDataFiFo.Create(const aPageSize: Integer);
  1832. begin
  1833. inherited Create;
  1834. fReadPage := nil;
  1835. fWritePage := nil;
  1836. fPageSize := aPageSize;
  1837. end;
  1838. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1839. destructor TutlPagedDataFiFo.Destroy;
  1840. begin
  1841. Clear;
  1842. inherited Destroy;
  1843. end;
  1844. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1845. //TutlSyncPagedDataFiFo/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1846. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1847. function TutlSyncPagedDataFiFo.WriteIntern(const aProvider: IDataProvider; aCount: Integer): Integer;
  1848. begin
  1849. fLock.Enter;
  1850. try
  1851. result := inherited WriteIntern(aProvider, aCount);
  1852. finally
  1853. fLock.Leave;
  1854. end;
  1855. end;
  1856. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1857. function TutlSyncPagedDataFiFo.ReadIntern(const aConsumer: IDataConsumer; aCount: Integer; const aMoveReadPos: Boolean): Integer;
  1858. begin
  1859. fLock.Enter;
  1860. try
  1861. result := inherited ReadIntern(aConsumer, aCount, aMoveReadPos);
  1862. finally
  1863. fLock.Leave;
  1864. end;
  1865. end;
  1866. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1867. constructor TutlSyncPagedDataFiFo.Create(const aPageSize: Integer);
  1868. begin
  1869. inherited Create(aPageSize);
  1870. fLock := TutlSpinLock.Create;
  1871. end;
  1872. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1873. destructor TutlSyncPagedDataFiFo.Destroy;
  1874. begin
  1875. inherited Destroy;
  1876. FreeAndNil(fLock);
  1877. end;
  1878. end.