1
0

GroupBy.cs 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778
  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 new GroupedAsyncEnumerable<TSource, TKey, TElement>(source, 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 new GroupedAsyncEnumerableWithTask<TSource, TKey, TElement>(source, 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 new GroupedResultAsyncEnumerable<TSource, TKey, TResult>(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 new GroupedResultAsyncEnumerableWithTask<TSource, TKey, TResult>(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 Task<int> GetCountAsync(bool onlyIfCheap, CancellationToken cancellationToken)
  252. {
  253. if (onlyIfCheap)
  254. {
  255. return TaskExt.MinusOne;
  256. }
  257. return Core();
  258. async Task<int> Core()
  259. {
  260. var l = await Internal.Lookup<TKey, TSource>.CreateAsync(_source, _keySelector, _comparer, cancellationToken).ConfigureAwait(false);
  261. return l.Count;
  262. }
  263. }
  264. }
  265. internal sealed class GroupedResultAsyncEnumerableWithTask<TSource, TKey, TResult> : AsyncIterator<TResult>, IAsyncIListProvider<TResult>
  266. {
  267. private readonly IAsyncEnumerable<TSource> _source;
  268. private readonly Func<TSource, Task<TKey>> _keySelector;
  269. private readonly Func<TKey, IAsyncEnumerable<TSource>, Task<TResult>> _resultSelector;
  270. private readonly IEqualityComparer<TKey> _comparer;
  271. private Internal.LookupWithTask<TKey, TSource> _lookup;
  272. private IAsyncEnumerator<TResult> _enumerator;
  273. public GroupedResultAsyncEnumerableWithTask(IAsyncEnumerable<TSource> source, Func<TSource, Task<TKey>> keySelector, Func<TKey, IAsyncEnumerable<TSource>, Task<TResult>> resultSelector, IEqualityComparer<TKey> comparer)
  274. {
  275. Debug.Assert(source != null);
  276. Debug.Assert(keySelector != null);
  277. Debug.Assert(resultSelector != null);
  278. Debug.Assert(comparer != null);
  279. _source = source;
  280. _keySelector = keySelector;
  281. _resultSelector = resultSelector;
  282. _comparer = comparer;
  283. }
  284. public override AsyncIterator<TResult> Clone()
  285. {
  286. return new GroupedResultAsyncEnumerableWithTask<TSource, TKey, TResult>(_source, _keySelector, _resultSelector, _comparer);
  287. }
  288. public override async ValueTask DisposeAsync()
  289. {
  290. if (_enumerator != null)
  291. {
  292. await _enumerator.DisposeAsync().ConfigureAwait(false);
  293. _enumerator = null;
  294. _lookup = null;
  295. }
  296. await base.DisposeAsync().ConfigureAwait(false);
  297. }
  298. protected override async ValueTask<bool> MoveNextCore(CancellationToken cancellationToken)
  299. {
  300. switch (state)
  301. {
  302. case AsyncIteratorState.Allocated:
  303. _lookup = await Internal.LookupWithTask<TKey, TSource>.CreateAsync(_source, _keySelector, _comparer, cancellationToken).ConfigureAwait(false);
  304. _enumerator = _lookup.Select(async g => await _resultSelector(g.Key, g).ConfigureAwait(false)).GetAsyncEnumerator(cancellationToken);
  305. state = AsyncIteratorState.Iterating;
  306. goto case AsyncIteratorState.Iterating;
  307. case AsyncIteratorState.Iterating:
  308. if (await _enumerator.MoveNextAsync().ConfigureAwait(false))
  309. {
  310. current = _enumerator.Current;
  311. return true;
  312. }
  313. await DisposeAsync().ConfigureAwait(false);
  314. break;
  315. }
  316. return false;
  317. }
  318. public async Task<TResult[]> ToArrayAsync(CancellationToken cancellationToken)
  319. {
  320. var l = await Internal.LookupWithTask<TKey, TSource>.CreateAsync(_source, _keySelector, _comparer, cancellationToken).ConfigureAwait(false);
  321. return await l.ToArray(_resultSelector).ConfigureAwait(false);
  322. }
  323. public async Task<List<TResult>> ToListAsync(CancellationToken cancellationToken)
  324. {
  325. var l = await Internal.LookupWithTask<TKey, TSource>.CreateAsync(_source, _keySelector, _comparer, cancellationToken).ConfigureAwait(false);
  326. return await l.ToList(_resultSelector).ConfigureAwait(false);
  327. }
  328. public Task<int> GetCountAsync(bool onlyIfCheap, CancellationToken cancellationToken)
  329. {
  330. if (onlyIfCheap)
  331. {
  332. return TaskExt.MinusOne;
  333. }
  334. return Core();
  335. async Task<int> Core()
  336. {
  337. var l = await Internal.LookupWithTask<TKey, TSource>.CreateAsync(_source, _keySelector, _comparer, cancellationToken).ConfigureAwait(false);
  338. return l.Count;
  339. }
  340. }
  341. }
  342. internal sealed class GroupedAsyncEnumerable<TSource, TKey, TElement> : AsyncIterator<IAsyncGrouping<TKey, TElement>>, IAsyncIListProvider<IAsyncGrouping<TKey, TElement>>
  343. {
  344. private readonly IAsyncEnumerable<TSource> _source;
  345. private readonly Func<TSource, TKey> _keySelector;
  346. private readonly Func<TSource, TElement> _elementSelector;
  347. private readonly IEqualityComparer<TKey> _comparer;
  348. private Internal.Lookup<TKey, TElement> _lookup;
  349. private IEnumerator<IGrouping<TKey, TElement>> _enumerator;
  350. public GroupedAsyncEnumerable(IAsyncEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector, IEqualityComparer<TKey> comparer)
  351. {
  352. Debug.Assert(source != null);
  353. Debug.Assert(keySelector != null);
  354. Debug.Assert(elementSelector != null);
  355. Debug.Assert(comparer != null);
  356. _source = source;
  357. _keySelector = keySelector;
  358. _elementSelector = elementSelector;
  359. _comparer = comparer;
  360. }
  361. public override AsyncIterator<IAsyncGrouping<TKey, TElement>> Clone()
  362. {
  363. return new GroupedAsyncEnumerable<TSource, TKey, TElement>(_source, _keySelector, _elementSelector, _comparer);
  364. }
  365. public override async ValueTask DisposeAsync()
  366. {
  367. if (_enumerator != null)
  368. {
  369. _enumerator.Dispose();
  370. _enumerator = null;
  371. _lookup = null;
  372. }
  373. await base.DisposeAsync().ConfigureAwait(false);
  374. }
  375. protected override async ValueTask<bool> MoveNextCore(CancellationToken cancellationToken)
  376. {
  377. switch (state)
  378. {
  379. case AsyncIteratorState.Allocated:
  380. _lookup = await Internal.Lookup<TKey, TElement>.CreateAsync(_source, _keySelector, _elementSelector, _comparer, cancellationToken).ConfigureAwait(false);
  381. _enumerator = _lookup.GetEnumerator();
  382. state = AsyncIteratorState.Iterating;
  383. goto case AsyncIteratorState.Iterating;
  384. case AsyncIteratorState.Iterating:
  385. if (_enumerator.MoveNext())
  386. {
  387. current = (IAsyncGrouping<TKey, TElement>)_enumerator.Current;
  388. return true;
  389. }
  390. await DisposeAsync().ConfigureAwait(false);
  391. break;
  392. }
  393. return false;
  394. }
  395. public async Task<IAsyncGrouping<TKey, TElement>[]> ToArrayAsync(CancellationToken cancellationToken)
  396. {
  397. IAsyncIListProvider<IAsyncGrouping<TKey, TElement>> l = await Internal.Lookup<TKey, TElement>.CreateAsync(_source, _keySelector, _elementSelector, _comparer, cancellationToken).ConfigureAwait(false);
  398. return await l.ToArrayAsync(cancellationToken).ConfigureAwait(false);
  399. }
  400. public async Task<List<IAsyncGrouping<TKey, TElement>>> ToListAsync(CancellationToken cancellationToken)
  401. {
  402. IAsyncIListProvider<IAsyncGrouping<TKey, TElement>> l = await Internal.Lookup<TKey, TElement>.CreateAsync(_source, _keySelector, _elementSelector, _comparer, cancellationToken).ConfigureAwait(false);
  403. return await l.ToListAsync(cancellationToken).ConfigureAwait(false);
  404. }
  405. public Task<int> GetCountAsync(bool onlyIfCheap, CancellationToken cancellationToken)
  406. {
  407. if (onlyIfCheap)
  408. {
  409. return TaskExt.MinusOne;
  410. }
  411. return Core();
  412. async Task<int> Core()
  413. {
  414. var l = await Internal.Lookup<TKey, TElement>.CreateAsync(_source, _keySelector, _elementSelector, _comparer, cancellationToken).ConfigureAwait(false);
  415. return l.Count;
  416. }
  417. }
  418. }
  419. internal sealed class GroupedAsyncEnumerableWithTask<TSource, TKey, TElement> : AsyncIterator<IAsyncGrouping<TKey, TElement>>, IAsyncIListProvider<IAsyncGrouping<TKey, TElement>>
  420. {
  421. private readonly IAsyncEnumerable<TSource> _source;
  422. private readonly Func<TSource, Task<TKey>> _keySelector;
  423. private readonly Func<TSource, Task<TElement>> _elementSelector;
  424. private readonly IEqualityComparer<TKey> _comparer;
  425. private Internal.LookupWithTask<TKey, TElement> _lookup;
  426. private IEnumerator<IGrouping<TKey, TElement>> _enumerator;
  427. public GroupedAsyncEnumerableWithTask(IAsyncEnumerable<TSource> source, Func<TSource, Task<TKey>> keySelector, Func<TSource, Task<TElement>> elementSelector, IEqualityComparer<TKey> comparer)
  428. {
  429. Debug.Assert(source != null);
  430. Debug.Assert(keySelector != null);
  431. Debug.Assert(elementSelector != null);
  432. Debug.Assert(comparer != null);
  433. _source = source;
  434. _keySelector = keySelector;
  435. _elementSelector = elementSelector;
  436. _comparer = comparer;
  437. }
  438. public override AsyncIterator<IAsyncGrouping<TKey, TElement>> Clone()
  439. {
  440. return new GroupedAsyncEnumerableWithTask<TSource, TKey, TElement>(_source, _keySelector, _elementSelector, _comparer);
  441. }
  442. public override async ValueTask DisposeAsync()
  443. {
  444. if (_enumerator != null)
  445. {
  446. _enumerator.Dispose();
  447. _enumerator = null;
  448. _lookup = null;
  449. }
  450. await base.DisposeAsync().ConfigureAwait(false);
  451. }
  452. protected override async ValueTask<bool> MoveNextCore(CancellationToken cancellationToken)
  453. {
  454. switch (state)
  455. {
  456. case AsyncIteratorState.Allocated:
  457. _lookup = await Internal.LookupWithTask<TKey, TElement>.CreateAsync(_source, _keySelector, _elementSelector, _comparer, cancellationToken).ConfigureAwait(false);
  458. _enumerator = _lookup.GetEnumerator();
  459. state = AsyncIteratorState.Iterating;
  460. goto case AsyncIteratorState.Iterating;
  461. case AsyncIteratorState.Iterating:
  462. if (_enumerator.MoveNext())
  463. {
  464. current = (IAsyncGrouping<TKey, TElement>)_enumerator.Current;
  465. return true;
  466. }
  467. await DisposeAsync().ConfigureAwait(false);
  468. break;
  469. }
  470. return false;
  471. }
  472. public async Task<IAsyncGrouping<TKey, TElement>[]> ToArrayAsync(CancellationToken cancellationToken)
  473. {
  474. IAsyncIListProvider<IAsyncGrouping<TKey, TElement>> l = await Internal.LookupWithTask<TKey, TElement>.CreateAsync(_source, _keySelector, _elementSelector, _comparer, cancellationToken).ConfigureAwait(false);
  475. return await l.ToArrayAsync(cancellationToken).ConfigureAwait(false);
  476. }
  477. public async Task<List<IAsyncGrouping<TKey, TElement>>> ToListAsync(CancellationToken cancellationToken)
  478. {
  479. IAsyncIListProvider<IAsyncGrouping<TKey, TElement>> l = await Internal.LookupWithTask<TKey, TElement>.CreateAsync(_source, _keySelector, _elementSelector, _comparer, cancellationToken).ConfigureAwait(false);
  480. return await l.ToListAsync(cancellationToken).ConfigureAwait(false);
  481. }
  482. public Task<int> GetCountAsync(bool onlyIfCheap, CancellationToken cancellationToken)
  483. {
  484. if (onlyIfCheap)
  485. {
  486. return TaskExt.MinusOne;
  487. }
  488. return Core();
  489. async Task<int> Core()
  490. {
  491. var l = await Internal.LookupWithTask<TKey, TElement>.CreateAsync(_source, _keySelector, _elementSelector, _comparer, cancellationToken).ConfigureAwait(false);
  492. return l.Count;
  493. }
  494. }
  495. }
  496. internal sealed class GroupedAsyncEnumerable<TSource, TKey> : AsyncIterator<IAsyncGrouping<TKey, TSource>>, IAsyncIListProvider<IAsyncGrouping<TKey, TSource>>
  497. {
  498. private readonly IAsyncEnumerable<TSource> _source;
  499. private readonly Func<TSource, TKey> _keySelector;
  500. private readonly IEqualityComparer<TKey> _comparer;
  501. private Internal.Lookup<TKey, TSource> _lookup;
  502. private IEnumerator<IGrouping<TKey, TSource>> _enumerator;
  503. public GroupedAsyncEnumerable(IAsyncEnumerable<TSource> source, Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer)
  504. {
  505. Debug.Assert(source != null);
  506. Debug.Assert(keySelector != null);
  507. Debug.Assert(comparer != null);
  508. _source = source;
  509. _keySelector = keySelector;
  510. _comparer = comparer;
  511. }
  512. public override AsyncIterator<IAsyncGrouping<TKey, TSource>> Clone()
  513. {
  514. return new GroupedAsyncEnumerable<TSource, TKey>(_source, _keySelector, _comparer);
  515. }
  516. public override async ValueTask DisposeAsync()
  517. {
  518. if (_enumerator != null)
  519. {
  520. _enumerator.Dispose();
  521. _enumerator = null;
  522. _lookup = null;
  523. }
  524. await base.DisposeAsync().ConfigureAwait(false);
  525. }
  526. protected override async ValueTask<bool> MoveNextCore(CancellationToken cancellationToken)
  527. {
  528. switch (state)
  529. {
  530. case AsyncIteratorState.Allocated:
  531. _lookup = await Internal.Lookup<TKey, TSource>.CreateAsync(_source, _keySelector, _comparer, cancellationToken).ConfigureAwait(false);
  532. _enumerator = _lookup.GetEnumerator();
  533. state = AsyncIteratorState.Iterating;
  534. goto case AsyncIteratorState.Iterating;
  535. case AsyncIteratorState.Iterating:
  536. if (_enumerator.MoveNext())
  537. {
  538. current = (IAsyncGrouping<TKey, TSource>)_enumerator.Current;
  539. return true;
  540. }
  541. await DisposeAsync().ConfigureAwait(false);
  542. break;
  543. }
  544. return false;
  545. }
  546. public async Task<IAsyncGrouping<TKey, TSource>[]> ToArrayAsync(CancellationToken cancellationToken)
  547. {
  548. IAsyncIListProvider<IAsyncGrouping<TKey, TSource>> l = await Internal.Lookup<TKey, TSource>.CreateAsync(_source, _keySelector, _comparer, cancellationToken).ConfigureAwait(false);
  549. return await l.ToArrayAsync(cancellationToken).ConfigureAwait(false);
  550. }
  551. public async Task<List<IAsyncGrouping<TKey, TSource>>> ToListAsync(CancellationToken cancellationToken)
  552. {
  553. IAsyncIListProvider<IAsyncGrouping<TKey, TSource>> l = await Internal.Lookup<TKey, TSource>.CreateAsync(_source, _keySelector, _comparer, cancellationToken).ConfigureAwait(false);
  554. return await l.ToListAsync(cancellationToken).ConfigureAwait(false);
  555. }
  556. public Task<int> GetCountAsync(bool onlyIfCheap, CancellationToken cancellationToken)
  557. {
  558. if (onlyIfCheap)
  559. {
  560. return TaskExt.MinusOne;
  561. }
  562. return Core();
  563. async Task<int> Core()
  564. {
  565. var l = await Internal.Lookup<TKey, TSource>.CreateAsync(_source, _keySelector, _comparer, cancellationToken).ConfigureAwait(false);
  566. return l.Count;
  567. }
  568. }
  569. }
  570. internal sealed class GroupedAsyncEnumerableWithTask<TSource, TKey> : AsyncIterator<IAsyncGrouping<TKey, TSource>>, IAsyncIListProvider<IAsyncGrouping<TKey, TSource>>
  571. {
  572. private readonly IAsyncEnumerable<TSource> _source;
  573. private readonly Func<TSource, Task<TKey>> _keySelector;
  574. private readonly IEqualityComparer<TKey> _comparer;
  575. private Internal.LookupWithTask<TKey, TSource> _lookup;
  576. private IEnumerator<IGrouping<TKey, TSource>> _enumerator;
  577. public GroupedAsyncEnumerableWithTask(IAsyncEnumerable<TSource> source, Func<TSource, Task<TKey>> keySelector, IEqualityComparer<TKey> comparer)
  578. {
  579. Debug.Assert(source != null);
  580. Debug.Assert(keySelector != null);
  581. Debug.Assert(comparer != null);
  582. _source = source;
  583. _keySelector = keySelector;
  584. _comparer = comparer;
  585. }
  586. public override AsyncIterator<IAsyncGrouping<TKey, TSource>> Clone()
  587. {
  588. return new GroupedAsyncEnumerableWithTask<TSource, TKey>(_source, _keySelector, _comparer);
  589. }
  590. public override async ValueTask DisposeAsync()
  591. {
  592. if (_enumerator != null)
  593. {
  594. _enumerator.Dispose();
  595. _enumerator = null;
  596. _lookup = null;
  597. }
  598. await base.DisposeAsync().ConfigureAwait(false);
  599. }
  600. protected override async ValueTask<bool> MoveNextCore(CancellationToken cancellationToken)
  601. {
  602. switch (state)
  603. {
  604. case AsyncIteratorState.Allocated:
  605. _lookup = await Internal.LookupWithTask<TKey, TSource>.CreateAsync(_source, _keySelector, _comparer, cancellationToken).ConfigureAwait(false);
  606. _enumerator = _lookup.GetEnumerator();
  607. state = AsyncIteratorState.Iterating;
  608. goto case AsyncIteratorState.Iterating;
  609. case AsyncIteratorState.Iterating:
  610. if (_enumerator.MoveNext())
  611. {
  612. current = (IAsyncGrouping<TKey, TSource>)_enumerator.Current;
  613. return true;
  614. }
  615. await DisposeAsync().ConfigureAwait(false);
  616. break;
  617. }
  618. return false;
  619. }
  620. public async Task<IAsyncGrouping<TKey, TSource>[]> ToArrayAsync(CancellationToken cancellationToken)
  621. {
  622. IAsyncIListProvider<IAsyncGrouping<TKey, TSource>> l = await Internal.LookupWithTask<TKey, TSource>.CreateAsync(_source, _keySelector, _comparer, cancellationToken).ConfigureAwait(false);
  623. return await l.ToArrayAsync(cancellationToken).ConfigureAwait(false);
  624. }
  625. public async Task<List<IAsyncGrouping<TKey, TSource>>> ToListAsync(CancellationToken cancellationToken)
  626. {
  627. IAsyncIListProvider<IAsyncGrouping<TKey, TSource>> l = await Internal.LookupWithTask<TKey, TSource>.CreateAsync(_source, _keySelector, _comparer, cancellationToken).ConfigureAwait(false);
  628. return await l.ToListAsync(cancellationToken).ConfigureAwait(false);
  629. }
  630. public Task<int> GetCountAsync(bool onlyIfCheap, CancellationToken cancellationToken)
  631. {
  632. if (onlyIfCheap)
  633. {
  634. return TaskExt.MinusOne;
  635. }
  636. return Core();
  637. async Task<int> Core()
  638. {
  639. var l = await Internal.LookupWithTask<TKey, TSource>.CreateAsync(_source, _keySelector, _comparer, cancellationToken).ConfigureAwait(false);
  640. return l.Count;
  641. }
  642. }
  643. }
  644. }
  645. }