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

2049 рядки
81 KiB

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