25'ten fazla konu seçemezsiniz Konular bir harf veya rakamla başlamalı, kısa çizgiler ('-') içerebilir ve en fazla 35 karakter uzunluğunda olabilir.
 
 

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