Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

2250 строки
92 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. TItemEvent = procedure(aSender: TObject; const aIndex: Integer; const aItem: T) of object;
  74. TEnumerator = class(TObject)
  75. private
  76. fReverse: Boolean;
  77. fList: TFPList;
  78. fPosition: Integer;
  79. function GetCurrent: T;
  80. public
  81. property Current: T read GetCurrent;
  82. function GetEnumerator: TEnumerator;
  83. function MoveNext: Boolean;
  84. constructor Create(const aList: TFPList; const aReverse: Boolean = false);
  85. end;
  86. private
  87. fList: TFPList;
  88. fOwnsObjects: Boolean;
  89. protected
  90. property List: TFPList read fList;
  91. function GetCount: Integer;
  92. function GetItem(const aIndex: Integer): T;
  93. procedure SetCount(const aValue: Integer);
  94. procedure SetItem(const aIndex: Integer; const aItem: T);
  95. function CreateItem: PListItem; virtual;
  96. procedure DestroyItem(const aItem: PListItem; const aFreeItem: Boolean = true); virtual;
  97. procedure InsertIntern(const aIndex: Integer; const aItem: T); virtual;
  98. procedure DeleteIntern(const aIndex: Integer; const aFreeItem: Boolean = true); virtual;
  99. public
  100. property OwnsObjects: Boolean read fOwnsObjects write fOwnsObjects;
  101. function GetEnumerator: TEnumerator;
  102. function GetReverseEnumerator: TEnumerator;
  103. procedure ForEach(const aEvent: TItemEvent);
  104. procedure Clear;
  105. constructor Create(const aOwnsObjects: Boolean = true);
  106. destructor Destroy; override;
  107. end;
  108. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  109. { a simple list without the ability to compare objects (e.g. for IndexOf, Remove, Extract) }
  110. generic TutlSimpleList<T> = class(specialize TutlListBase<T>)
  111. public type
  112. IComparer = specialize IutlComparer<T>;
  113. TSortDirection = (sdAscending, sdDescending);
  114. private
  115. function Split(aComparer: IComparer; const aDirection: TSortDirection; const aLeft, aRight: Integer): Integer;
  116. procedure QuickSort(aComparer: IComparer; const aDirection: TSortDirection; const aLeft, aRight: Integer);
  117. public
  118. property Items[const aIndex: Integer]: T read GetItem write SetItem; default;
  119. property Count: Integer read GetCount write SetCount;
  120. function Add(const aItem: T): Integer;
  121. procedure Insert(const aIndex: Integer; const aItem: T);
  122. procedure Exchange(const aIndex1, aIndex2: Integer);
  123. procedure Move(const aCurIndex, aNewIndex: Integer);
  124. procedure Sort(aComparer: IComparer; const aDirection: TSortDirection = sdAscending);
  125. procedure Delete(const aIndex: Integer);
  126. function First: T;
  127. procedure PushFirst(const aItem: T);
  128. function PopFirst(const aFreeItem: Boolean = false): T;
  129. function Last: T;
  130. procedure PushLast(const aItem: T);
  131. function PopLast(const aFreeItem: Boolean = false): T;
  132. end;
  133. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  134. generic TutlCustomList<T> = class(specialize TutlSimpleList<T>)
  135. public type
  136. IEqualityComparer = specialize IutlEqualityComparer<T>;
  137. private
  138. fEqualityComparer: IEqualityComparer;
  139. public
  140. function IndexOf(const aItem: T): Integer;
  141. function Extract(const aItem: T; const aDefault: T): T;
  142. function Remove(const aItem: T): Integer;
  143. constructor Create(aEqualityComparer: IEqualityComparer; const aOwnsObjects: Boolean = true);
  144. destructor Destroy; override;
  145. end;
  146. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  147. generic TutlList<T> = class(specialize TutlCustomList<T>)
  148. public type
  149. TEqualityComparer = specialize TutlEqualityComparer<T>;
  150. public
  151. constructor Create(const aOwnsObjects: Boolean = true);
  152. end;
  153. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  154. generic TutlHashSetBase<T> = class(specialize TutlListBase<T>)
  155. public type
  156. THashItemEvent = procedure(aSender: TObject; const aItem: T) of object;
  157. IComparer = specialize IutlComparer<T>;
  158. private
  159. fComparer: IComparer;
  160. protected
  161. function SearchItem(const aMin, aMax: Integer; const aItem: T; out aIndex: Integer): Integer;
  162. public
  163. procedure ForEach(const aEvent: THashItemEvent);
  164. constructor Create(aComparer: IComparer; const aOwnsObjects: Boolean = true);
  165. destructor Destroy; override;
  166. end;
  167. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  168. generic TutlCustomHashSet<T> = class(specialize TutlHashSetBase<T>)
  169. public
  170. property Items[const aIndex: Integer]: T read GetItem; default;
  171. property Count: Integer read GetCount;
  172. function Add(const aItem: T): Boolean;
  173. function Contains(const aItem: T): Boolean;
  174. function IndexOf(const aItem: T): Integer;
  175. function Remove(const aItem: T): Boolean;
  176. procedure Delete(const aIndex: Integer);
  177. end;
  178. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  179. generic TutlHashSet<T> = class(specialize TutlCustomHashSet<T>)
  180. public type
  181. TComparer = specialize TutlComparer<T>;
  182. public
  183. constructor Create(const aOwnsObjects: Boolean = true);
  184. end;
  185. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  186. EutlMap = class(Exception);
  187. EutlMapKeyNotFound = class(EutlMap)
  188. public
  189. constructor Create;
  190. end;
  191. EutlMapKeyAlreadyExists = class(EutlMap)
  192. public
  193. constructor Create;
  194. end;
  195. generic TutlMapBase<TKey, TValue> = class(TObject)
  196. public type
  197. TKeyValuePairEvent = procedure(aSender: TObject; const aKey: TKey; const aValue: TValue) of object;
  198. IComparer = specialize IutlComparer<TKey>;
  199. TKeyValuePair = packed record
  200. Key: TKey;
  201. Value: TValue;
  202. end;
  203. THashSet = class(specialize TutlCustomHashSet<TKeyValuePair>)
  204. protected
  205. procedure DestroyItem(const aItem: PListItem; const aFreeItem: Boolean = true); override;
  206. public
  207. property Items[const aIndex: Integer]: TKeyValuePair read GetItem write SetItem; default;
  208. end;
  209. TKeyValuePairComparer = class(TInterfacedObject, THashSet.IComparer)
  210. private
  211. fComparer: IComparer;
  212. public
  213. function Compare(const i1, i2: TKeyValuePair): Integer;
  214. constructor Create(aComparer: IComparer);
  215. destructor Destroy; override;
  216. end;
  217. TEnumeratorProxy = class(TObject)
  218. fEnumerator: THashSet.TEnumerator;
  219. function MoveNext: Boolean;
  220. constructor Create(const aEnumerator: THashSet.TEnumerator);
  221. destructor Destroy; override;
  222. end;
  223. TValueEnumerator = class(TEnumeratorProxy)
  224. function GetCurrent: TValue;
  225. property Current: TValue read GetCurrent;
  226. function GetEnumerator: TValueEnumerator;
  227. end;
  228. TKeyEnumerator = class(TEnumeratorProxy)
  229. function GetCurrent: TKey;
  230. property Current: TKey read GetCurrent;
  231. function GetEnumerator: TKeyEnumerator;
  232. end;
  233. TKeyWrapper = class(TObject)
  234. private
  235. fHashSet: THashSet;
  236. function GetItem(const aIndex: Integer): TKey;
  237. function GetCount: Integer;
  238. public
  239. property Items[const aIndex: Integer]: TKey read GetItem; default;
  240. property Count: Integer read GetCount;
  241. function GetEnumerator: TKeyEnumerator;
  242. function GetReverseEnumerator: TKeyEnumerator;
  243. constructor Create(const aHashSet: THashSet);
  244. end;
  245. TKeyValuePairWrapper = class(TObject)
  246. private
  247. fHashSet: THashSet;
  248. function GetItem(const aIndex: Integer): TKeyValuePair;
  249. function GetCount: Integer;
  250. public
  251. property Items[const aIndex: Integer]: TKeyValuePair read GetItem; default;
  252. property Count: Integer read GetCount;
  253. function GetEnumerator: THashSet.TEnumerator;
  254. function GetReverseEnumerator: THashSet.TEnumerator;
  255. constructor Create(const aHashSet: THashSet);
  256. end;
  257. private
  258. fHashSetRef: THashSet;
  259. fKeyWrapper: TKeyWrapper;
  260. fKeyValuePairWrapper: TKeyValuePairWrapper;
  261. function GetValues(const aKey: TKey): TValue;
  262. function GetValueAt(const aIndex: Integer): TValue;
  263. function GetCount: Integer;
  264. procedure SetValueAt(const aIndex: Integer; aValue: TValue);
  265. procedure SetValues(const aKey: TKey; aValue: TValue);
  266. public
  267. property Values [const aKey: TKey]: TValue read GetValues write SetValues; default;
  268. property ValueAt[const aIndex: Integer]: TValue read GetValueAt write SetValueAt;
  269. property Keys: TKeyWrapper read fKeyWrapper;
  270. property KeyValuePairs: TKeyValuePairWrapper read fKeyValuePairWrapper;
  271. property Count: Integer read GetCount;
  272. procedure Add(const aKey: TKey; const aValue: TValue);
  273. function IndexOf(const aKey: TKey): Integer;
  274. function Contains(const aKey: TKey): Boolean;
  275. procedure Delete(const aKey: TKey);
  276. procedure DeleteAt(const aIndex: Integer);
  277. procedure Clear;
  278. procedure ForEach(const aEvent: TKeyValuePairEvent);
  279. function GetEnumerator: TValueEnumerator;
  280. function GetReverseEnumerator: TValueEnumerator;
  281. constructor Create(const aHashSet: THashSet);
  282. destructor Destroy; override;
  283. end;
  284. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  285. generic TutlCustomMap<TKey, TValue> = class(specialize TutlMapBase<TKey, TValue>)
  286. private
  287. fHashSetImpl: THashSet;
  288. public
  289. constructor Create(const aComparer: IComparer; const aOwnsObjects: Boolean = true);
  290. destructor Destroy; override;
  291. end;
  292. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  293. generic TutlMap<TKey, TValue> = class(specialize TutlCustomMap<TKey, TValue>)
  294. public type
  295. TComparer = specialize TutlComparer<TKey>;
  296. public
  297. constructor Create(const aOwnsObjects: Boolean = true);
  298. end;
  299. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  300. generic TutlQueue<T> = class(TObject)
  301. public type
  302. PListItem = ^TListItem;
  303. TListItem = packed record
  304. data: T;
  305. next: PListItem;
  306. end;
  307. private
  308. function GetCount: Integer;
  309. protected
  310. fFirst: PListItem;
  311. fLast: PListItem;
  312. fCount: Integer;
  313. fOwnsObjects: Boolean;
  314. public
  315. property Count: Integer read GetCount;
  316. procedure Push(const aItem: T); virtual;
  317. function Pop(out aItem: T): Boolean; virtual;
  318. function Pop: Boolean;
  319. procedure Clear;
  320. constructor Create(const aOwnsObjects: Boolean = true);
  321. destructor Destroy; override;
  322. end;
  323. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  324. generic TutlSyncQueue<T> = class(specialize TutlQueue<T>)
  325. private
  326. fPushLock: TutlSpinLock;
  327. fPopLock: TutlSpinLock;
  328. public
  329. procedure Push(const aItem: T); override;
  330. function Pop(out aItem: T): Boolean; override;
  331. constructor Create(const aOwnsObjects: Boolean = true);
  332. destructor Destroy; override;
  333. end;
  334. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  335. generic TutlInterfaceList<T> = class(TInterfaceList)
  336. private type
  337. TInterfaceEnumerator = class(TObject)
  338. private
  339. fList: TInterfaceList;
  340. fPos: Integer;
  341. function GetCurrent: T;
  342. public
  343. property Current: T read GetCurrent;
  344. function MoveNext: Boolean;
  345. constructor Create(const aList: TInterfaceList);
  346. end;
  347. private
  348. function Get(i : Integer): T;
  349. procedure Put(i : Integer; aItem : T);
  350. public
  351. property Items[Index : Integer]: T read Get write Put; default;
  352. function First: T;
  353. function IndexOf(aItem : T): Integer;
  354. function Add(aItem : IUnknown): Integer;
  355. procedure Insert(i : Integer; aItem : T);
  356. function Last : T;
  357. function Remove(aItem : T): Integer;
  358. function GetEnumerator: TInterfaceEnumerator;
  359. end;
  360. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  361. EutlEnumConvert = class(EConvertError)
  362. public
  363. constructor Create(const aValue, aExpectedType: String);
  364. end;
  365. generic TutlEnumHelper<T> = class(TObject)
  366. private type
  367. TValueArray = array of T;
  368. private class var
  369. FTypeInfo: PTypeInfo;
  370. FValues: TValueArray;
  371. public
  372. class constructor Initialize;
  373. class function ToString(aValue: T): String; reintroduce;
  374. class function TryToEnum(aStr: String; out aValue: T): Boolean;
  375. class function ToEnum(aStr: String): T; overload;
  376. class function ToEnum(aStr: String; const aDefault: T): T; overload;
  377. class function Values: TValueArray;
  378. class function TypeInfo: PTypeInfo;
  379. end;
  380. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  381. generic TutlRingBuffer<T> = class
  382. private
  383. fAborted: boolean;
  384. fData: packed array of T;
  385. fDataLen: Integer;
  386. fDataSize: integer;
  387. fFillState: integer;
  388. fWritePtr, fReadPtr: integer;
  389. fWrittenEvent,
  390. fReadEvent: TutlAutoResetEvent;
  391. public
  392. constructor Create(const Elements: Integer);
  393. destructor Destroy; override;
  394. function Read(Buf: Pointer; Items: integer; BlockUntilAvail: boolean): integer;
  395. function Write(Buf: Pointer; Items: integer; BlockUntilDone: boolean): integer;
  396. procedure BreakPipe;
  397. property FillState: Integer read fFillState;
  398. property Size: integer read fDataLen;
  399. end;
  400. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  401. generic TutlPagedDataFiFo<TData> = class
  402. private type
  403. PPage = ^TPage;
  404. TPage = packed record
  405. Next: PPage;
  406. Data: array of TData;
  407. ReadPos: Integer;
  408. WritePos: Integer;
  409. end;
  410. public type
  411. PData = ^TData;
  412. IDataProvider = interface(IUnknown)
  413. function Give(const aBuffer: PData; aCount: Integer): Integer;
  414. end;
  415. IDataConsumer = interface(IUnknown)
  416. function Take(const aBuffer: PData; aCount: Integer): Integer;
  417. end;
  418. // read from buffer, write to fifo
  419. TDataProvider = class(TInterfacedObject, IDataProvider)
  420. private
  421. fData: PData;
  422. fPos: Integer;
  423. fCount: Integer;
  424. public
  425. function Give(const aBuffer: PData; aCount: Integer): Integer;
  426. constructor Create(const aData: PData; const aCount: Integer);
  427. end;
  428. // read from fifo, write to buffer
  429. TDataConsumer = class(TInterfacedObject, IDataConsumer)
  430. private
  431. fData: PData;
  432. fPos: Integer;
  433. fCount: Integer;
  434. public
  435. function Take(const aBuffer: PData; aCount: Integer): Integer;
  436. constructor Create(const aData: PData; const aCount: Integer);
  437. end;
  438. // read from nested callback, write to fifo
  439. TDataCallback = function(const aBuffer: PData; aCount: Integer): Integer is nested;
  440. TNestedDataProvider = class(TInterfacedObject, IDataProvider)
  441. private
  442. fCallback: TDataCallback;
  443. public
  444. function Give(const aBuffer: PData; aCount: Integer): Integer;
  445. constructor Create(const aCallback: TDataCallback);
  446. end;
  447. // read from fifo, write to nested callback
  448. TNestedDataConsumer = class(TInterfacedObject, IDataConsumer)
  449. private
  450. fCallback: TDataCallback;
  451. public
  452. function Take(const aBuffer: PData; aCount: Integer): Integer;
  453. constructor Create(const aCallback: TDataCallback);
  454. end;
  455. // read from stream, write to fifo
  456. TStreamDataProvider = class(TInterfacedObject, IDataProvider)
  457. private
  458. fStream: TStream;
  459. public
  460. function Give(const aBuffer: PData; aCount: Integer): Integer;
  461. constructor Create(const aStream: TStream);
  462. end;
  463. // read from fifo, write to stream
  464. TStreamDataConsumer = class(TInterfacedObject, IDataConsumer)
  465. private
  466. fStream: TStream;
  467. public
  468. function Take(const aBuffer: PData; aCount: Integer): Integer;
  469. constructor Create(const aStream: TStream);
  470. end;
  471. private
  472. fPageSize: Integer;
  473. fReadPage: PPage;
  474. fWritePage: PPage;
  475. fSize: Integer;
  476. protected
  477. function WriteIntern(const aProvider: IDataProvider; aCount: Integer): Integer; virtual;
  478. function ReadIntern(const aConsumer: IDataConsumer; aCount: Integer; const aMoveReadPos: Boolean): Integer; virtual;
  479. public
  480. property Size: Integer read fSize;
  481. property PageSize: Integer read fPageSize;
  482. function Write(const aProvider: IDataProvider; const aCount: Integer): Integer; overload;
  483. function Write(const aData: PData; const aCount: Integer): Integer; overload;
  484. function Read(const aConsumer: IDataConsumer; const aCount: Integer): Integer; overload;
  485. function Read(const aData: PData; const aCount: Integer): Integer; overload;
  486. function Peek(const aConsumer: IDataConsumer; const aCount: Integer): Integer; overload;
  487. function Peek(const aData: PData; const aCount: Integer): Integer; overload;
  488. function Discard(const aCount: Integer): Integer;
  489. procedure Clear;
  490. constructor Create(const aPageSize: Integer = 2048);
  491. destructor Destroy; override;
  492. end;
  493. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  494. generic TutlSyncPagedDataFiFo<TData> = class(specialize TutlPagedDataFiFo<TData>)
  495. private
  496. fLock: TutlSpinLock;
  497. protected
  498. function WriteIntern(const aProvider: IDataProvider; aCount: Integer): Integer; override;
  499. function ReadIntern(const aConsumer: IDataConsumer; aCount: Integer; const aMoveReadPos: Boolean): Integer; override;
  500. public
  501. constructor Create(const aPageSize: Integer = 2048);
  502. destructor Destroy; override;
  503. end;
  504. function utlFreeOrFinalize(var obj; const aTypeInfo: PTypeInfo; const aFreeObj: Boolean = true): Boolean;
  505. operator < (const i1, i2: TObject): Boolean; inline;
  506. operator > (const i1, i2: TObject): Boolean; inline;
  507. implementation
  508. uses
  509. uutlExceptions, syncobjs;
  510. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  511. //Helper////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  512. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  513. operator < (const i1, i2: TObject): Boolean;
  514. begin
  515. result := Pointer(i1) < Pointer(i2);
  516. end;
  517. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  518. operator > (const i1, i2: TObject): Boolean;
  519. begin
  520. result := Pointer(i1) > Pointer(i2);
  521. end;
  522. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  523. function utlFreeOrFinalize(var obj; const aTypeInfo: PTypeInfo; const aFreeObj: Boolean = true): Boolean;
  524. var
  525. o: TObject;
  526. begin
  527. result := true;
  528. case aTypeInfo^.Kind of
  529. tkClass: begin
  530. if (aFreeObj) then begin
  531. o := TObject(obj);
  532. Pointer(obj) := nil;
  533. o.Free;
  534. end;
  535. end;
  536. tkInterface: begin
  537. IUnknown(obj) := nil;
  538. end;
  539. tkAString: begin
  540. AnsiString(Obj) := '';
  541. end;
  542. tkUString: begin
  543. UnicodeString(Obj) := '';
  544. end;
  545. tkString: begin
  546. String(Obj) := '';
  547. end;
  548. else
  549. result := false;
  550. end;
  551. end;
  552. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  553. constructor TutlCustomMap.Create(const aComparer: IComparer; const aOwnsObjects: Boolean);
  554. begin
  555. fHashSetImpl := THashSet.Create(TKeyValuePairComparer.Create(aComparer), aOwnsObjects);
  556. inherited Create(fHashSetImpl);
  557. end;
  558. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  559. destructor TutlCustomMap.Destroy;
  560. begin
  561. inherited Destroy;
  562. FreeAndNil(fHashSetImpl);
  563. end;
  564. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  565. //EutlEnumConvert///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  566. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  567. constructor EutlEnumConvert.Create(const aValue, aExpectedType: String);
  568. begin
  569. inherited Create(Format('%s is not a %s', [aValue, aExpectedType]));
  570. end;
  571. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  572. //EutlMapKeyNotFound////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  573. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  574. constructor EutlMapKeyNotFound.Create;
  575. begin
  576. inherited Create('key not found');
  577. end;
  578. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  579. //EutlMapKeyAlreadyExists///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  580. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  581. constructor EutlMapKeyAlreadyExists.Create;
  582. begin
  583. inherited Create('key already exists');
  584. end;
  585. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  586. //TutlEqualityComparer//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  587. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  588. function TutlEqualityComparer.EqualityCompare(const i1, i2: T): Boolean;
  589. begin
  590. result := (i1 = i2);
  591. end;
  592. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  593. function TutlEventEqualityComparer.EqualityCompare(const i1, i2: T): Boolean;
  594. begin
  595. case fEventType of
  596. eetNormal: result := fEvent(i1, i2);
  597. eetObject: result := fEventO(i1, i2);
  598. eetNested: result := fEventN(i1, i2);
  599. end;
  600. end;
  601. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  602. constructor TutlEventEqualityComparer.Create(const aEvent: TEqualityEvent);
  603. begin
  604. inherited Create;
  605. fEvent := aEvent;
  606. fEventType := eetNormal;
  607. end;
  608. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  609. constructor TutlEventEqualityComparer.Create(const aEvent: TEqualityEventO);
  610. begin
  611. inherited Create;
  612. fEventO := aEvent;
  613. fEventType := eetObject;
  614. end;
  615. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  616. constructor TutlEventEqualityComparer.Create(const aEvent: TEqualityEventN);
  617. begin
  618. inherited Create;
  619. fEventN := aEvent;
  620. fEventType := eetNested;
  621. end;
  622. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  623. //TutlComparer//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  624. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  625. function TutlComparer.Compare(const i1, i2: T): Integer;
  626. begin
  627. if (i1 < i2) then
  628. result := -1
  629. else if (i1 > i2) then
  630. result := 1
  631. else
  632. result := 0;
  633. end;
  634. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  635. function TutlEventComparer.Compare(const i1, i2: T): Integer;
  636. begin
  637. case fEventType of
  638. etNormal: result := fEvent(i1, i2);
  639. etObject: result := fEventO(i1, i2);
  640. etNested: result := fEventN(i1, i2);
  641. end;
  642. end;
  643. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  644. constructor TutlEventComparer.Create(const aEvent: TEvent);
  645. begin
  646. inherited Create;
  647. fEvent := aEvent;
  648. fEventType := etNormal;
  649. end;
  650. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  651. constructor TutlEventComparer.Create(const aEvent: TEventO);
  652. begin
  653. inherited Create;
  654. fEventO := aEvent;
  655. fEventType := etObject;
  656. end;
  657. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  658. constructor TutlEventComparer.Create(const aEvent: TEventN);
  659. begin
  660. inherited Create;
  661. fEventN := aEvent;
  662. fEventType := etNested;
  663. end;
  664. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  665. //TutlListBase//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  666. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  667. function TutlListBase.TEnumerator.GetCurrent: T;
  668. begin
  669. result := PListItem(fList[fPosition])^.data;
  670. end;
  671. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  672. function TutlListBase.TEnumerator.GetEnumerator: TEnumerator;
  673. begin
  674. result := self;
  675. end;
  676. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  677. function TutlListBase.TEnumerator.MoveNext: Boolean;
  678. begin
  679. if fReverse then begin
  680. dec(fPosition);
  681. result := (fPosition >= 0);
  682. end else begin
  683. inc(fPosition);
  684. result := (fPosition < fList.Count)
  685. end;
  686. end;
  687. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  688. constructor TutlListBase.TEnumerator.Create(const aList: TFPList; const aReverse: Boolean);
  689. begin
  690. inherited Create;
  691. fList := aList;
  692. fReverse := aReverse;
  693. if fReverse then
  694. fPosition := fList.Count
  695. else
  696. fPosition := -1;
  697. end;
  698. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  699. //TutlListBase//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  700. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  701. function TutlListBase.GetCount: Integer;
  702. begin
  703. result := fList.Count;
  704. end;
  705. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  706. function TutlListBase.GetItem(const aIndex: Integer): T;
  707. begin
  708. if (aIndex >= 0) and (aIndex < fList.Count) then
  709. result := PListItem(fList[aIndex])^.data
  710. else
  711. raise EOutOfRange.Create(aIndex, 0, fList.Count-1);
  712. end;
  713. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  714. procedure TutlListBase.SetCount(const aValue: Integer);
  715. var
  716. item: PListItem;
  717. begin
  718. if (aValue < 0) then
  719. raise EArgument.Create('new value for count must be positiv');
  720. while (aValue > fList.Count) do begin
  721. item := CreateItem;
  722. FillByte(item^, SizeOf(item^), 0);
  723. fList.Add(item);
  724. end;
  725. while (aValue < fList.Count) do
  726. DeleteIntern(fList.Count-1);
  727. end;
  728. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  729. procedure TutlListBase.SetItem(const aIndex: Integer; const aItem: T);
  730. var
  731. item: PListItem;
  732. begin
  733. if (aIndex >= 0) and (aIndex < fList.Count) then begin
  734. item := PListItem(fList[aIndex]);
  735. utlFreeOrFinalize(item^, TypeInfo(item^), fOwnsObjects);
  736. item^.data := aItem;
  737. end else
  738. raise EOutOfRange.Create(aIndex, 0, fList.Count-1);
  739. end;
  740. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  741. function TutlListBase.CreateItem: PListItem;
  742. begin
  743. new(result);
  744. end;
  745. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  746. procedure TutlListBase.DestroyItem(const aItem: PListItem; const aFreeItem: Boolean);
  747. begin
  748. utlFreeOrFinalize(aItem^.data, TypeInfo(aItem^.data), fOwnsObjects and aFreeItem);
  749. Dispose(aItem);
  750. end;
  751. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  752. procedure TutlListBase.InsertIntern(const aIndex: Integer; const aItem: T);
  753. var
  754. item: PListItem;
  755. begin
  756. item := CreateItem;
  757. try
  758. item^.data := aItem;
  759. fList.Insert(aIndex, item);
  760. except
  761. DestroyItem(item, false);
  762. raise;
  763. end;
  764. end;
  765. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  766. procedure TutlListBase.DeleteIntern(const aIndex: Integer; const aFreeItem: Boolean);
  767. var
  768. item: PListItem;
  769. begin
  770. if (aIndex >= 0) and (aIndex < fList.Count) then begin
  771. item := PListItem(fList[aIndex]);
  772. fList.Delete(aIndex);
  773. DestroyItem(item, aFreeItem);
  774. end else
  775. raise EOutOfRange.Create(aIndex, 0, fList.Count-1);
  776. end;
  777. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  778. function TutlListBase.GetEnumerator: TEnumerator;
  779. begin
  780. result := TEnumerator.Create(fList, false);
  781. end;
  782. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  783. function TutlListBase.GetReverseEnumerator: TEnumerator;
  784. begin
  785. result := TEnumerator.Create(fList, true);
  786. end;
  787. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  788. procedure TutlListBase.ForEach(const aEvent: TItemEvent);
  789. var i: Integer;
  790. begin
  791. if not Assigned(aEvent) then
  792. for i := 0 to fList.Count-1 do
  793. aEvent(self, i, PListItem(fList[i])^.data);
  794. end;
  795. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  796. procedure TutlListBase.Clear;
  797. begin
  798. while (fList.Count > 0) do
  799. DeleteIntern(fList.Count-1);
  800. end;
  801. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  802. constructor TutlListBase.Create(const aOwnsObjects: Boolean);
  803. begin
  804. inherited Create;
  805. fOwnsObjects := aOwnsObjects;
  806. fList := TFPList.Create;
  807. end;
  808. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  809. destructor TutlListBase.Destroy;
  810. begin
  811. Clear;
  812. FreeAndNil(fList);
  813. inherited Destroy;
  814. end;
  815. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  816. //TutlSimpleList////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  817. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  818. function TutlSimpleList.Split(aComparer: IComparer; const aDirection: TSortDirection; const aLeft, aRight: Integer): Integer;
  819. var
  820. i, j: Integer;
  821. pivot: T;
  822. begin
  823. i := aLeft;
  824. j := aRight - 1;
  825. pivot := GetItem(aRight);
  826. repeat
  827. while ((aDirection = sdAscending) and (aComparer.Compare(GetItem(i), pivot) <= 0) or
  828. (aDirection = sdDescending) and (aComparer.Compare(GetItem(i), pivot) >= 0)) and
  829. (i < aRight) do inc(i);
  830. while ((aDirection = sdAscending) and (aComparer.Compare(GetItem(j), pivot) >= 0) or
  831. (aDirection = sdDescending) and (aComparer.Compare(GetItem(j), pivot) <= 0)) and
  832. (j > aLeft) do dec(j);
  833. if (i < j) then
  834. Exchange(i, j);
  835. until (i >= j);
  836. if ((aDirection = sdAscending) and (aComparer.Compare(GetItem(i), pivot) > 0)) or
  837. ((aDirection = sdDescending) and (aComparer.Compare(GetItem(i), pivot) < 0)) then
  838. Exchange(i, aRight);
  839. result := i;
  840. end;
  841. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  842. procedure TutlSimpleList.QuickSort(aComparer: IComparer; const aDirection: TSortDirection; const aLeft, aRight: Integer);
  843. var
  844. s: Integer;
  845. begin
  846. if (aLeft < aRight) then begin
  847. s := Split(aComparer, aDirection, aLeft, aRight);
  848. QuickSort(aComparer, aDirection, aLeft, s - 1);
  849. QuickSort(aComparer, aDirection, s + 1, aRight);
  850. end;
  851. end;
  852. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  853. function TutlSimpleList.Add(const aItem: T): Integer;
  854. begin
  855. result := Count;
  856. InsertIntern(result, aItem);
  857. end;
  858. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  859. procedure TutlSimpleList.Insert(const aIndex: Integer; const aItem: T);
  860. begin
  861. InsertIntern(aIndex, aItem);
  862. end;
  863. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  864. procedure TutlSimpleList.Exchange(const aIndex1, aIndex2: Integer);
  865. begin
  866. if (aIndex1 < 0) or (aIndex1 >= Count) then
  867. raise EOutOfRange.Create(aIndex1, 0, Count-1);
  868. if (aIndex2 < 0) or (aIndex2 >= Count) then
  869. raise EOutOfRange.Create(aIndex2, 0, Count-1);
  870. fList.Exchange(aIndex1, aIndex2);
  871. end;
  872. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  873. procedure TutlSimpleList.Move(const aCurIndex, aNewIndex: Integer);
  874. begin
  875. if (aCurIndex < 0) or (aCurIndex >= Count) then
  876. raise EOutOfRange.Create(aCurIndex, 0, Count-1);
  877. if (aNewIndex < 0) or (aNewIndex >= Count) then
  878. raise EOutOfRange.Create(aNewIndex, 0, Count-1);
  879. fList.Move(aCurIndex, aNewIndex);
  880. end;
  881. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  882. procedure TutlSimpleList.Sort(aComparer: IComparer; const aDirection: TSortDirection);
  883. begin
  884. QuickSort(aComparer, aDirection, 0, fList.Count-1);
  885. end;
  886. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  887. procedure TutlSimpleList.Delete(const aIndex: Integer);
  888. begin
  889. DeleteIntern(aIndex);
  890. end;
  891. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  892. function TutlSimpleList.First: T;
  893. begin
  894. result := Items[0];
  895. end;
  896. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  897. procedure TutlSimpleList.PushFirst(const aItem: T);
  898. begin
  899. InsertIntern(0, aItem);
  900. end;
  901. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  902. function TutlSimpleList.PopFirst(const aFreeItem: Boolean): T;
  903. begin
  904. if aFreeItem then
  905. FillByte(result{%H-}, SizeOf(result), 0)
  906. else
  907. result := First;
  908. DeleteIntern(0, aFreeItem);
  909. end;
  910. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  911. function TutlSimpleList.Last: T;
  912. begin
  913. result := Items[Count-1];
  914. end;
  915. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  916. procedure TutlSimpleList.PushLast(const aItem: T);
  917. begin
  918. InsertIntern(Count, aItem);
  919. end;
  920. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  921. function TutlSimpleList.PopLast(const aFreeItem: Boolean): T;
  922. begin
  923. if aFreeItem then
  924. FillByte(result{%H-}, SizeOf(result), 0)
  925. else
  926. result := Last;
  927. DeleteIntern(Count-1, aFreeItem);
  928. end;
  929. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  930. //TutlCustomList////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  931. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  932. function TutlCustomList.IndexOf(const aItem: T): Integer;
  933. var
  934. c: Integer;
  935. begin
  936. c := List.Count;
  937. result := 0;
  938. while (result < c) and
  939. not fEqualityComparer.EqualityCompare(PListItem(List[result])^.data, aItem) do
  940. inc(result);
  941. if (result >= c) then
  942. result := -1;
  943. end;
  944. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  945. function TutlCustomList.Extract(const aItem: T; const aDefault: T): T;
  946. var
  947. i: Integer;
  948. begin
  949. i := IndexOf(aItem);
  950. if (i >= 0) then begin
  951. result := Items[i];
  952. DeleteIntern(i, false);
  953. end else
  954. result := aDefault;
  955. end;
  956. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  957. function TutlCustomList.Remove(const aItem: T): Integer;
  958. begin
  959. result := IndexOf(aItem);
  960. if (result >= 0) then
  961. DeleteIntern(result);
  962. end;
  963. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  964. constructor TutlCustomList.Create(aEqualityComparer: IEqualityComparer; const aOwnsObjects: Boolean);
  965. begin
  966. inherited Create(aOwnsObjects);
  967. fEqualityComparer := aEqualityComparer;
  968. end;
  969. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  970. destructor TutlCustomList.Destroy;
  971. begin
  972. fEqualityComparer := nil;
  973. inherited Destroy;
  974. end;
  975. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  976. //TutlList//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  977. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  978. constructor TutlList.Create(const aOwnsObjects: Boolean);
  979. begin
  980. inherited Create(TEqualityComparer.Create, aOwnsObjects);
  981. end;
  982. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  983. //TutlHashSetBase///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  984. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  985. function TutlHashSetBase.SearchItem(const aMin, aMax: Integer; const aItem: T; out aIndex: Integer): Integer;
  986. var
  987. i, cmp: Integer;
  988. begin
  989. if (aMin <= aMax) then begin
  990. i := aMin + Trunc((aMax - aMin) / 2);
  991. cmp := fComparer.Compare(aItem, GetItem(i));
  992. if (cmp = 0) then
  993. result := i
  994. else if (cmp < 0) then
  995. result := SearchItem(aMin, i-1, aItem, aIndex)
  996. else if (cmp > 0) then
  997. result := SearchItem(i+1, aMax, aItem, aIndex);
  998. end else begin
  999. result := -1;
  1000. aIndex := aMin;
  1001. end;
  1002. end;
  1003. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1004. procedure TutlHashSetBase.ForEach(const aEvent: THashItemEvent);
  1005. var item: T;
  1006. begin
  1007. if Assigned(aEvent) then
  1008. for item in self do
  1009. aEvent(self, item);
  1010. end;
  1011. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1012. constructor TutlHashSetBase.Create(aComparer: IComparer; const aOwnsObjects: Boolean);
  1013. begin
  1014. inherited Create(aOwnsObjects);
  1015. fComparer := aComparer;
  1016. end;
  1017. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1018. destructor TutlHashSetBase.Destroy;
  1019. begin
  1020. fComparer := nil;
  1021. inherited Destroy;
  1022. end;
  1023. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1024. //TutlCustomHashSet/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1025. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1026. function TutlCustomHashSet.Add(const aItem: T): Boolean;
  1027. var
  1028. i: Integer;
  1029. begin
  1030. result := (SearchItem(0, List.Count-1, aItem, i) < 0);
  1031. if result then
  1032. InsertIntern(i, aItem);
  1033. end;
  1034. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1035. function TutlCustomHashSet.Contains(const aItem: T): Boolean;
  1036. var
  1037. tmp: Integer;
  1038. begin
  1039. result := (SearchItem(0, List.Count-1, aItem, tmp) >= 0);
  1040. end;
  1041. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1042. function TutlCustomHashSet.IndexOf(const aItem: T): Integer;
  1043. var
  1044. tmp: Integer;
  1045. begin
  1046. result := SearchItem(0, List.Count-1, aItem, tmp);
  1047. end;
  1048. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1049. function TutlCustomHashSet.Remove(const aItem: T): Boolean;
  1050. var
  1051. i, tmp: Integer;
  1052. begin
  1053. i := SearchItem(0, List.Count-1, aItem, tmp);
  1054. result := (i >= 0);
  1055. if result then
  1056. DeleteIntern(i);
  1057. end;
  1058. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1059. procedure TutlCustomHashSet.Delete(const aIndex: Integer);
  1060. begin
  1061. DeleteIntern(aIndex);
  1062. end;
  1063. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1064. //TutlHashSet///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1065. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1066. constructor TutlHashSet.Create(const aOwnsObjects: Boolean);
  1067. begin
  1068. inherited Create(TComparer.Create, aOwnsObjects);
  1069. end;
  1070. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1071. //TutlMapBase.THashSet//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1072. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1073. procedure TutlMapBase.THashSet.DestroyItem(const aItem: PListItem; const aFreeItem: Boolean);
  1074. begin
  1075. // never free objects used as keys, but do finalize strings, interfaces etc.
  1076. utlFreeOrFinalize(aItem^.data.key, TypeInfo(aItem^.data.key), false);
  1077. utlFreeOrFinalize(aItem^.data.value, TypeInfo(aItem^.data.value), aFreeItem and OwnsObjects);
  1078. inherited DestroyItem(aItem, aFreeItem);
  1079. end;
  1080. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1081. //TutlMapBase.TKeyValuePairComparer/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1082. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1083. function TutlMapBase.TKeyValuePairComparer.Compare(const i1, i2: TKeyValuePair): Integer;
  1084. begin
  1085. result := fComparer.Compare(i1.Key, i2.Key);
  1086. end;
  1087. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1088. constructor TutlMapBase.TKeyValuePairComparer.Create(aComparer: IComparer);
  1089. begin
  1090. inherited Create;
  1091. fComparer := aComparer;
  1092. end;
  1093. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1094. destructor TutlMapBase.TKeyValuePairComparer.Destroy;
  1095. begin
  1096. fComparer := nil;
  1097. inherited Destroy;
  1098. end;
  1099. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1100. //TutlMapBase.TEnumeratorProxy//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1101. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1102. function TutlMapBase.TEnumeratorProxy.MoveNext: Boolean;
  1103. begin
  1104. result := fEnumerator.MoveNext;
  1105. end;
  1106. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1107. constructor TutlMapBase.TEnumeratorProxy.Create(const aEnumerator: THashSet.TEnumerator);
  1108. begin
  1109. inherited Create;
  1110. fEnumerator := aEnumerator;
  1111. end;
  1112. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1113. destructor TutlMapBase.TEnumeratorProxy.Destroy;
  1114. begin
  1115. FreeAndNil(fEnumerator);
  1116. inherited Destroy;
  1117. end;
  1118. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1119. //TutlMapBase.TValueEnumerator//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1120. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1121. function TutlMapBase.TValueEnumerator.GetCurrent: TValue;
  1122. begin
  1123. result := fEnumerator.GetCurrent.Value;
  1124. end;
  1125. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1126. function TutlMapBase.TValueEnumerator.GetEnumerator: TValueEnumerator;
  1127. begin
  1128. result := self;
  1129. end;
  1130. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1131. //TutlMapBase.TKeyEnumerator////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1132. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1133. function TutlMapBase.TKeyEnumerator.GetCurrent: TKey;
  1134. begin
  1135. result := fEnumerator.GetCurrent.Key;
  1136. end;
  1137. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1138. function TutlMapBase.TKeyEnumerator.GetEnumerator: TKeyEnumerator;
  1139. begin
  1140. result := self;
  1141. end;
  1142. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1143. //TutlMapBase.TKeyWrapper///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1144. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1145. function TutlMapBase.TKeyWrapper.GetItem(const aIndex: Integer): TKey;
  1146. begin
  1147. result := fHashSet[aIndex].Key;
  1148. end;
  1149. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1150. function TutlMapBase.TKeyWrapper.GetCount: Integer;
  1151. begin
  1152. result := fHashSet.Count;
  1153. end;
  1154. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1155. function TutlMapBase.TKeyWrapper.GetEnumerator: TKeyEnumerator;
  1156. begin
  1157. result := TKeyEnumerator.Create(fHashSet.GetEnumerator);
  1158. end;
  1159. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1160. function TutlMapBase.TKeyWrapper.GetReverseEnumerator: TKeyEnumerator;
  1161. begin
  1162. result := TKeyEnumerator.Create(fHashSet.GetReverseEnumerator);
  1163. end;
  1164. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1165. constructor TutlMapBase.TKeyWrapper.Create(const aHashSet: THashSet);
  1166. begin
  1167. inherited Create;
  1168. fHashSet := aHashSet;
  1169. end;
  1170. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1171. //TutlMapBase.TKeyValuePairWrapper//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1172. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1173. function TutlMapBase.TKeyValuePairWrapper.GetItem(const aIndex: Integer): TKeyValuePair;
  1174. begin
  1175. result := fHashSet[aIndex];
  1176. end;
  1177. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1178. function TutlMapBase.TKeyValuePairWrapper.GetCount: Integer;
  1179. begin
  1180. result := fHashSet.Count;
  1181. end;
  1182. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1183. function TutlMapBase.TKeyValuePairWrapper.GetEnumerator: THashSet.TEnumerator;
  1184. begin
  1185. result := fHashSet.GetEnumerator;
  1186. end;
  1187. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1188. function TutlMapBase.TKeyValuePairWrapper.GetReverseEnumerator: THashSet.TEnumerator;
  1189. begin
  1190. result := fHashSet.GetReverseEnumerator;
  1191. end;
  1192. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1193. constructor TutlMapBase.TKeyValuePairWrapper.Create(const aHashSet: THashSet);
  1194. begin
  1195. inherited Create;
  1196. fHashSet := aHashSet;
  1197. end;
  1198. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1199. //TutlMapBase///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1200. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1201. function TutlMapBase.GetValues(const aKey: TKey): TValue;
  1202. var
  1203. i: Integer;
  1204. kvp: TKeyValuePair;
  1205. begin
  1206. kvp.Key := aKey;
  1207. i := fHashSetRef.IndexOf(kvp);
  1208. if (i < 0) then
  1209. FillByte(result{%H-}, SizeOf(result), 0)
  1210. else
  1211. result := fHashSetRef[i].Value;
  1212. end;
  1213. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1214. function TutlMapBase.GetValueAt(const aIndex: Integer): TValue;
  1215. begin
  1216. result := fHashSetRef[aIndex].Value;
  1217. end;
  1218. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1219. function TutlMapBase.GetCount: Integer;
  1220. begin
  1221. result := fHashSetRef.Count;
  1222. end;
  1223. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1224. procedure TutlMapBase.SetValues(const aKey: TKey; aValue: TValue);
  1225. var
  1226. i: Integer;
  1227. kvp: TKeyValuePair;
  1228. begin
  1229. kvp.Key := aKey;
  1230. kvp.Value := aValue;
  1231. i := fHashSetRef.IndexOf(kvp);
  1232. if (i < 0) then
  1233. raise EutlMap.Create('key not found');
  1234. fHashSetRef[i] := kvp;
  1235. end;
  1236. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1237. procedure TutlMapBase.SetValueAt(const aIndex: Integer; aValue: TValue);
  1238. var
  1239. kvp: TKeyValuePair;
  1240. begin
  1241. kvp := fHashSetRef[aIndex];
  1242. kvp.Value := aValue;
  1243. fHashSetRef[aIndex] := kvp;
  1244. end;
  1245. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1246. procedure TutlMapBase.Add(const aKey: TKey; const aValue: TValue);
  1247. var
  1248. kvp: TKeyValuePair;
  1249. begin
  1250. kvp.Key := aKey;
  1251. kvp.Value := aValue;
  1252. if not fHashSetRef.Add(kvp) then
  1253. raise EutlMapKeyAlreadyExists.Create();
  1254. end;
  1255. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1256. function TutlMapBase.IndexOf(const aKey: TKey): Integer;
  1257. var
  1258. kvp: TKeyValuePair;
  1259. begin
  1260. kvp.Key := aKey;
  1261. result := fHashSetRef.IndexOf(kvp);
  1262. end;
  1263. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1264. function TutlMapBase.Contains(const aKey: TKey): Boolean;
  1265. var
  1266. kvp: TKeyValuePair;
  1267. begin
  1268. kvp.Key := aKey;
  1269. result := (fHashSetRef.IndexOf(kvp) >= 0);
  1270. end;
  1271. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1272. procedure TutlMapBase.Delete(const aKey: TKey);
  1273. var
  1274. kvp: TKeyValuePair;
  1275. begin
  1276. kvp.Key := aKey;
  1277. if not fHashSetRef.Remove(kvp) then
  1278. raise EutlMapKeyNotFound.Create;
  1279. end;
  1280. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1281. procedure TutlMapBase.DeleteAt(const aIndex: Integer);
  1282. begin
  1283. fHashSetRef.Delete(aIndex);
  1284. end;
  1285. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1286. procedure TutlMapBase.Clear;
  1287. begin
  1288. fHashSetRef.Clear;
  1289. end;
  1290. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1291. procedure TutlMapBase.ForEach(const aEvent: TKeyValuePairEvent);
  1292. var kvp: TKeyValuePair;
  1293. begin
  1294. if Assigned(aEvent) then
  1295. for kvp in fHashSetRef do
  1296. aEvent(self, kvp.Key, kvp.Value);
  1297. end;
  1298. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1299. function TutlMapBase.GetEnumerator: TValueEnumerator;
  1300. begin
  1301. result := TValueEnumerator.Create(fHashSetRef.GetEnumerator);
  1302. end;
  1303. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1304. function TutlMapBase.GetReverseEnumerator: TValueEnumerator;
  1305. begin
  1306. result := TValueEnumerator.Create(fHashSetRef.GetReverseEnumerator);
  1307. end;
  1308. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1309. constructor TutlMapBase.Create(const aHashSet: THashSet);
  1310. begin
  1311. inherited Create;
  1312. fHashSetRef := aHashSet;
  1313. fKeyWrapper := TKeyWrapper.Create(fHashSetRef);
  1314. fKeyValuePairWrapper := TKeyValuePairWrapper.Create(fHashSetRef);
  1315. end;
  1316. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1317. destructor TutlMapBase.Destroy;
  1318. begin
  1319. FreeAndNil(fKeyValuePairWrapper);
  1320. FreeAndNil(fKeyWrapper);
  1321. fHashSetRef := nil;
  1322. inherited Destroy;
  1323. end;
  1324. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1325. //TutlMap///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1326. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1327. constructor TutlMap.Create(const aOwnsObjects: Boolean);
  1328. begin
  1329. inherited Create(TComparer.Create, aOwnsObjects);
  1330. end;
  1331. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1332. //TutlQueue/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1333. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1334. function TutlQueue.GetCount: Integer;
  1335. begin
  1336. InterLockedExchange(result{%H-}, fCount);
  1337. end;
  1338. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1339. procedure TutlQueue.Push(const aItem: T);
  1340. var
  1341. p: PListItem;
  1342. begin
  1343. new(p);
  1344. p^.data := aItem;
  1345. p^.next := nil;
  1346. fLast^.next := p;
  1347. fLast := fLast^.next;
  1348. InterLockedIncrement(fCount);
  1349. end;
  1350. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1351. function TutlQueue.Pop(out aItem: T): Boolean;
  1352. var
  1353. old: PListItem;
  1354. begin
  1355. result := false;
  1356. FillByte(aItem{%H-}, SizeOf(aItem), 0);
  1357. if (Count <= 0) then
  1358. exit;
  1359. result := true;
  1360. old := fFirst;
  1361. fFirst := fFirst^.next;
  1362. aItem := fFirst^.data;
  1363. InterLockedDecrement(fCount);
  1364. Dispose(old);
  1365. end;
  1366. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1367. function TutlQueue.Pop: Boolean;
  1368. var
  1369. tmp: T;
  1370. begin
  1371. result := Pop(tmp);
  1372. utlFreeOrFinalize(tmp, TypeInfo(tmp), fOwnsObjects);
  1373. end;
  1374. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1375. procedure TutlQueue.Clear;
  1376. begin
  1377. while Pop do;
  1378. end;
  1379. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1380. constructor TutlQueue.Create(const aOwnsObjects: Boolean);
  1381. begin
  1382. inherited Create;
  1383. new(fFirst);
  1384. FillByte(fFirst^, SizeOf(fFirst^), 0);
  1385. fLast := fFirst;
  1386. fCount := 0;
  1387. fOwnsObjects := aOwnsObjects;
  1388. end;
  1389. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1390. destructor TutlQueue.Destroy;
  1391. begin
  1392. Clear;
  1393. if Assigned(fLast) then begin
  1394. Dispose(fLast);
  1395. fLast := nil;
  1396. end;
  1397. inherited Destroy;
  1398. end;
  1399. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1400. //TutlSyncQueue/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1401. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1402. procedure TutlSyncQueue.Push(const aItem: T);
  1403. begin
  1404. fPushLock.Enter;
  1405. try
  1406. inherited Push(aItem);
  1407. finally
  1408. fPushLock.Leave;
  1409. end;
  1410. end;
  1411. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1412. function TutlSyncQueue.Pop(out aItem: T): Boolean;
  1413. begin
  1414. fPopLock.Enter;
  1415. try
  1416. result := inherited Pop(aItem);
  1417. finally
  1418. fPopLock.Leave;
  1419. end;
  1420. end;
  1421. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1422. constructor TutlSyncQueue.Create(const aOwnsObjects: Boolean);
  1423. begin
  1424. inherited Create(aOwnsObjects);
  1425. fPushLock := TutlSpinLock.Create;
  1426. fPopLock := TutlSpinLock.Create;
  1427. end;
  1428. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1429. destructor TutlSyncQueue.Destroy;
  1430. begin
  1431. inherited Destroy; //inherited will pop all remaining items, so do not destroy spinlock before!
  1432. FreeAndNil(fPushLock);
  1433. FreeAndNil(fPopLock);
  1434. end;
  1435. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1436. //TutlInterfaceList.TInterfaceEnumerator////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1437. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1438. function TutlInterfaceList.TInterfaceEnumerator.GetCurrent: T;
  1439. begin
  1440. result := T(fList[fPos]);
  1441. end;
  1442. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1443. function TutlInterfaceList.TInterfaceEnumerator.MoveNext: Boolean;
  1444. begin
  1445. inc(fPos);
  1446. result := (fPos < fList.Count);
  1447. end;
  1448. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1449. constructor TutlInterfaceList.TInterfaceEnumerator.Create(const aList: TInterfaceList);
  1450. begin
  1451. inherited Create;
  1452. fPos := -1;
  1453. fList := aList;
  1454. end;
  1455. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1456. //TutlInterfaceList/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1457. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1458. function TutlInterfaceList.Get(i : Integer): T;
  1459. begin
  1460. result := T(inherited Get(i));
  1461. end;
  1462. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1463. procedure TutlInterfaceList.Put(i : Integer; aItem : T);
  1464. begin
  1465. inherited Put(i, aItem);
  1466. end;
  1467. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1468. function TutlInterfaceList.First: T;
  1469. begin
  1470. result := T(inherited First);
  1471. end;
  1472. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1473. function TutlInterfaceList.IndexOf(aItem : T): Integer;
  1474. begin
  1475. result := inherited IndexOf(aItem);
  1476. end;
  1477. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1478. function TutlInterfaceList.Add(aItem : IUnknown): Integer;
  1479. begin
  1480. result := inherited Add(aItem);
  1481. end;
  1482. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1483. procedure TutlInterfaceList.Insert(i : Integer; aItem : T);
  1484. begin
  1485. inherited Insert(i, aItem);
  1486. end;
  1487. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1488. function TutlInterfaceList.Last : T;
  1489. begin
  1490. result := T(inherited Last);
  1491. end;
  1492. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1493. function TutlInterfaceList.Remove(aItem : T): Integer;
  1494. begin
  1495. result := inherited Remove(aItem);
  1496. end;
  1497. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1498. function TutlInterfaceList.GetEnumerator: TInterfaceEnumerator;
  1499. begin
  1500. result := TInterfaceEnumerator.Create(self);
  1501. end;
  1502. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1503. //TutlEnumHelper////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1504. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1505. class constructor TutlEnumHelper.Initialize;
  1506. var
  1507. tiArray: PTypeInfo;
  1508. tdArray, tdEnum: PTypeData;
  1509. aName: PShortString;
  1510. i: integer;
  1511. en: T;
  1512. begin
  1513. {
  1514. See FPC Bug http://bugs.freepascal.org/view.php?id=27622
  1515. For Sparse Enums, the compiler won't give us TypeInfo, because it contains some wrong data. This is
  1516. safe, but sadly we don't even get the *correct* fields (TypeName, NameList), even though they are
  1517. generated in any case.
  1518. Fortunately, arrays do know this type info segment as their Element Type (and we declared one anyway).
  1519. }
  1520. tiArray := System.TypeInfo(TValueArray);
  1521. tdArray := GetTypeData(tiArray);
  1522. FTypeInfo:= tdArray^.elType2;
  1523. {
  1524. Now that we have the TypeInfo, fill our values from it. This is safe because while the *values* in
  1525. TypeData are wrong for Sparse Enums, the *names* are always correct.
  1526. }
  1527. tdEnum:= GetTypeData(FTypeInfo);
  1528. aName:= @tdEnum^.NameList;
  1529. SetLength(FValues, 0);
  1530. i:= 0;
  1531. While Length(aName^) > 0 do begin
  1532. SetLength(FValues, i+1);
  1533. {
  1534. Memory layout for TTypeData has the declaring EnumUnitName after the last NameList entry.
  1535. This can normally not be the same as a valid enum value, because it is in the same identifier
  1536. namespace. However, with scoped enums we might have the same name for module and element, because
  1537. the full identifier for the element would be TypeName.ElementName.
  1538. In either case, the next PShortString will point to a zero-length string, and the loop is left
  1539. with the last element being invalid (either empty or whatever value the unit-named element has).
  1540. }
  1541. if TryToEnum(aName^, en) then
  1542. FValues[i]:= en;
  1543. inc(i);
  1544. inc(PByte(aName), Length(aName^) + 1);
  1545. end;
  1546. // remove the EnumUnitName item
  1547. SetLength(FValues, Length(FValues) - 1);
  1548. end;
  1549. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1550. class function TutlEnumHelper.ToString(aValue: T): String;
  1551. begin
  1552. {$Push}
  1553. {$IOChecks OFF}
  1554. WriteStr(Result, aValue);
  1555. if IOResult = 107 then
  1556. Result:= '';
  1557. {$Pop}
  1558. end;
  1559. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1560. class function TutlEnumHelper.TryToEnum(aStr: String; out aValue: T): Boolean;
  1561. var
  1562. a: T;
  1563. begin
  1564. a := T(0);
  1565. Result := false;
  1566. if Length(aStr) = 0 then
  1567. exit;
  1568. {$Push}
  1569. {$IOChecks OFF}
  1570. ReadStr(aStr, a);
  1571. Result:= IOResult <> 106;
  1572. {$Pop}
  1573. if Result then
  1574. aValue := a;
  1575. end;
  1576. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1577. class function TutlEnumHelper.ToEnum(aStr: String): T;
  1578. begin
  1579. if not TryToEnum(aStr, result) then
  1580. raise EutlEnumConvert.Create(aStr, TypeInfo^.Name);
  1581. end;
  1582. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1583. class function TutlEnumHelper.ToEnum(aStr: String; const aDefault: T): T;
  1584. begin
  1585. if not TryToEnum(aStr, result) then
  1586. result := aDefault;
  1587. end;
  1588. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1589. class function TutlEnumHelper.Values: TValueArray;
  1590. begin
  1591. Result:= FValues;
  1592. end;
  1593. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1594. class function TutlEnumHelper.TypeInfo: PTypeInfo;
  1595. begin
  1596. Result:= FTypeInfo;
  1597. end;
  1598. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1599. //TutlRingBuffer////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1600. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1601. constructor TutlRingBuffer.Create(const Elements: Integer);
  1602. begin
  1603. inherited Create;
  1604. fAborted:= false;
  1605. fDataLen:= Elements;
  1606. fDataSize:= SizeOf(T);
  1607. SetLength(fData, fDataLen);
  1608. fWritePtr:= 1;
  1609. fReadPtr:= 0;
  1610. fFillState:= 0;
  1611. fReadEvent:= TutlAutoResetEvent.Create;
  1612. fWrittenEvent:= TutlAutoResetEvent.Create;
  1613. end;
  1614. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1615. destructor TutlRingBuffer.Destroy;
  1616. begin
  1617. BreakPipe;
  1618. FreeAndNil(fReadEvent);
  1619. FreeAndNil(fWrittenEvent);
  1620. SetLength(fData, 0);
  1621. inherited Destroy;
  1622. end;
  1623. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1624. function TutlRingBuffer.Read(Buf: Pointer; Items: integer; BlockUntilAvail: boolean): integer;
  1625. var
  1626. wp, c, r: Integer;
  1627. begin
  1628. Result:= 0;
  1629. while Items > 0 do begin
  1630. if fAborted then
  1631. exit;
  1632. InterLockedExchange(wp{%H-}, fWritePtr);
  1633. r:= (fReadPtr + 1) mod fDataLen;
  1634. if wp < r then
  1635. wp:= fDataLen;
  1636. c:= wp - r;
  1637. if c > Items then
  1638. c:= Items;
  1639. if c > 0 then begin
  1640. Move(fData[r], Buf^, c * fDataSize);
  1641. Dec(Items, c);
  1642. inc(Result, c);
  1643. dec(fFillState, c);
  1644. inc(PByte(Buf), c * fDataSize);
  1645. InterLockedExchange(fReadPtr, (fReadPtr + c) mod fDataLen);
  1646. fReadEvent.SetEvent;
  1647. end else begin
  1648. if not BlockUntilAvail then
  1649. break;
  1650. fWrittenEvent.WaitFor(INFINITE);
  1651. end;
  1652. end;
  1653. end;
  1654. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1655. function TutlRingBuffer.Write(Buf: Pointer; Items: integer; BlockUntilDone: boolean): integer;
  1656. var
  1657. rp, c: integer;
  1658. begin
  1659. Result:= 0;
  1660. while Items > 0 do begin
  1661. if fAborted then
  1662. exit;
  1663. InterLockedExchange(rp{%H-}, fReadPtr);
  1664. if rp < fWritePtr then
  1665. rp:= fDataLen;
  1666. c:= rp - fWritePtr;
  1667. if c > Items then
  1668. c:= Items;
  1669. if c > 0 then begin
  1670. Move(Buf^, fData[fWritePtr], c * fDataSize);
  1671. dec(Items, c);
  1672. inc(Result, c);
  1673. inc(fFillState, c);
  1674. inc(PByte(Buf), c * fDataSize);
  1675. InterLockedExchange(fWritePtr, (fWritePtr + c) mod fDataLen);
  1676. fWrittenEvent.SetEvent;
  1677. end else begin
  1678. if not BlockUntilDone then
  1679. Break;
  1680. fReadEvent.WaitFor(INFINITE);
  1681. end;
  1682. end;
  1683. end;
  1684. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1685. procedure TutlRingBuffer.BreakPipe;
  1686. begin
  1687. fAborted:= true;
  1688. fWrittenEvent.SetEvent;
  1689. fReadEvent.SetEvent;
  1690. end;
  1691. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1692. //TutlPagedDataFiFo.TDataProvider///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1693. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1694. function TutlPagedDataFiFo.TDataProvider.Give(const aBuffer: PData; aCount: Integer): Integer;
  1695. begin
  1696. result := 0;
  1697. if (aCount > fCount - fPos) then
  1698. aCount := fCount - fPos;
  1699. if (aCount <= 0) then
  1700. exit;
  1701. Move((fData + fPos)^, aBuffer^, aCount * SizeOf(TData));
  1702. inc(fPos, aCount);
  1703. result := aCount;
  1704. end;
  1705. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1706. constructor TutlPagedDataFiFo.TDataProvider.Create(const aData: PData; const aCount: Integer);
  1707. begin
  1708. inherited Create;
  1709. fData := aData;
  1710. fCount := aCount;
  1711. fPos := 0;
  1712. end;
  1713. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1714. //TutlPagedDataFiFo.TDataConsumer///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1715. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1716. function TutlPagedDataFiFo.TDataConsumer.Take(const aBuffer: PData; aCount: Integer): Integer;
  1717. begin
  1718. result := 0;
  1719. if (aCount > fCount - fPos) then
  1720. aCount := fCount - fPos;
  1721. if (aCount <= 0) then
  1722. exit;
  1723. Move(aBuffer^, (fData + fPos)^, aCount * SizeOf(TData));
  1724. inc(fPos, aCount);
  1725. result := aCount;
  1726. end;
  1727. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1728. constructor TutlPagedDataFiFo.TDataConsumer.Create(const aData: PData; const aCount: Integer);
  1729. begin
  1730. inherited Create;
  1731. fData := aData;
  1732. fCount := aCount;
  1733. fPos := 0;
  1734. end;
  1735. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1736. //TutlPagedDataFiFo.TNestedDataProvider/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1737. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1738. function TutlPagedDataFiFo.TNestedDataProvider.Give(const aBuffer: PData; aCount: Integer): Integer;
  1739. begin
  1740. result := fCallback(aBuffer, aCount);
  1741. end;
  1742. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1743. constructor TutlPagedDataFiFo.TNestedDataProvider.Create(const aCallback: TDataCallback);
  1744. begin
  1745. inherited Create;
  1746. fCallback := aCallback;
  1747. end;
  1748. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1749. //TutlPagedDataFiFo.TNestedDataConsumer/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1750. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1751. function TutlPagedDataFiFo.TNestedDataConsumer.Take(const aBuffer: PData; aCount: Integer): Integer;
  1752. begin
  1753. result := fCallback(aBuffer, aCount);
  1754. end;
  1755. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1756. constructor TutlPagedDataFiFo.TNestedDataConsumer.Create(const aCallback: TDataCallback);
  1757. begin
  1758. inherited Create;
  1759. fCallback := aCallback;
  1760. end;
  1761. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1762. //TutlPagedDataFiFo.TStreamDataProvider/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1763. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1764. function TutlPagedDataFiFo.TStreamDataProvider.Give(const aBuffer: PData; aCount: Integer): Integer;
  1765. begin
  1766. result := fStream.Read(aBuffer^, aCount);
  1767. end;
  1768. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1769. constructor TutlPagedDataFiFo.TStreamDataProvider.Create(const aStream: TStream);
  1770. begin
  1771. inherited Create;
  1772. fStream := aStream;
  1773. end;
  1774. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1775. //TutlPagedDataFiFo.TStreamDataConsumer/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1776. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1777. function TutlPagedDataFiFo.TStreamDataConsumer.Take(const aBuffer: PData; aCount: Integer): Integer;
  1778. begin
  1779. result := fStream.Write(aBuffer^, aCount);
  1780. end;
  1781. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1782. constructor TutlPagedDataFiFo.TStreamDataConsumer.Create(const aStream: TStream);
  1783. begin
  1784. inherited Create;
  1785. fStream := aStream;
  1786. end;
  1787. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1788. //TutlPagedDataFiFo/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1789. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1790. function TutlPagedDataFiFo.WriteIntern(const aProvider: IDataProvider; aCount: Integer): Integer;
  1791. var
  1792. c, r: Integer;
  1793. p: PPage;
  1794. begin
  1795. if not Assigned(aProvider) then
  1796. raise EArgumentNil.Create('aProvider');
  1797. result := 0;
  1798. while (aCount > 0) do begin
  1799. if not Assigned(fWritePage) or (fWritePage^.WritePos >= fPageSize) then begin
  1800. new(p);
  1801. p^.ReadPos := 0;
  1802. p^.WritePos := 0;
  1803. p^.Next := nil;
  1804. SetLength(p^.Data, fPageSize);
  1805. if Assigned(fWritePage) then
  1806. fWritePage^.Next := p;
  1807. fWritePage := p;
  1808. if not Assigned(fReadPage) then
  1809. fReadPage := fWritePage;
  1810. end;
  1811. c := fPageSize - fWritePage^.WritePos;
  1812. if (c > aCount) then
  1813. c := aCount;
  1814. r := aProvider.Give(@fWritePage^.Data[fWritePage^.WritePos], c);
  1815. if (r = 0) then
  1816. exit;
  1817. inc(result, r);
  1818. inc(fWritePage^.WritePos, r);
  1819. inc(fSize, r);
  1820. dec(aCount, r);
  1821. end;
  1822. end;
  1823. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1824. function TutlPagedDataFiFo.ReadIntern(const aConsumer: IDataConsumer; aCount: Integer; const aMoveReadPos: Boolean): Integer;
  1825. var
  1826. ReadPage: PPage;
  1827. DummyPage: TPage;
  1828. c, r: Integer;
  1829. begin
  1830. result := 0;
  1831. if not Assigned(fReadPage) then
  1832. exit;
  1833. //init read page
  1834. if not aMoveReadPos then begin
  1835. DummyPage := fReadPage^; // copy page (data is not copied, because it's a dynamic array)
  1836. ReadPage := @DummyPage;
  1837. end else
  1838. ReadPage := fReadPage;
  1839. while (aCount > 0) do begin
  1840. if (ReadPage^.ReadPos >= fPageSize) then begin
  1841. if not Assigned(ReadPage^.Next) then
  1842. exit;
  1843. if aMoveReadPos then begin
  1844. if (fReadPage = fWritePage) then // write finished with page end, so reset WritePage wenn disposing ReadPage
  1845. fWritePage := nil;
  1846. fReadPage := fReadPage^.Next;
  1847. Dispose(ReadPage);
  1848. ReadPage := fReadPage;
  1849. end else
  1850. ReadPage^ := ReadPage^.Next^;
  1851. end;
  1852. c := ReadPage^.WritePos - ReadPage^.ReadPos;
  1853. if (c = 0) then
  1854. exit;
  1855. if (c > aCount) then
  1856. c := aCount;
  1857. if Assigned(aConsumer) then begin
  1858. r := aConsumer.Take(@ReadPage^.Data[ReadPage^.ReadPos], c);
  1859. if (r = 0) then
  1860. exit;
  1861. end else
  1862. r := c;
  1863. inc(result, r);
  1864. inc(ReadPage^.ReadPos, r);
  1865. dec(aCount, r);
  1866. if aMoveReadPos then
  1867. dec(fSize, r);
  1868. end;
  1869. end;
  1870. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1871. function TutlPagedDataFiFo.Write(const aProvider: IDataProvider; const aCount: Integer): Integer;
  1872. begin
  1873. result := WriteIntern(aProvider, aCount);
  1874. end;
  1875. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1876. function TutlPagedDataFiFo.Write(const aData: PData; const aCount: Integer): Integer;
  1877. var
  1878. provider: IDataProvider;
  1879. begin
  1880. provider := TDataProvider.Create(aData, aCount);
  1881. result := WriteIntern(provider, aCount);
  1882. end;
  1883. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1884. function TutlPagedDataFiFo.Read(const aConsumer: IDataConsumer; const aCount: Integer): Integer;
  1885. begin
  1886. result := ReadIntern(aConsumer, aCount, true);
  1887. end;
  1888. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1889. function TutlPagedDataFiFo.Read(const aData: PData; const aCount: Integer): Integer;
  1890. var
  1891. consumer: IDataConsumer;
  1892. begin
  1893. consumer := TDataConsumer.Create(aData, aCount);
  1894. result := ReadIntern(consumer, aCount, true);
  1895. end;
  1896. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1897. function TutlPagedDataFiFo.Peek(const aConsumer: IDataConsumer; const aCount: Integer): Integer;
  1898. begin
  1899. result := ReadIntern(aConsumer, aCount, false);
  1900. end;
  1901. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1902. function TutlPagedDataFiFo.Peek(const aData: PData; const aCount: Integer): Integer;
  1903. var
  1904. consumer: IDataConsumer;
  1905. begin
  1906. consumer := TDataConsumer.Create(aData, aCount);
  1907. result := ReadIntern(consumer, aCount, false);
  1908. end;
  1909. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1910. function TutlPagedDataFiFo.Discard(const aCount: Integer): Integer;
  1911. begin
  1912. result := ReadIntern(nil, aCount, true);
  1913. end;
  1914. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1915. procedure TutlPagedDataFiFo.Clear;
  1916. var
  1917. tmp: PPage;
  1918. begin
  1919. while Assigned(fReadPage) do begin
  1920. tmp := fReadPage;
  1921. fReadPage := tmp^.Next;
  1922. Dispose(tmp);
  1923. end;
  1924. fReadPage := nil;
  1925. fWritePage := nil;
  1926. end;
  1927. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1928. constructor TutlPagedDataFiFo.Create(const aPageSize: Integer);
  1929. begin
  1930. inherited Create;
  1931. fReadPage := nil;
  1932. fWritePage := nil;
  1933. fPageSize := aPageSize;
  1934. end;
  1935. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1936. destructor TutlPagedDataFiFo.Destroy;
  1937. begin
  1938. Clear;
  1939. inherited Destroy;
  1940. end;
  1941. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1942. //TutlSyncPagedDataFiFo/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1943. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1944. function TutlSyncPagedDataFiFo.WriteIntern(const aProvider: IDataProvider; aCount: Integer): Integer;
  1945. begin
  1946. fLock.Enter;
  1947. try
  1948. result := inherited WriteIntern(aProvider, aCount);
  1949. finally
  1950. fLock.Leave;
  1951. end;
  1952. end;
  1953. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1954. function TutlSyncPagedDataFiFo.ReadIntern(const aConsumer: IDataConsumer; aCount: Integer; const aMoveReadPos: Boolean): Integer;
  1955. begin
  1956. fLock.Enter;
  1957. try
  1958. result := inherited ReadIntern(aConsumer, aCount, aMoveReadPos);
  1959. finally
  1960. fLock.Leave;
  1961. end;
  1962. end;
  1963. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1964. constructor TutlSyncPagedDataFiFo.Create(const aPageSize: Integer);
  1965. begin
  1966. inherited Create(aPageSize);
  1967. fLock := TutlSpinLock.Create;
  1968. end;
  1969. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1970. destructor TutlSyncPagedDataFiFo.Destroy;
  1971. begin
  1972. inherited Destroy;
  1973. FreeAndNil(fLock);
  1974. end;
  1975. end.