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

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