25개 이상의 토픽을 선택하실 수 없습니다. Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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