Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

516 рядки
20 KiB

  1. unit uutlEnumerator;
  2. {$mode objfpc}{$H+}
  3. interface
  4. uses
  5. Classes, SysUtils,
  6. uutlInterfaces;
  7. type
  8. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  9. generic TutlEnumerator<T> = class(
  10. TInterfacedObject,
  11. specialize IutlEnumerator<T>)
  12. public type
  13. IEnumerator = specialize IutlEnumerator<T>;
  14. IFilter = specialize IutlFilter<T>;
  15. TArray = specialize TGenericArray<T>;
  16. public { IEnumerator }
  17. function GetCurrent: T; virtual; abstract;
  18. function MoveNext: Boolean; virtual; abstract;
  19. procedure Reset; virtual; abstract;
  20. public { IutlEnumerator }
  21. function GetEnumerator: IEnumerator; virtual;
  22. function Count: Integer; virtual;
  23. function Reverse: IEnumerator; virtual;
  24. function Skip (const aCount: Integer): IEnumerator; virtual;
  25. function Take (const aCount: Integer): IEnumerator; virtual;
  26. function Where(const aFilter: IFilter): IEnumerator; virtual;
  27. function ToArray: TArray; virtual;
  28. end;
  29. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  30. generic TutlMemoryEnumerator<T> = class(
  31. specialize TutlEnumerator<T>)
  32. public type
  33. PT = ^T;
  34. strict private
  35. fReverse: Boolean;
  36. fMemory: PT;
  37. fCurrent: Integer;
  38. fCount: Integer;
  39. public { IEnumerator }
  40. function GetCurrent: T; override;
  41. function MoveNext: Boolean; override;
  42. procedure Reset; override;
  43. public { IutlEnumerator }
  44. function Count: Integer; override;
  45. function Reverse: IEnumerator; override;
  46. public
  47. constructor Create(const aMemory: PT; const aCount: Integer); overload;
  48. constructor Create(const aMemory: PT; const aCount: Integer; const aReverse: Boolean); overload;
  49. end;
  50. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  51. generic TutlArrayEnumerator<T> = class(
  52. specialize TutlEnumerator<T>)
  53. strict private
  54. fArray: TArray;
  55. fReverse: Boolean;
  56. fCurrent: Integer;
  57. fFirst: Integer;
  58. fLast: Integer;
  59. public { IEnumerator }
  60. function GetCurrent: T; override;
  61. function MoveNext: Boolean; override;
  62. procedure Reset; override;
  63. public { IutlEnumerator }
  64. function Count: Integer; override;
  65. function Reverse: IEnumerator; override;
  66. function Skip(const aCount: Integer): IEnumerator; override;
  67. function Take(const aCount: Integer): IEnumerator; override;
  68. function ToArray: TArray; override;
  69. public
  70. constructor Create(
  71. const aArray: TArray); overload;
  72. constructor Create(
  73. const aArray: TArray;
  74. const aReverse: Boolean;
  75. const aFirst: Integer;
  76. const aLast: Integer); overload;
  77. end;
  78. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  79. generic TutlSkipTakeEnumerator<T> = class(
  80. specialize TutlEnumerator<T>)
  81. strict private
  82. fEnumerator: IEnumerator;
  83. fSkip: Integer; // greater than 0: skip X; lower than 0: skip none
  84. fTake: Integer; // greater than 0: take X; lower than 0: take all
  85. fCurrentSkip: Integer;
  86. fCurrentTake: Integer;
  87. public { IEnumerator }
  88. function GetCurrent: T; override;
  89. function MoveNext: Boolean; override;
  90. procedure Reset; override;
  91. public
  92. constructor Create(const aEnumerator: IEnumerator; const aSkip: Integer; const aTake: Integer);
  93. destructor Destroy; override;
  94. end;
  95. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  96. generic TutlWhereEnumerator<T> = class(
  97. specialize TutlEnumerator<T>)
  98. strict private
  99. fEnumerator: IEnumerator;
  100. fFilter: IFilter;
  101. public { IEnumerator }
  102. function GetCurrent: T; override;
  103. function MoveNext: Boolean; override;
  104. procedure Reset; override;
  105. public
  106. constructor Create(const aEnumerator: IEnumerator; const aFilter: IFilter);
  107. destructor Destroy; override;
  108. end;
  109. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  110. generic TutlSelectEnumerator<Tin, Tout> = class(
  111. specialize TutlEnumerator<Tout>)
  112. public type
  113. IInEnumerator = specialize IutlEnumerator<Tin>;
  114. ISelector = specialize IutlSelector<Tin, Tout>;
  115. strict private
  116. fEnumerator: IInEnumerator;
  117. fSelector: ISelector;
  118. public { IEnumerator }
  119. function GetCurrent: Tout; override;
  120. function MoveNext: Boolean; override;
  121. procedure Reset; override;
  122. public
  123. constructor Create(const aEnumerator: IInEnumerator; const aSelector: ISelector);
  124. destructor Destroy; override;
  125. end;
  126. implementation
  127. uses
  128. uutlExceptions;
  129. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  130. //TutlEnumerator////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  131. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  132. function TutlEnumerator.GetEnumerator: IEnumerator;
  133. begin
  134. result := self;
  135. end;
  136. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  137. function TutlEnumerator.Reverse: IEnumerator;
  138. var
  139. arr: TArray;
  140. begin
  141. arr := ToArray;
  142. result := specialize TutlArrayEnumerator<T>.Create(arr, true, low(arr), high(arr));
  143. end;
  144. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  145. function TutlEnumerator.Skip(const aCount: Integer): IEnumerator;
  146. begin
  147. result := specialize TutlSkipTakeEnumerator<T>.Create(self, aCount, -1);
  148. end;
  149. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  150. function TutlEnumerator.Take(const aCount: Integer): IEnumerator;
  151. begin
  152. result := specialize TutlSkipTakeEnumerator<T>.Create(self, -1, aCount);
  153. end;
  154. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  155. function TutlEnumerator.Where(const aFilter: IFilter): IEnumerator;
  156. begin
  157. result := specialize TutlWhereEnumerator<T>.Create(self, aFilter);
  158. end;
  159. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  160. function TutlEnumerator.ToArray: TArray;
  161. var
  162. i: Integer;
  163. arr: array of T;
  164. begin
  165. i := 0;
  166. SetLength(arr, i);
  167. Reset;
  168. while MoveNext do begin
  169. inc(i);
  170. SetLength(arr, i);
  171. arr[i-1] := GetCurrent;
  172. end;
  173. end;
  174. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  175. function TutlEnumerator.Count: Integer;
  176. begin
  177. result := 0;
  178. Reset;
  179. while MoveNext do
  180. inc(result);
  181. end;
  182. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  183. //TutlMemoryEnumerator//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  184. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  185. function TutlMemoryEnumerator.GetCurrent: T;
  186. var
  187. p: PT;
  188. begin
  189. if (fCurrent < 0) or (fCurrent >= fCount) then
  190. raise EutlInvalidOperation.Create('enumerator is not initialized');
  191. p := fMemory;
  192. if fReverse
  193. then inc(p, fCount - fCurrent - 1)
  194. else inc(p, fCurrent);
  195. result := p^;
  196. end;
  197. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  198. function TutlMemoryEnumerator.MoveNext: Boolean;
  199. begin
  200. inc(fCurrent);
  201. result := (fCurrent < fCount);
  202. end;
  203. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  204. procedure TutlMemoryEnumerator.Reset;
  205. begin
  206. fCurrent := -1;
  207. end;
  208. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  209. function TutlMemoryEnumerator.Count: Integer;
  210. begin
  211. result := fCount;
  212. end;
  213. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  214. function TutlMemoryEnumerator.Reverse: IEnumerator;
  215. begin
  216. result := TutlMemoryEnumerator.Create(fMemory, fCount, not fReverse);
  217. end;
  218. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  219. constructor TutlMemoryEnumerator.Create(const aMemory: PT; const aCount: Integer);
  220. begin
  221. Create(aMemory, aCount, false);
  222. end;
  223. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  224. constructor TutlMemoryEnumerator.Create(const aMemory: PT; const aCount: Integer; const aReverse: Boolean);
  225. begin
  226. inherited Create;
  227. fMemory := aMemory;
  228. fCount := aCount;
  229. fReverse := aReverse;
  230. fCurrent := -1;
  231. end;
  232. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  233. //TutlArrayEnumerator///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  234. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  235. function TutlArrayEnumerator.GetCurrent: T;
  236. begin
  237. if (fCurrent < fFirst) or (fCurrent > fLast) then
  238. raise EutlInvalidOperation.Create('enumerator is not initialized');
  239. result := fArray[fCurrent];
  240. end;
  241. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  242. function TutlArrayEnumerator.MoveNext: Boolean;
  243. begin
  244. if fReverse
  245. then dec(fCurrent)
  246. else inc(fCurrent);
  247. result := (fFirst <= fCurrent) and (fCurrent <= fLast);
  248. end;
  249. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  250. procedure TutlArrayEnumerator.Reset;
  251. begin
  252. if fReverse
  253. then fCurrent := fLast + 1
  254. else fCurrent := fFirst - 1;
  255. end;
  256. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  257. function TutlArrayEnumerator.Count: Integer;
  258. begin
  259. result := fLast - fFirst + 1;
  260. end;
  261. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  262. function TutlArrayEnumerator.Reverse: IEnumerator;
  263. begin
  264. result := specialize TutlArrayEnumerator<T>.Create(fArray, not fReverse, fFirst, fLast);
  265. end;
  266. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  267. function TutlArrayEnumerator.Skip(const aCount: Integer): IEnumerator;
  268. begin
  269. if fReverse
  270. then result := specialize TutlArrayEnumerator<T>.Create(fArray, fReverse, fFirst, fLast - aCount)
  271. else result := specialize TutlArrayEnumerator<T>.Create(fArray, fReverse, fFirst + aCount, fLast);
  272. end;
  273. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  274. function TutlArrayEnumerator.Take(const aCount: Integer): IEnumerator;
  275. begin
  276. if fReverse
  277. then result := specialize TutlArrayEnumerator<T>.Create(fArray, fReverse, fLast - aCount + 1, fLast)
  278. else result := specialize TutlArrayEnumerator<T>.Create(fArray, fReverse, fFirst, fFirst + aCount - 1);
  279. end;
  280. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  281. function TutlArrayEnumerator.ToArray: TArray;
  282. var
  283. i: Integer;
  284. begin
  285. SetLength(result, fLast - fFirst + 1);
  286. if fReverse then begin
  287. for i := fFirst to fLast do
  288. result[i-fFirst] := fArray[i];
  289. end else
  290. System.Move(fArray[fFirst], result[0], Length(result));
  291. end;
  292. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  293. constructor TutlArrayEnumerator.Create(const aArray: TArray);
  294. begin
  295. Create(aArray, false, low(aArray), high(aArray));
  296. end;
  297. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  298. constructor TutlArrayEnumerator.Create(
  299. const aArray: TArray;
  300. const aReverse: Boolean;
  301. const aFirst: Integer;
  302. const aLast: Integer);
  303. begin
  304. inherited Create;
  305. fArray := aArray;
  306. fReverse := aReverse;
  307. fFirst := aFirst;
  308. fLast := aLast;
  309. if (fFirst < low(fArray)) then
  310. fFirst := low(fArray);
  311. if (fLast > high(fArray)) then
  312. fLast := high(fArray);
  313. if fReverse
  314. then fCurrent := fLast + 1
  315. else fCurrent := fFirst - 1;
  316. end;
  317. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  318. //TutlSkipTakeEnumerator////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  319. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  320. function TutlSkipTakeEnumerator.GetCurrent: T;
  321. begin
  322. result := fEnumerator.Current;
  323. end;
  324. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  325. function TutlSkipTakeEnumerator.MoveNext: Boolean;
  326. begin
  327. while (fCurrentSkip > 0) and fEnumerator.MoveNext do
  328. dec(fCurrentSkip);
  329. result :=
  330. (fCurrentSkip <= 0)
  331. and (fCurrentTake <> 0)
  332. and fEnumerator.MoveNext;
  333. if (fCurrentTake > 0) then
  334. dec(fCurrentTake);
  335. end;
  336. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  337. procedure TutlSkipTakeEnumerator.Reset;
  338. begin
  339. fEnumerator.Reset;
  340. fCurrentSkip := fSkip;
  341. fCurrentTake := fTake;
  342. end;
  343. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  344. constructor TutlSkipTakeEnumerator.Create(const aEnumerator: IEnumerator; const aSkip: Integer; const aTake: Integer);
  345. begin
  346. if not Assigned(aEnumerator) then
  347. raise EutlArgumentNil.Create('aEnumerator');
  348. inherited Create;
  349. fEnumerator := aEnumerator;
  350. fSkip := aSkip;
  351. fTake := aTake;
  352. fCurrentSkip := aSkip;
  353. fCurrentTake := aTake;
  354. end;
  355. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  356. destructor TutlSkipTakeEnumerator.Destroy;
  357. begin
  358. fEnumerator := nil;
  359. inherited Destroy;
  360. end;
  361. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  362. //TutlWhereEnumerator///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  363. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  364. function TutlWhereEnumerator.GetCurrent: T;
  365. begin
  366. result := fEnumerator.Current;
  367. end;
  368. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  369. function TutlWhereEnumerator.MoveNext: Boolean;
  370. begin
  371. repeat
  372. result := fEnumerator.MoveNext;
  373. until not result or fFilter.Filter(fEnumerator.Current);
  374. end;
  375. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  376. procedure TutlWhereEnumerator.Reset;
  377. begin
  378. fEnumerator.Reset;
  379. end;
  380. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  381. constructor TutlWhereEnumerator.Create(const aEnumerator: IEnumerator; const aFilter: IFilter);
  382. begin
  383. if not Assigned(aEnumerator) then
  384. raise EutlArgumentNil.Create('aEnumerator');
  385. if not Assigned(aFilter) then
  386. raise EutlArgumentNil.Create('aFilter');
  387. inherited Create;
  388. fEnumerator := aEnumerator;
  389. fFilter := aFilter;
  390. end;
  391. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  392. destructor TutlWhereEnumerator.Destroy;
  393. begin
  394. fEnumerator := nil;
  395. fFilter := nil;
  396. inherited Destroy;
  397. end;
  398. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  399. //TutlSelectEnumerator//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  400. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  401. function TutlSelectEnumerator.GetCurrent: Tout;
  402. begin
  403. result := fSelector.Select(fEnumerator.Current);
  404. end;
  405. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  406. function TutlSelectEnumerator.MoveNext: Boolean;
  407. begin
  408. result := fEnumerator.MoveNext;
  409. end;
  410. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  411. procedure TutlSelectEnumerator.Reset;
  412. begin
  413. fEnumerator.Reset;
  414. end;
  415. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  416. constructor TutlSelectEnumerator.Create(const aEnumerator: IInEnumerator; const aSelector: ISelector);
  417. begin
  418. if not Assigned(aEnumerator) then
  419. raise EutlArgumentNil.Create('aEnumerator');
  420. if not Assigned(aSelector) then
  421. raise EutlArgumentNil.Create('aSelector');
  422. inherited Create;
  423. fEnumerator := aEnumerator;
  424. fSelector := aSelector;
  425. end;
  426. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  427. destructor TutlSelectEnumerator.Destroy;
  428. begin
  429. fEnumerator := nil;
  430. fSelector := nil;
  431. inherited Destroy;
  432. end;
  433. end.