GroupBy.cs 35 KB

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