Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

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