Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.
 
 

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