GroupBy.cs 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756
  1. // Licensed to the .NET Foundation under one or more agreements.
  2. // The .NET Foundation licenses this file to you under the Apache 2.0 License.
  3. // See the LICENSE file in the project root for more information.
  4. using System.Collections.Generic;
  5. using System.Diagnostics;
  6. using System.Threading;
  7. using System.Threading.Tasks;
  8. namespace System.Linq
  9. {
  10. public static partial class AsyncEnumerable
  11. {
  12. public static IAsyncEnumerable<IAsyncGrouping<TKey, TSource>> GroupBy<TSource, TKey>(this IAsyncEnumerable<TSource> source, Func<TSource, TKey> keySelector)
  13. {
  14. if (source == null)
  15. throw Error.ArgumentNull(nameof(source));
  16. if (keySelector == null)
  17. throw Error.ArgumentNull(nameof(keySelector));
  18. return new GroupedAsyncEnumerable<TSource, TKey>(source, keySelector, comparer: null);
  19. }
  20. public static IAsyncEnumerable<IAsyncGrouping<TKey, TSource>> GroupBy<TSource, TKey>(this IAsyncEnumerable<TSource> source, Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer)
  21. {
  22. if (source == null)
  23. throw Error.ArgumentNull(nameof(source));
  24. if (keySelector == null)
  25. throw Error.ArgumentNull(nameof(keySelector));
  26. return new GroupedAsyncEnumerable<TSource, TKey>(source, keySelector, comparer);
  27. }
  28. public static IAsyncEnumerable<IAsyncGrouping<TKey, TSource>> GroupBy<TSource, TKey>(this IAsyncEnumerable<TSource> source, Func<TSource, Task<TKey>> keySelector)
  29. {
  30. if (source == null)
  31. throw Error.ArgumentNull(nameof(source));
  32. if (keySelector == null)
  33. throw Error.ArgumentNull(nameof(keySelector));
  34. return new GroupedAsyncEnumerableWithTask<TSource, TKey>(source, keySelector, comparer: null);
  35. }
  36. public static IAsyncEnumerable<IAsyncGrouping<TKey, TSource>> GroupBy<TSource, TKey>(this IAsyncEnumerable<TSource> source, Func<TSource, Task<TKey>> keySelector, IEqualityComparer<TKey> comparer)
  37. {
  38. if (source == null)
  39. throw Error.ArgumentNull(nameof(source));
  40. if (keySelector == null)
  41. throw Error.ArgumentNull(nameof(keySelector));
  42. return new GroupedAsyncEnumerableWithTask<TSource, TKey>(source, keySelector, comparer);
  43. }
  44. public static IAsyncEnumerable<IAsyncGrouping<TKey, TElement>> GroupBy<TSource, TKey, TElement>(this IAsyncEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector)
  45. {
  46. if (source == null)
  47. throw Error.ArgumentNull(nameof(source));
  48. if (keySelector == null)
  49. throw Error.ArgumentNull(nameof(keySelector));
  50. if (elementSelector == null)
  51. throw Error.ArgumentNull(nameof(elementSelector));
  52. return new GroupedAsyncEnumerable<TSource, TKey, TElement>(source, keySelector, elementSelector, comparer: null);
  53. }
  54. public static IAsyncEnumerable<IAsyncGrouping<TKey, TElement>> GroupBy<TSource, TKey, TElement>(this IAsyncEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector, IEqualityComparer<TKey> comparer)
  55. {
  56. if (source == null)
  57. throw Error.ArgumentNull(nameof(source));
  58. if (keySelector == null)
  59. throw Error.ArgumentNull(nameof(keySelector));
  60. if (elementSelector == null)
  61. throw Error.ArgumentNull(nameof(elementSelector));
  62. return new GroupedAsyncEnumerable<TSource, TKey, TElement>(source, keySelector, elementSelector, comparer);
  63. }
  64. public static IAsyncEnumerable<IAsyncGrouping<TKey, TElement>> GroupBy<TSource, TKey, TElement>(this IAsyncEnumerable<TSource> source, Func<TSource, Task<TKey>> keySelector, Func<TSource, Task<TElement>> elementSelector)
  65. {
  66. if (source == null)
  67. throw Error.ArgumentNull(nameof(source));
  68. if (keySelector == null)
  69. throw Error.ArgumentNull(nameof(keySelector));
  70. if (elementSelector == null)
  71. throw Error.ArgumentNull(nameof(elementSelector));
  72. return new GroupedAsyncEnumerableWithTask<TSource, TKey, TElement>(source, keySelector, elementSelector, comparer: null);
  73. }
  74. public static IAsyncEnumerable<IAsyncGrouping<TKey, TElement>> GroupBy<TSource, TKey, TElement>(this IAsyncEnumerable<TSource> source, Func<TSource, Task<TKey>> keySelector, Func<TSource, Task<TElement>> elementSelector, IEqualityComparer<TKey> comparer)
  75. {
  76. if (source == null)
  77. throw Error.ArgumentNull(nameof(source));
  78. if (keySelector == null)
  79. throw Error.ArgumentNull(nameof(keySelector));
  80. if (elementSelector == null)
  81. throw Error.ArgumentNull(nameof(elementSelector));
  82. return new GroupedAsyncEnumerableWithTask<TSource, TKey, TElement>(source, keySelector, elementSelector, comparer);
  83. }
  84. public static IAsyncEnumerable<TResult> GroupBy<TSource, TKey, TResult>(this IAsyncEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TKey, IAsyncEnumerable<TSource>, TResult> resultSelector)
  85. {
  86. if (source == null)
  87. throw Error.ArgumentNull(nameof(source));
  88. if (keySelector == null)
  89. throw Error.ArgumentNull(nameof(keySelector));
  90. if (resultSelector == null)
  91. throw Error.ArgumentNull(nameof(resultSelector));
  92. return new GroupedResultAsyncEnumerable<TSource, TKey, TResult>(source, keySelector, resultSelector, comparer: null);
  93. }
  94. public static IAsyncEnumerable<TResult> GroupBy<TSource, TKey, TResult>(this IAsyncEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TKey, IAsyncEnumerable<TSource>, TResult> resultSelector, IEqualityComparer<TKey> comparer)
  95. {
  96. if (source == null)
  97. throw Error.ArgumentNull(nameof(source));
  98. if (keySelector == null)
  99. throw Error.ArgumentNull(nameof(keySelector));
  100. if (resultSelector == null)
  101. throw Error.ArgumentNull(nameof(resultSelector));
  102. return new GroupedResultAsyncEnumerable<TSource, TKey, TResult>(source, keySelector, resultSelector, comparer);
  103. }
  104. public static IAsyncEnumerable<TResult> GroupBy<TSource, TKey, TResult>(this IAsyncEnumerable<TSource> source, Func<TSource, Task<TKey>> keySelector, Func<TKey, IAsyncEnumerable<TSource>, Task<TResult>> resultSelector)
  105. {
  106. if (source == null)
  107. throw Error.ArgumentNull(nameof(source));
  108. if (keySelector == null)
  109. throw Error.ArgumentNull(nameof(keySelector));
  110. if (resultSelector == null)
  111. throw Error.ArgumentNull(nameof(resultSelector));
  112. return new GroupedResultAsyncEnumerableWithTask<TSource, TKey, TResult>(source, keySelector, resultSelector, comparer: null);
  113. }
  114. public static IAsyncEnumerable<TResult> GroupBy<TSource, TKey, TResult>(this IAsyncEnumerable<TSource> source, Func<TSource, Task<TKey>> keySelector, Func<TKey, IAsyncEnumerable<TSource>, Task<TResult>> resultSelector, IEqualityComparer<TKey> comparer)
  115. {
  116. if (source == null)
  117. throw Error.ArgumentNull(nameof(source));
  118. if (keySelector == null)
  119. throw Error.ArgumentNull(nameof(keySelector));
  120. if (resultSelector == null)
  121. throw Error.ArgumentNull(nameof(resultSelector));
  122. return new GroupedResultAsyncEnumerableWithTask<TSource, TKey, TResult>(source, keySelector, resultSelector, comparer);
  123. }
  124. public static IAsyncEnumerable<TResult> GroupBy<TSource, TKey, TElement, TResult>(this IAsyncEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector, Func<TKey, IAsyncEnumerable<TElement>, TResult> resultSelector)
  125. {
  126. if (source == null)
  127. throw Error.ArgumentNull(nameof(source));
  128. if (keySelector == null)
  129. throw Error.ArgumentNull(nameof(keySelector));
  130. if (elementSelector == null)
  131. throw Error.ArgumentNull(nameof(elementSelector));
  132. if (resultSelector == null)
  133. throw Error.ArgumentNull(nameof(resultSelector));
  134. return source.GroupBy(keySelector, elementSelector, comparer: null).Select(g => resultSelector(g.Key, g));
  135. }
  136. public static IAsyncEnumerable<TResult> GroupBy<TSource, TKey, TElement, TResult>(this IAsyncEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector, Func<TKey, IAsyncEnumerable<TElement>, TResult> resultSelector, IEqualityComparer<TKey> comparer)
  137. {
  138. if (source == null)
  139. throw Error.ArgumentNull(nameof(source));
  140. if (keySelector == null)
  141. throw Error.ArgumentNull(nameof(keySelector));
  142. if (elementSelector == null)
  143. throw Error.ArgumentNull(nameof(elementSelector));
  144. if (resultSelector == null)
  145. throw Error.ArgumentNull(nameof(resultSelector));
  146. return source.GroupBy(keySelector, elementSelector, comparer).Select(g => resultSelector(g.Key, g));
  147. }
  148. public static IAsyncEnumerable<TResult> GroupBy<TSource, TKey, TElement, TResult>(this IAsyncEnumerable<TSource> source, Func<TSource, Task<TKey>> keySelector, Func<TSource, Task<TElement>> elementSelector, Func<TKey, IAsyncEnumerable<TElement>, Task<TResult>> resultSelector)
  149. {
  150. if (source == null)
  151. throw Error.ArgumentNull(nameof(source));
  152. if (keySelector == null)
  153. throw Error.ArgumentNull(nameof(keySelector));
  154. if (elementSelector == null)
  155. throw Error.ArgumentNull(nameof(elementSelector));
  156. if (resultSelector == null)
  157. throw Error.ArgumentNull(nameof(resultSelector));
  158. return source.GroupBy<TSource, TKey, TElement>(keySelector, elementSelector, comparer: null).Select(g => resultSelector(g.Key, g));
  159. }
  160. public static IAsyncEnumerable<TResult> GroupBy<TSource, TKey, TElement, TResult>(this IAsyncEnumerable<TSource> source, Func<TSource, Task<TKey>> keySelector, Func<TSource, Task<TElement>> elementSelector, Func<TKey, IAsyncEnumerable<TElement>, Task<TResult>> resultSelector, IEqualityComparer<TKey> comparer)
  161. {
  162. if (source == null)
  163. throw Error.ArgumentNull(nameof(source));
  164. if (keySelector == null)
  165. throw Error.ArgumentNull(nameof(keySelector));
  166. if (elementSelector == null)
  167. throw Error.ArgumentNull(nameof(elementSelector));
  168. if (resultSelector == null)
  169. throw Error.ArgumentNull(nameof(resultSelector));
  170. return source.GroupBy(keySelector, elementSelector, comparer).Select(g => resultSelector(g.Key, g));
  171. }
  172. internal sealed class GroupedResultAsyncEnumerable<TSource, TKey, TResult> : AsyncIterator<TResult>, IAsyncIListProvider<TResult>
  173. {
  174. private readonly IAsyncEnumerable<TSource> _source;
  175. private readonly Func<TSource, TKey> _keySelector;
  176. private readonly Func<TKey, IAsyncEnumerable<TSource>, TResult> _resultSelector;
  177. private readonly IEqualityComparer<TKey> _comparer;
  178. private Internal.Lookup<TKey, TSource> _lookup;
  179. private IEnumerator<TResult> _enumerator;
  180. public GroupedResultAsyncEnumerable(IAsyncEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TKey, IAsyncEnumerable<TSource>, TResult> resultSelector, IEqualityComparer<TKey> comparer)
  181. {
  182. Debug.Assert(source != null);
  183. Debug.Assert(keySelector != null);
  184. Debug.Assert(resultSelector != null);
  185. _source = source;
  186. _keySelector = keySelector;
  187. _resultSelector = resultSelector;
  188. _comparer = comparer;
  189. }
  190. public override AsyncIterator<TResult> Clone()
  191. {
  192. return new GroupedResultAsyncEnumerable<TSource, TKey, TResult>(_source, _keySelector, _resultSelector, _comparer);
  193. }
  194. public override async ValueTask DisposeAsync()
  195. {
  196. if (_enumerator != null)
  197. {
  198. _enumerator.Dispose();
  199. _enumerator = null;
  200. _lookup = null;
  201. }
  202. await base.DisposeAsync().ConfigureAwait(false);
  203. }
  204. protected override async ValueTask<bool> MoveNextCore(CancellationToken cancellationToken)
  205. {
  206. switch (state)
  207. {
  208. case AsyncIteratorState.Allocated:
  209. _lookup = await Internal.Lookup<TKey, TSource>.CreateAsync(_source, _keySelector, _comparer, cancellationToken).ConfigureAwait(false);
  210. _enumerator = _lookup.ApplyResultSelector(_resultSelector).GetEnumerator();
  211. state = AsyncIteratorState.Iterating;
  212. goto case AsyncIteratorState.Iterating;
  213. case AsyncIteratorState.Iterating:
  214. if (_enumerator.MoveNext())
  215. {
  216. current = _enumerator.Current;
  217. return true;
  218. }
  219. await DisposeAsync().ConfigureAwait(false);
  220. break;
  221. }
  222. return false;
  223. }
  224. public async Task<TResult[]> ToArrayAsync(CancellationToken cancellationToken)
  225. {
  226. var l = await Internal.Lookup<TKey, TSource>.CreateAsync(_source, _keySelector, _comparer, cancellationToken).ConfigureAwait(false);
  227. return l.ToArray(_resultSelector);
  228. }
  229. public async Task<List<TResult>> ToListAsync(CancellationToken cancellationToken)
  230. {
  231. var l = await Internal.Lookup<TKey, TSource>.CreateAsync(_source, _keySelector, _comparer, cancellationToken).ConfigureAwait(false);
  232. return l.ToList(_resultSelector);
  233. }
  234. public Task<int> GetCountAsync(bool onlyIfCheap, CancellationToken cancellationToken)
  235. {
  236. if (onlyIfCheap)
  237. {
  238. return TaskExt.MinusOne;
  239. }
  240. return Core();
  241. async Task<int> Core()
  242. {
  243. var l = await Internal.Lookup<TKey, TSource>.CreateAsync(_source, _keySelector, _comparer, cancellationToken).ConfigureAwait(false);
  244. return l.Count;
  245. }
  246. }
  247. }
  248. internal sealed class GroupedResultAsyncEnumerableWithTask<TSource, TKey, TResult> : AsyncIterator<TResult>, IAsyncIListProvider<TResult>
  249. {
  250. private readonly IAsyncEnumerable<TSource> _source;
  251. private readonly Func<TSource, Task<TKey>> _keySelector;
  252. private readonly Func<TKey, IAsyncEnumerable<TSource>, Task<TResult>> _resultSelector;
  253. private readonly IEqualityComparer<TKey> _comparer;
  254. private Internal.LookupWithTask<TKey, TSource> _lookup;
  255. private IAsyncEnumerator<TResult> _enumerator;
  256. public GroupedResultAsyncEnumerableWithTask(IAsyncEnumerable<TSource> source, Func<TSource, Task<TKey>> keySelector, Func<TKey, IAsyncEnumerable<TSource>, Task<TResult>> resultSelector, IEqualityComparer<TKey> comparer)
  257. {
  258. Debug.Assert(source != null);
  259. Debug.Assert(keySelector != null);
  260. Debug.Assert(resultSelector != null);
  261. _source = source;
  262. _keySelector = keySelector;
  263. _resultSelector = resultSelector;
  264. _comparer = comparer;
  265. }
  266. public override AsyncIterator<TResult> Clone()
  267. {
  268. return new GroupedResultAsyncEnumerableWithTask<TSource, TKey, TResult>(_source, _keySelector, _resultSelector, _comparer);
  269. }
  270. public override async ValueTask DisposeAsync()
  271. {
  272. if (_enumerator != null)
  273. {
  274. await _enumerator.DisposeAsync().ConfigureAwait(false);
  275. _enumerator = null;
  276. _lookup = null;
  277. }
  278. await base.DisposeAsync().ConfigureAwait(false);
  279. }
  280. protected override async ValueTask<bool> MoveNextCore(CancellationToken cancellationToken)
  281. {
  282. switch (state)
  283. {
  284. case AsyncIteratorState.Allocated:
  285. _lookup = await Internal.LookupWithTask<TKey, TSource>.CreateAsync(_source, _keySelector, _comparer, cancellationToken).ConfigureAwait(false);
  286. _enumerator = _lookup.Select(async g => await _resultSelector(g.Key, g).ConfigureAwait(false)).GetAsyncEnumerator(cancellationToken);
  287. state = AsyncIteratorState.Iterating;
  288. goto case AsyncIteratorState.Iterating;
  289. case AsyncIteratorState.Iterating:
  290. if (await _enumerator.MoveNextAsync().ConfigureAwait(false))
  291. {
  292. current = _enumerator.Current;
  293. return true;
  294. }
  295. await DisposeAsync().ConfigureAwait(false);
  296. break;
  297. }
  298. return false;
  299. }
  300. public async Task<TResult[]> ToArrayAsync(CancellationToken cancellationToken)
  301. {
  302. var l = await Internal.LookupWithTask<TKey, TSource>.CreateAsync(_source, _keySelector, _comparer, cancellationToken).ConfigureAwait(false);
  303. return await l.ToArray(_resultSelector).ConfigureAwait(false);
  304. }
  305. public async Task<List<TResult>> ToListAsync(CancellationToken cancellationToken)
  306. {
  307. var l = await Internal.LookupWithTask<TKey, TSource>.CreateAsync(_source, _keySelector, _comparer, cancellationToken).ConfigureAwait(false);
  308. return await l.ToList(_resultSelector).ConfigureAwait(false);
  309. }
  310. public Task<int> GetCountAsync(bool onlyIfCheap, CancellationToken cancellationToken)
  311. {
  312. if (onlyIfCheap)
  313. {
  314. return TaskExt.MinusOne;
  315. }
  316. return Core();
  317. async Task<int> Core()
  318. {
  319. var l = await Internal.LookupWithTask<TKey, TSource>.CreateAsync(_source, _keySelector, _comparer, cancellationToken).ConfigureAwait(false);
  320. return l.Count;
  321. }
  322. }
  323. }
  324. internal sealed class GroupedAsyncEnumerable<TSource, TKey, TElement> : AsyncIterator<IAsyncGrouping<TKey, TElement>>, IAsyncIListProvider<IAsyncGrouping<TKey, TElement>>
  325. {
  326. private readonly IAsyncEnumerable<TSource> _source;
  327. private readonly Func<TSource, TKey> _keySelector;
  328. private readonly Func<TSource, TElement> _elementSelector;
  329. private readonly IEqualityComparer<TKey> _comparer;
  330. private Internal.Lookup<TKey, TElement> _lookup;
  331. private IEnumerator<IGrouping<TKey, TElement>> _enumerator;
  332. public GroupedAsyncEnumerable(IAsyncEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector, IEqualityComparer<TKey> comparer)
  333. {
  334. Debug.Assert(source != null);
  335. Debug.Assert(keySelector != null);
  336. Debug.Assert(elementSelector != null);
  337. _source = source;
  338. _keySelector = keySelector;
  339. _elementSelector = elementSelector;
  340. _comparer = comparer;
  341. }
  342. public override AsyncIterator<IAsyncGrouping<TKey, TElement>> Clone()
  343. {
  344. return new GroupedAsyncEnumerable<TSource, TKey, TElement>(_source, _keySelector, _elementSelector, _comparer);
  345. }
  346. public override async ValueTask DisposeAsync()
  347. {
  348. if (_enumerator != null)
  349. {
  350. _enumerator.Dispose();
  351. _enumerator = null;
  352. _lookup = null;
  353. }
  354. await base.DisposeAsync().ConfigureAwait(false);
  355. }
  356. protected override async ValueTask<bool> MoveNextCore(CancellationToken cancellationToken)
  357. {
  358. switch (state)
  359. {
  360. case AsyncIteratorState.Allocated:
  361. _lookup = await Internal.Lookup<TKey, TElement>.CreateAsync(_source, _keySelector, _elementSelector, _comparer, cancellationToken).ConfigureAwait(false);
  362. _enumerator = _lookup.GetEnumerator();
  363. state = AsyncIteratorState.Iterating;
  364. goto case AsyncIteratorState.Iterating;
  365. case AsyncIteratorState.Iterating:
  366. if (_enumerator.MoveNext())
  367. {
  368. current = (IAsyncGrouping<TKey, TElement>)_enumerator.Current;
  369. return true;
  370. }
  371. await DisposeAsync().ConfigureAwait(false);
  372. break;
  373. }
  374. return false;
  375. }
  376. public async Task<IAsyncGrouping<TKey, TElement>[]> ToArrayAsync(CancellationToken cancellationToken)
  377. {
  378. IAsyncIListProvider<IAsyncGrouping<TKey, TElement>> l = await Internal.Lookup<TKey, TElement>.CreateAsync(_source, _keySelector, _elementSelector, _comparer, cancellationToken).ConfigureAwait(false);
  379. return await l.ToArrayAsync(cancellationToken).ConfigureAwait(false);
  380. }
  381. public async Task<List<IAsyncGrouping<TKey, TElement>>> ToListAsync(CancellationToken cancellationToken)
  382. {
  383. IAsyncIListProvider<IAsyncGrouping<TKey, TElement>> l = await Internal.Lookup<TKey, TElement>.CreateAsync(_source, _keySelector, _elementSelector, _comparer, cancellationToken).ConfigureAwait(false);
  384. return await l.ToListAsync(cancellationToken).ConfigureAwait(false);
  385. }
  386. public Task<int> GetCountAsync(bool onlyIfCheap, CancellationToken cancellationToken)
  387. {
  388. if (onlyIfCheap)
  389. {
  390. return TaskExt.MinusOne;
  391. }
  392. return Core();
  393. async Task<int> Core()
  394. {
  395. var l = await Internal.Lookup<TKey, TElement>.CreateAsync(_source, _keySelector, _elementSelector, _comparer, cancellationToken).ConfigureAwait(false);
  396. return l.Count;
  397. }
  398. }
  399. }
  400. internal sealed class GroupedAsyncEnumerableWithTask<TSource, TKey, TElement> : AsyncIterator<IAsyncGrouping<TKey, TElement>>, IAsyncIListProvider<IAsyncGrouping<TKey, TElement>>
  401. {
  402. private readonly IAsyncEnumerable<TSource> _source;
  403. private readonly Func<TSource, Task<TKey>> _keySelector;
  404. private readonly Func<TSource, Task<TElement>> _elementSelector;
  405. private readonly IEqualityComparer<TKey> _comparer;
  406. private Internal.LookupWithTask<TKey, TElement> _lookup;
  407. private IEnumerator<IGrouping<TKey, TElement>> _enumerator;
  408. public GroupedAsyncEnumerableWithTask(IAsyncEnumerable<TSource> source, Func<TSource, Task<TKey>> keySelector, Func<TSource, Task<TElement>> elementSelector, IEqualityComparer<TKey> comparer)
  409. {
  410. Debug.Assert(source != null);
  411. Debug.Assert(keySelector != null);
  412. Debug.Assert(elementSelector != null);
  413. _source = source;
  414. _keySelector = keySelector;
  415. _elementSelector = elementSelector;
  416. _comparer = comparer;
  417. }
  418. public override AsyncIterator<IAsyncGrouping<TKey, TElement>> Clone()
  419. {
  420. return new GroupedAsyncEnumerableWithTask<TSource, TKey, TElement>(_source, _keySelector, _elementSelector, _comparer);
  421. }
  422. public override async ValueTask DisposeAsync()
  423. {
  424. if (_enumerator != null)
  425. {
  426. _enumerator.Dispose();
  427. _enumerator = null;
  428. _lookup = null;
  429. }
  430. await base.DisposeAsync().ConfigureAwait(false);
  431. }
  432. protected override async ValueTask<bool> MoveNextCore(CancellationToken cancellationToken)
  433. {
  434. switch (state)
  435. {
  436. case AsyncIteratorState.Allocated:
  437. _lookup = await Internal.LookupWithTask<TKey, TElement>.CreateAsync(_source, _keySelector, _elementSelector, _comparer, cancellationToken).ConfigureAwait(false);
  438. _enumerator = _lookup.GetEnumerator();
  439. state = AsyncIteratorState.Iterating;
  440. goto case AsyncIteratorState.Iterating;
  441. case AsyncIteratorState.Iterating:
  442. if (_enumerator.MoveNext())
  443. {
  444. current = (IAsyncGrouping<TKey, TElement>)_enumerator.Current;
  445. return true;
  446. }
  447. await DisposeAsync().ConfigureAwait(false);
  448. break;
  449. }
  450. return false;
  451. }
  452. public async Task<IAsyncGrouping<TKey, TElement>[]> ToArrayAsync(CancellationToken cancellationToken)
  453. {
  454. IAsyncIListProvider<IAsyncGrouping<TKey, TElement>> l = await Internal.LookupWithTask<TKey, TElement>.CreateAsync(_source, _keySelector, _elementSelector, _comparer, cancellationToken).ConfigureAwait(false);
  455. return await l.ToArrayAsync(cancellationToken).ConfigureAwait(false);
  456. }
  457. public async Task<List<IAsyncGrouping<TKey, TElement>>> ToListAsync(CancellationToken cancellationToken)
  458. {
  459. IAsyncIListProvider<IAsyncGrouping<TKey, TElement>> l = await Internal.LookupWithTask<TKey, TElement>.CreateAsync(_source, _keySelector, _elementSelector, _comparer, cancellationToken).ConfigureAwait(false);
  460. return await l.ToListAsync(cancellationToken).ConfigureAwait(false);
  461. }
  462. public Task<int> GetCountAsync(bool onlyIfCheap, CancellationToken cancellationToken)
  463. {
  464. if (onlyIfCheap)
  465. {
  466. return TaskExt.MinusOne;
  467. }
  468. return Core();
  469. async Task<int> Core()
  470. {
  471. var l = await Internal.LookupWithTask<TKey, TElement>.CreateAsync(_source, _keySelector, _elementSelector, _comparer, cancellationToken).ConfigureAwait(false);
  472. return l.Count;
  473. }
  474. }
  475. }
  476. internal sealed class GroupedAsyncEnumerable<TSource, TKey> : AsyncIterator<IAsyncGrouping<TKey, TSource>>, IAsyncIListProvider<IAsyncGrouping<TKey, TSource>>
  477. {
  478. private readonly IAsyncEnumerable<TSource> _source;
  479. private readonly Func<TSource, TKey> _keySelector;
  480. private readonly IEqualityComparer<TKey> _comparer;
  481. private Internal.Lookup<TKey, TSource> _lookup;
  482. private IEnumerator<IGrouping<TKey, TSource>> _enumerator;
  483. public GroupedAsyncEnumerable(IAsyncEnumerable<TSource> source, Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer)
  484. {
  485. Debug.Assert(source != null);
  486. Debug.Assert(keySelector != null);
  487. _source = source;
  488. _keySelector = keySelector;
  489. _comparer = comparer;
  490. }
  491. public override AsyncIterator<IAsyncGrouping<TKey, TSource>> Clone()
  492. {
  493. return new GroupedAsyncEnumerable<TSource, TKey>(_source, _keySelector, _comparer);
  494. }
  495. public override async ValueTask DisposeAsync()
  496. {
  497. if (_enumerator != null)
  498. {
  499. _enumerator.Dispose();
  500. _enumerator = null;
  501. _lookup = null;
  502. }
  503. await base.DisposeAsync().ConfigureAwait(false);
  504. }
  505. protected override async ValueTask<bool> MoveNextCore(CancellationToken cancellationToken)
  506. {
  507. switch (state)
  508. {
  509. case AsyncIteratorState.Allocated:
  510. _lookup = await Internal.Lookup<TKey, TSource>.CreateAsync(_source, _keySelector, _comparer, cancellationToken).ConfigureAwait(false);
  511. _enumerator = _lookup.GetEnumerator();
  512. state = AsyncIteratorState.Iterating;
  513. goto case AsyncIteratorState.Iterating;
  514. case AsyncIteratorState.Iterating:
  515. if (_enumerator.MoveNext())
  516. {
  517. current = (IAsyncGrouping<TKey, TSource>)_enumerator.Current;
  518. return true;
  519. }
  520. await DisposeAsync().ConfigureAwait(false);
  521. break;
  522. }
  523. return false;
  524. }
  525. public async Task<IAsyncGrouping<TKey, TSource>[]> ToArrayAsync(CancellationToken cancellationToken)
  526. {
  527. IAsyncIListProvider<IAsyncGrouping<TKey, TSource>> l = await Internal.Lookup<TKey, TSource>.CreateAsync(_source, _keySelector, _comparer, cancellationToken).ConfigureAwait(false);
  528. return await l.ToArrayAsync(cancellationToken).ConfigureAwait(false);
  529. }
  530. public async Task<List<IAsyncGrouping<TKey, TSource>>> ToListAsync(CancellationToken cancellationToken)
  531. {
  532. IAsyncIListProvider<IAsyncGrouping<TKey, TSource>> l = await Internal.Lookup<TKey, TSource>.CreateAsync(_source, _keySelector, _comparer, cancellationToken).ConfigureAwait(false);
  533. return await l.ToListAsync(cancellationToken).ConfigureAwait(false);
  534. }
  535. public Task<int> GetCountAsync(bool onlyIfCheap, CancellationToken cancellationToken)
  536. {
  537. if (onlyIfCheap)
  538. {
  539. return TaskExt.MinusOne;
  540. }
  541. return Core();
  542. async Task<int> Core()
  543. {
  544. var l = await Internal.Lookup<TKey, TSource>.CreateAsync(_source, _keySelector, _comparer, cancellationToken).ConfigureAwait(false);
  545. return l.Count;
  546. }
  547. }
  548. }
  549. internal sealed class GroupedAsyncEnumerableWithTask<TSource, TKey> : AsyncIterator<IAsyncGrouping<TKey, TSource>>, IAsyncIListProvider<IAsyncGrouping<TKey, TSource>>
  550. {
  551. private readonly IAsyncEnumerable<TSource> _source;
  552. private readonly Func<TSource, Task<TKey>> _keySelector;
  553. private readonly IEqualityComparer<TKey> _comparer;
  554. private Internal.LookupWithTask<TKey, TSource> _lookup;
  555. private IEnumerator<IGrouping<TKey, TSource>> _enumerator;
  556. public GroupedAsyncEnumerableWithTask(IAsyncEnumerable<TSource> source, Func<TSource, Task<TKey>> keySelector, IEqualityComparer<TKey> comparer)
  557. {
  558. Debug.Assert(source != null);
  559. Debug.Assert(keySelector != null);
  560. _source = source;
  561. _keySelector = keySelector;
  562. _comparer = comparer;
  563. }
  564. public override AsyncIterator<IAsyncGrouping<TKey, TSource>> Clone()
  565. {
  566. return new GroupedAsyncEnumerableWithTask<TSource, TKey>(_source, _keySelector, _comparer);
  567. }
  568. public override async ValueTask DisposeAsync()
  569. {
  570. if (_enumerator != null)
  571. {
  572. _enumerator.Dispose();
  573. _enumerator = null;
  574. _lookup = null;
  575. }
  576. await base.DisposeAsync().ConfigureAwait(false);
  577. }
  578. protected override async ValueTask<bool> MoveNextCore(CancellationToken cancellationToken)
  579. {
  580. switch (state)
  581. {
  582. case AsyncIteratorState.Allocated:
  583. _lookup = await Internal.LookupWithTask<TKey, TSource>.CreateAsync(_source, _keySelector, _comparer, cancellationToken).ConfigureAwait(false);
  584. _enumerator = _lookup.GetEnumerator();
  585. state = AsyncIteratorState.Iterating;
  586. goto case AsyncIteratorState.Iterating;
  587. case AsyncIteratorState.Iterating:
  588. if (_enumerator.MoveNext())
  589. {
  590. current = (IAsyncGrouping<TKey, TSource>)_enumerator.Current;
  591. return true;
  592. }
  593. await DisposeAsync().ConfigureAwait(false);
  594. break;
  595. }
  596. return false;
  597. }
  598. public async Task<IAsyncGrouping<TKey, TSource>[]> ToArrayAsync(CancellationToken cancellationToken)
  599. {
  600. IAsyncIListProvider<IAsyncGrouping<TKey, TSource>> l = await Internal.LookupWithTask<TKey, TSource>.CreateAsync(_source, _keySelector, _comparer, cancellationToken).ConfigureAwait(false);
  601. return await l.ToArrayAsync(cancellationToken).ConfigureAwait(false);
  602. }
  603. public async Task<List<IAsyncGrouping<TKey, TSource>>> ToListAsync(CancellationToken cancellationToken)
  604. {
  605. IAsyncIListProvider<IAsyncGrouping<TKey, TSource>> l = await Internal.LookupWithTask<TKey, TSource>.CreateAsync(_source, _keySelector, _comparer, cancellationToken).ConfigureAwait(false);
  606. return await l.ToListAsync(cancellationToken).ConfigureAwait(false);
  607. }
  608. public Task<int> GetCountAsync(bool onlyIfCheap, CancellationToken cancellationToken)
  609. {
  610. if (onlyIfCheap)
  611. {
  612. return TaskExt.MinusOne;
  613. }
  614. return Core();
  615. async Task<int> Core()
  616. {
  617. var l = await Internal.LookupWithTask<TKey, TSource>.CreateAsync(_source, _keySelector, _comparer, cancellationToken).ConfigureAwait(false);
  618. return l.Count;
  619. }
  620. }
  621. }
  622. }
  623. }