You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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