Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

2093 рядки
85 KiB

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