Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

2199 lignes
89 KiB

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