Du kannst nicht mehr als 25 Themen auswählen Themen müssen entweder mit einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

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