GroupBy.cs 49 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969
  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. GroupedAsyncEnumerable<TSource, TKey>(source, keySelector, comparer: null);
  14. public static IAsyncEnumerable<IAsyncGrouping<TKey, TSource>> GroupBy<TSource, TKey>(this IAsyncEnumerable<TSource> source, Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer) =>
  15. new GroupedAsyncEnumerable<TSource, TKey>(source, keySelector, comparer);
  16. public static IAsyncEnumerable<IAsyncGrouping<TKey, TSource>> GroupBy<TSource, TKey>(this IAsyncEnumerable<TSource> source, Func<TSource, ValueTask<TKey>> keySelector) =>
  17. new GroupedAsyncEnumerableWithTask<TSource, TKey>(source, keySelector, comparer: null);
  18. #if !NO_DEEP_CANCELLATION
  19. public static IAsyncEnumerable<IAsyncGrouping<TKey, TSource>> GroupBy<TSource, TKey>(this IAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, ValueTask<TKey>> keySelector) =>
  20. new GroupedAsyncEnumerableWithTaskAndCancellation<TSource, TKey>(source, keySelector, comparer: null);
  21. #endif
  22. public static IAsyncEnumerable<IAsyncGrouping<TKey, TSource>> GroupBy<TSource, TKey>(this IAsyncEnumerable<TSource> source, Func<TSource, ValueTask<TKey>> keySelector, IEqualityComparer<TKey> comparer) =>
  23. new GroupedAsyncEnumerableWithTask<TSource, TKey>(source, keySelector, comparer);
  24. #if !NO_DEEP_CANCELLATION
  25. public static IAsyncEnumerable<IAsyncGrouping<TKey, TSource>> GroupBy<TSource, TKey>(this IAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, ValueTask<TKey>> keySelector, IEqualityComparer<TKey> comparer) =>
  26. new GroupedAsyncEnumerableWithTaskAndCancellation<TSource, TKey>(source, keySelector, comparer);
  27. #endif
  28. public static IAsyncEnumerable<IAsyncGrouping<TKey, TElement>> GroupBy<TSource, TKey, TElement>(this IAsyncEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector) =>
  29. new GroupedAsyncEnumerable<TSource, TKey, TElement>(source, keySelector, elementSelector, comparer: null);
  30. 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) =>
  31. new GroupedAsyncEnumerable<TSource, TKey, TElement>(source, keySelector, elementSelector, comparer);
  32. public static IAsyncEnumerable<IAsyncGrouping<TKey, TElement>> GroupBy<TSource, TKey, TElement>(this IAsyncEnumerable<TSource> source, Func<TSource, ValueTask<TKey>> keySelector, Func<TSource, ValueTask<TElement>> elementSelector) =>
  33. new GroupedAsyncEnumerableWithTask<TSource, TKey, TElement>(source, keySelector, elementSelector, comparer: null);
  34. #if !NO_DEEP_CANCELLATION
  35. public static IAsyncEnumerable<IAsyncGrouping<TKey, TElement>> GroupBy<TSource, TKey, TElement>(this IAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, ValueTask<TKey>> keySelector, Func<TSource, CancellationToken, ValueTask<TElement>> elementSelector) =>
  36. new GroupedAsyncEnumerableWithTaskAndCancellation<TSource, TKey, TElement>(source, keySelector, elementSelector, comparer: null);
  37. #endif
  38. public static IAsyncEnumerable<IAsyncGrouping<TKey, TElement>> GroupBy<TSource, TKey, TElement>(this IAsyncEnumerable<TSource> source, Func<TSource, ValueTask<TKey>> keySelector, Func<TSource, ValueTask<TElement>> elementSelector, IEqualityComparer<TKey> comparer) =>
  39. new GroupedAsyncEnumerableWithTask<TSource, TKey, TElement>(source, keySelector, elementSelector, comparer);
  40. #if !NO_DEEP_CANCELLATION
  41. public static IAsyncEnumerable<IAsyncGrouping<TKey, TElement>> GroupBy<TSource, TKey, TElement>(this IAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, ValueTask<TKey>> keySelector, Func<TSource, CancellationToken, ValueTask<TElement>> elementSelector, IEqualityComparer<TKey> comparer) =>
  42. new GroupedAsyncEnumerableWithTaskAndCancellation<TSource, TKey, TElement>(source, keySelector, elementSelector, comparer);
  43. #endif
  44. public static IAsyncEnumerable<TResult> GroupBy<TSource, TKey, TResult>(this IAsyncEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TKey, IAsyncEnumerable<TSource>, TResult> resultSelector) =>
  45. new GroupedResultAsyncEnumerable<TSource, TKey, TResult>(source, keySelector, resultSelector, comparer: null);
  46. 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) =>
  47. new GroupedResultAsyncEnumerable<TSource, TKey, TResult>(source, keySelector, resultSelector, comparer);
  48. public static IAsyncEnumerable<TResult> GroupBy<TSource, TKey, TResult>(this IAsyncEnumerable<TSource> source, Func<TSource, ValueTask<TKey>> keySelector, Func<TKey, IAsyncEnumerable<TSource>, ValueTask<TResult>> resultSelector) =>
  49. new GroupedResultAsyncEnumerableWithTask<TSource, TKey, TResult>(source, keySelector, resultSelector, comparer: null);
  50. #if !NO_DEEP_CANCELLATION
  51. public static IAsyncEnumerable<TResult> GroupBy<TSource, TKey, TResult>(this IAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, ValueTask<TKey>> keySelector, Func<TKey, IAsyncEnumerable<TSource>, CancellationToken, ValueTask<TResult>> resultSelector) =>
  52. new GroupedResultAsyncEnumerableWithTaskAndCancellation<TSource, TKey, TResult>(source, keySelector, resultSelector, comparer: null);
  53. #endif
  54. public static IAsyncEnumerable<TResult> GroupBy<TSource, TKey, TResult>(this IAsyncEnumerable<TSource> source, Func<TSource, ValueTask<TKey>> keySelector, Func<TKey, IAsyncEnumerable<TSource>, ValueTask<TResult>> resultSelector, IEqualityComparer<TKey> comparer) =>
  55. new GroupedResultAsyncEnumerableWithTask<TSource, TKey, TResult>(source, keySelector, resultSelector, comparer);
  56. #if !NO_DEEP_CANCELLATION
  57. public static IAsyncEnumerable<TResult> GroupBy<TSource, TKey, TResult>(this IAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, ValueTask<TKey>> keySelector, Func<TKey, IAsyncEnumerable<TSource>, CancellationToken, ValueTask<TResult>> resultSelector, IEqualityComparer<TKey> comparer) =>
  58. new GroupedResultAsyncEnumerableWithTaskAndCancellation<TSource, TKey, TResult>(source, keySelector, resultSelector, comparer);
  59. #endif
  60. 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)
  61. {
  62. if (source == null)
  63. throw Error.ArgumentNull(nameof(source));
  64. if (keySelector == null)
  65. throw Error.ArgumentNull(nameof(keySelector));
  66. if (elementSelector == null)
  67. throw Error.ArgumentNull(nameof(elementSelector));
  68. if (resultSelector == null)
  69. throw Error.ArgumentNull(nameof(resultSelector));
  70. return source.GroupBy(keySelector, elementSelector, comparer: null).Select(g => resultSelector(g.Key, g));
  71. }
  72. 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)
  73. {
  74. if (source == null)
  75. throw Error.ArgumentNull(nameof(source));
  76. if (keySelector == null)
  77. throw Error.ArgumentNull(nameof(keySelector));
  78. if (elementSelector == null)
  79. throw Error.ArgumentNull(nameof(elementSelector));
  80. if (resultSelector == null)
  81. throw Error.ArgumentNull(nameof(resultSelector));
  82. return source.GroupBy(keySelector, elementSelector, comparer).Select(g => resultSelector(g.Key, g));
  83. }
  84. public static IAsyncEnumerable<TResult> GroupBy<TSource, TKey, TElement, TResult>(this IAsyncEnumerable<TSource> source, Func<TSource, ValueTask<TKey>> keySelector, Func<TSource, ValueTask<TElement>> elementSelector, Func<TKey, IAsyncEnumerable<TElement>, ValueTask<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 (elementSelector == null)
  91. throw Error.ArgumentNull(nameof(elementSelector));
  92. if (resultSelector == null)
  93. throw Error.ArgumentNull(nameof(resultSelector));
  94. return source.GroupBy<TSource, TKey, TElement>(keySelector, elementSelector, comparer: null).Select(g => resultSelector(g.Key, g));
  95. }
  96. #if !NO_DEEP_CANCELLATION
  97. public static IAsyncEnumerable<TResult> GroupBy<TSource, TKey, TElement, TResult>(this IAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, ValueTask<TKey>> keySelector, Func<TSource, CancellationToken, ValueTask<TElement>> elementSelector, Func<TKey, IAsyncEnumerable<TElement>, CancellationToken, ValueTask<TResult>> resultSelector)
  98. {
  99. if (source == null)
  100. throw Error.ArgumentNull(nameof(source));
  101. if (keySelector == null)
  102. throw Error.ArgumentNull(nameof(keySelector));
  103. if (elementSelector == null)
  104. throw Error.ArgumentNull(nameof(elementSelector));
  105. if (resultSelector == null)
  106. throw Error.ArgumentNull(nameof(resultSelector));
  107. return source.GroupBy(keySelector, elementSelector, comparer: null).Select((g, ct) => resultSelector(g.Key, g, ct));
  108. }
  109. #endif
  110. public static IAsyncEnumerable<TResult> GroupBy<TSource, TKey, TElement, TResult>(this IAsyncEnumerable<TSource> source, Func<TSource, ValueTask<TKey>> keySelector, Func<TSource, ValueTask<TElement>> elementSelector, Func<TKey, IAsyncEnumerable<TElement>, ValueTask<TResult>> resultSelector, IEqualityComparer<TKey> comparer)
  111. {
  112. if (source == null)
  113. throw Error.ArgumentNull(nameof(source));
  114. if (keySelector == null)
  115. throw Error.ArgumentNull(nameof(keySelector));
  116. if (elementSelector == null)
  117. throw Error.ArgumentNull(nameof(elementSelector));
  118. if (resultSelector == null)
  119. throw Error.ArgumentNull(nameof(resultSelector));
  120. return source.GroupBy(keySelector, elementSelector, comparer).Select(g => resultSelector(g.Key, g));
  121. }
  122. #if !NO_DEEP_CANCELLATION
  123. public static IAsyncEnumerable<TResult> GroupBy<TSource, TKey, TElement, TResult>(this IAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, ValueTask<TKey>> keySelector, Func<TSource, CancellationToken, ValueTask<TElement>> elementSelector, Func<TKey, IAsyncEnumerable<TElement>, CancellationToken, ValueTask<TResult>> resultSelector, IEqualityComparer<TKey> comparer)
  124. {
  125. if (source == null)
  126. throw Error.ArgumentNull(nameof(source));
  127. if (keySelector == null)
  128. throw Error.ArgumentNull(nameof(keySelector));
  129. if (elementSelector == null)
  130. throw Error.ArgumentNull(nameof(elementSelector));
  131. if (resultSelector == null)
  132. throw Error.ArgumentNull(nameof(resultSelector));
  133. return source.GroupBy(keySelector, elementSelector, comparer).Select((g, ct) => resultSelector(g.Key, g, ct));
  134. }
  135. #endif
  136. private sealed class GroupedResultAsyncEnumerable<TSource, TKey, TResult> : AsyncIterator<TResult>, IAsyncIListProvider<TResult>
  137. {
  138. private readonly IAsyncEnumerable<TSource> _source;
  139. private readonly Func<TSource, TKey> _keySelector;
  140. private readonly Func<TKey, IAsyncEnumerable<TSource>, TResult> _resultSelector;
  141. private readonly IEqualityComparer<TKey> _comparer;
  142. private Internal.Lookup<TKey, TSource> _lookup;
  143. private IEnumerator<TResult> _enumerator;
  144. public GroupedResultAsyncEnumerable(IAsyncEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TKey, IAsyncEnumerable<TSource>, TResult> resultSelector, IEqualityComparer<TKey> comparer)
  145. {
  146. _source = source ?? throw Error.ArgumentNull(nameof(source));
  147. _keySelector = keySelector ?? throw Error.ArgumentNull(nameof(keySelector));
  148. _resultSelector = resultSelector ?? throw Error.ArgumentNull(nameof(resultSelector));
  149. _comparer = comparer;
  150. }
  151. public override AsyncIteratorBase<TResult> Clone()
  152. {
  153. return new GroupedResultAsyncEnumerable<TSource, TKey, TResult>(_source, _keySelector, _resultSelector, _comparer);
  154. }
  155. public override async ValueTask DisposeAsync()
  156. {
  157. if (_enumerator != null)
  158. {
  159. _enumerator.Dispose();
  160. _enumerator = null;
  161. _lookup = null;
  162. }
  163. await base.DisposeAsync().ConfigureAwait(false);
  164. }
  165. protected override async ValueTask<bool> MoveNextCore()
  166. {
  167. switch (_state)
  168. {
  169. case AsyncIteratorState.Allocated:
  170. _lookup = await Internal.Lookup<TKey, TSource>.CreateAsync(_source, _keySelector, _comparer, _cancellationToken).ConfigureAwait(false);
  171. _enumerator = _lookup.ApplyResultSelector(_resultSelector).GetEnumerator();
  172. _state = AsyncIteratorState.Iterating;
  173. goto case AsyncIteratorState.Iterating;
  174. case AsyncIteratorState.Iterating:
  175. if (_enumerator.MoveNext())
  176. {
  177. _current = _enumerator.Current;
  178. return true;
  179. }
  180. await DisposeAsync().ConfigureAwait(false);
  181. break;
  182. }
  183. return false;
  184. }
  185. public async ValueTask<TResult[]> ToArrayAsync(CancellationToken cancellationToken)
  186. {
  187. var l = await Internal.Lookup<TKey, TSource>.CreateAsync(_source, _keySelector, _comparer, cancellationToken).ConfigureAwait(false);
  188. return l.ToArray(_resultSelector);
  189. }
  190. public async ValueTask<List<TResult>> ToListAsync(CancellationToken cancellationToken)
  191. {
  192. var l = await Internal.Lookup<TKey, TSource>.CreateAsync(_source, _keySelector, _comparer, cancellationToken).ConfigureAwait(false);
  193. return l.ToList(_resultSelector);
  194. }
  195. public ValueTask<int> GetCountAsync(bool onlyIfCheap, CancellationToken cancellationToken)
  196. {
  197. if (onlyIfCheap)
  198. {
  199. return new ValueTask<int>(-1);
  200. }
  201. return Core();
  202. async ValueTask<int> Core()
  203. {
  204. var l = await Internal.Lookup<TKey, TSource>.CreateAsync(_source, _keySelector, _comparer, cancellationToken).ConfigureAwait(false);
  205. return l.Count;
  206. }
  207. }
  208. }
  209. private sealed class GroupedResultAsyncEnumerableWithTask<TSource, TKey, TResult> : AsyncIterator<TResult>, IAsyncIListProvider<TResult>
  210. {
  211. private readonly IAsyncEnumerable<TSource> _source;
  212. private readonly Func<TSource, ValueTask<TKey>> _keySelector;
  213. private readonly Func<TKey, IAsyncEnumerable<TSource>, ValueTask<TResult>> _resultSelector;
  214. private readonly IEqualityComparer<TKey> _comparer;
  215. private Internal.LookupWithTask<TKey, TSource> _lookup;
  216. private IAsyncEnumerator<TResult> _enumerator;
  217. public GroupedResultAsyncEnumerableWithTask(IAsyncEnumerable<TSource> source, Func<TSource, ValueTask<TKey>> keySelector, Func<TKey, IAsyncEnumerable<TSource>, ValueTask<TResult>> resultSelector, IEqualityComparer<TKey> comparer)
  218. {
  219. _source = source ?? throw Error.ArgumentNull(nameof(source));
  220. _keySelector = keySelector ?? throw Error.ArgumentNull(nameof(keySelector));
  221. _resultSelector = resultSelector ?? throw Error.ArgumentNull(nameof(resultSelector));
  222. _comparer = comparer;
  223. }
  224. public override AsyncIteratorBase<TResult> Clone()
  225. {
  226. return new GroupedResultAsyncEnumerableWithTask<TSource, TKey, TResult>(_source, _keySelector, _resultSelector, _comparer);
  227. }
  228. public override async ValueTask DisposeAsync()
  229. {
  230. if (_enumerator != null)
  231. {
  232. await _enumerator.DisposeAsync().ConfigureAwait(false);
  233. _enumerator = null;
  234. _lookup = null;
  235. }
  236. await base.DisposeAsync().ConfigureAwait(false);
  237. }
  238. protected override async ValueTask<bool> MoveNextCore()
  239. {
  240. switch (_state)
  241. {
  242. case AsyncIteratorState.Allocated:
  243. _lookup = await Internal.LookupWithTask<TKey, TSource>.CreateAsync(_source, _keySelector, _comparer, _cancellationToken).ConfigureAwait(false);
  244. _enumerator = _lookup.Select(async g => await _resultSelector(g.Key, g).ConfigureAwait(false)).GetAsyncEnumerator(_cancellationToken);
  245. _state = AsyncIteratorState.Iterating;
  246. goto case AsyncIteratorState.Iterating;
  247. case AsyncIteratorState.Iterating:
  248. if (await _enumerator.MoveNextAsync().ConfigureAwait(false))
  249. {
  250. _current = _enumerator.Current;
  251. return true;
  252. }
  253. await DisposeAsync().ConfigureAwait(false);
  254. break;
  255. }
  256. return false;
  257. }
  258. public async ValueTask<TResult[]> ToArrayAsync(CancellationToken cancellationToken)
  259. {
  260. var l = await Internal.LookupWithTask<TKey, TSource>.CreateAsync(_source, _keySelector, _comparer, cancellationToken).ConfigureAwait(false);
  261. return await l.ToArray(_resultSelector).ConfigureAwait(false);
  262. }
  263. public async ValueTask<List<TResult>> ToListAsync(CancellationToken cancellationToken)
  264. {
  265. var l = await Internal.LookupWithTask<TKey, TSource>.CreateAsync(_source, _keySelector, _comparer, cancellationToken).ConfigureAwait(false);
  266. return await l.ToList(_resultSelector).ConfigureAwait(false);
  267. }
  268. public ValueTask<int> GetCountAsync(bool onlyIfCheap, CancellationToken cancellationToken)
  269. {
  270. if (onlyIfCheap)
  271. {
  272. return new ValueTask<int>(-1);
  273. }
  274. return Core();
  275. async ValueTask<int> Core()
  276. {
  277. var l = await Internal.LookupWithTask<TKey, TSource>.CreateAsync(_source, _keySelector, _comparer, cancellationToken).ConfigureAwait(false);
  278. return l.Count;
  279. }
  280. }
  281. }
  282. #if !NO_DEEP_CANCELLATION
  283. private sealed class GroupedResultAsyncEnumerableWithTaskAndCancellation<TSource, TKey, TResult> : AsyncIterator<TResult>, IAsyncIListProvider<TResult>
  284. {
  285. private readonly IAsyncEnumerable<TSource> _source;
  286. private readonly Func<TSource, CancellationToken, ValueTask<TKey>> _keySelector;
  287. private readonly Func<TKey, IAsyncEnumerable<TSource>, CancellationToken, ValueTask<TResult>> _resultSelector;
  288. private readonly IEqualityComparer<TKey> _comparer;
  289. private Internal.LookupWithTask<TKey, TSource> _lookup;
  290. private IAsyncEnumerator<TResult> _enumerator;
  291. public GroupedResultAsyncEnumerableWithTaskAndCancellation(IAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, ValueTask<TKey>> keySelector, Func<TKey, IAsyncEnumerable<TSource>, CancellationToken, ValueTask<TResult>> resultSelector, IEqualityComparer<TKey> comparer)
  292. {
  293. _source = source ?? throw Error.ArgumentNull(nameof(source));
  294. _keySelector = keySelector ?? throw Error.ArgumentNull(nameof(keySelector));
  295. _resultSelector = resultSelector ?? throw Error.ArgumentNull(nameof(resultSelector));
  296. _comparer = comparer;
  297. }
  298. public override AsyncIteratorBase<TResult> Clone()
  299. {
  300. return new GroupedResultAsyncEnumerableWithTaskAndCancellation<TSource, TKey, TResult>(_source, _keySelector, _resultSelector, _comparer);
  301. }
  302. public override async ValueTask DisposeAsync()
  303. {
  304. if (_enumerator != null)
  305. {
  306. await _enumerator.DisposeAsync().ConfigureAwait(false);
  307. _enumerator = null;
  308. _lookup = null;
  309. }
  310. await base.DisposeAsync().ConfigureAwait(false);
  311. }
  312. protected override async ValueTask<bool> MoveNextCore()
  313. {
  314. switch (_state)
  315. {
  316. case AsyncIteratorState.Allocated:
  317. _lookup = await Internal.LookupWithTask<TKey, TSource>.CreateAsync(_source, _keySelector, _comparer, _cancellationToken).ConfigureAwait(false);
  318. _enumerator = _lookup.Select(async g => await _resultSelector(g.Key, g, _cancellationToken).ConfigureAwait(false)).GetAsyncEnumerator(_cancellationToken);
  319. _state = AsyncIteratorState.Iterating;
  320. goto case AsyncIteratorState.Iterating;
  321. case AsyncIteratorState.Iterating:
  322. if (await _enumerator.MoveNextAsync().ConfigureAwait(false))
  323. {
  324. _current = _enumerator.Current;
  325. return true;
  326. }
  327. await DisposeAsync().ConfigureAwait(false);
  328. break;
  329. }
  330. return false;
  331. }
  332. public async ValueTask<TResult[]> ToArrayAsync(CancellationToken cancellationToken)
  333. {
  334. var l = await Internal.LookupWithTask<TKey, TSource>.CreateAsync(_source, _keySelector, _comparer, cancellationToken).ConfigureAwait(false);
  335. return await l.ToArray(_resultSelector, cancellationToken).ConfigureAwait(false);
  336. }
  337. public async ValueTask<List<TResult>> ToListAsync(CancellationToken cancellationToken)
  338. {
  339. var l = await Internal.LookupWithTask<TKey, TSource>.CreateAsync(_source, _keySelector, _comparer, cancellationToken).ConfigureAwait(false);
  340. return await l.ToList(_resultSelector, cancellationToken).ConfigureAwait(false);
  341. }
  342. public ValueTask<int> GetCountAsync(bool onlyIfCheap, CancellationToken cancellationToken)
  343. {
  344. if (onlyIfCheap)
  345. {
  346. return new ValueTask<int>(-1);
  347. }
  348. return Core();
  349. async ValueTask<int> Core()
  350. {
  351. var l = await Internal.LookupWithTask<TKey, TSource>.CreateAsync(_source, _keySelector, _comparer, cancellationToken).ConfigureAwait(false);
  352. return l.Count;
  353. }
  354. }
  355. }
  356. #endif
  357. private sealed class GroupedAsyncEnumerable<TSource, TKey, TElement> : AsyncIterator<IAsyncGrouping<TKey, TElement>>, IAsyncIListProvider<IAsyncGrouping<TKey, TElement>>
  358. {
  359. private readonly IAsyncEnumerable<TSource> _source;
  360. private readonly Func<TSource, TKey> _keySelector;
  361. private readonly Func<TSource, TElement> _elementSelector;
  362. private readonly IEqualityComparer<TKey> _comparer;
  363. private Internal.Lookup<TKey, TElement> _lookup;
  364. private IEnumerator<IGrouping<TKey, TElement>> _enumerator;
  365. public GroupedAsyncEnumerable(IAsyncEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector, IEqualityComparer<TKey> comparer)
  366. {
  367. _source = source ?? throw Error.ArgumentNull(nameof(source));
  368. _keySelector = keySelector ?? throw Error.ArgumentNull(nameof(keySelector));
  369. _elementSelector = elementSelector ?? throw Error.ArgumentNull(nameof(elementSelector));
  370. _comparer = comparer;
  371. }
  372. public override AsyncIteratorBase<IAsyncGrouping<TKey, TElement>> Clone()
  373. {
  374. return new GroupedAsyncEnumerable<TSource, TKey, TElement>(_source, _keySelector, _elementSelector, _comparer);
  375. }
  376. public override async ValueTask DisposeAsync()
  377. {
  378. if (_enumerator != null)
  379. {
  380. _enumerator.Dispose();
  381. _enumerator = null;
  382. _lookup = null;
  383. }
  384. await base.DisposeAsync().ConfigureAwait(false);
  385. }
  386. protected override async ValueTask<bool> MoveNextCore()
  387. {
  388. switch (_state)
  389. {
  390. case AsyncIteratorState.Allocated:
  391. _lookup = await Internal.Lookup<TKey, TElement>.CreateAsync(_source, _keySelector, _elementSelector, _comparer, _cancellationToken).ConfigureAwait(false);
  392. _enumerator = _lookup.GetEnumerator();
  393. _state = AsyncIteratorState.Iterating;
  394. goto case AsyncIteratorState.Iterating;
  395. case AsyncIteratorState.Iterating:
  396. if (_enumerator.MoveNext())
  397. {
  398. _current = (IAsyncGrouping<TKey, TElement>)_enumerator.Current;
  399. return true;
  400. }
  401. await DisposeAsync().ConfigureAwait(false);
  402. break;
  403. }
  404. return false;
  405. }
  406. public async ValueTask<IAsyncGrouping<TKey, TElement>[]> ToArrayAsync(CancellationToken cancellationToken)
  407. {
  408. IAsyncIListProvider<IAsyncGrouping<TKey, TElement>> l = await Internal.Lookup<TKey, TElement>.CreateAsync(_source, _keySelector, _elementSelector, _comparer, cancellationToken).ConfigureAwait(false);
  409. return await l.ToArrayAsync(cancellationToken).ConfigureAwait(false);
  410. }
  411. public async ValueTask<List<IAsyncGrouping<TKey, TElement>>> ToListAsync(CancellationToken cancellationToken)
  412. {
  413. IAsyncIListProvider<IAsyncGrouping<TKey, TElement>> l = await Internal.Lookup<TKey, TElement>.CreateAsync(_source, _keySelector, _elementSelector, _comparer, cancellationToken).ConfigureAwait(false);
  414. return await l.ToListAsync(cancellationToken).ConfigureAwait(false);
  415. }
  416. public ValueTask<int> GetCountAsync(bool onlyIfCheap, CancellationToken cancellationToken)
  417. {
  418. if (onlyIfCheap)
  419. {
  420. return new ValueTask<int>(-1);
  421. }
  422. return Core();
  423. async ValueTask<int> Core()
  424. {
  425. var l = await Internal.Lookup<TKey, TElement>.CreateAsync(_source, _keySelector, _elementSelector, _comparer, cancellationToken).ConfigureAwait(false);
  426. return l.Count;
  427. }
  428. }
  429. }
  430. private sealed class GroupedAsyncEnumerableWithTask<TSource, TKey, TElement> : AsyncIterator<IAsyncGrouping<TKey, TElement>>, IAsyncIListProvider<IAsyncGrouping<TKey, TElement>>
  431. {
  432. private readonly IAsyncEnumerable<TSource> _source;
  433. private readonly Func<TSource, ValueTask<TKey>> _keySelector;
  434. private readonly Func<TSource, ValueTask<TElement>> _elementSelector;
  435. private readonly IEqualityComparer<TKey> _comparer;
  436. private Internal.LookupWithTask<TKey, TElement> _lookup;
  437. private IEnumerator<IGrouping<TKey, TElement>> _enumerator;
  438. public GroupedAsyncEnumerableWithTask(IAsyncEnumerable<TSource> source, Func<TSource, ValueTask<TKey>> keySelector, Func<TSource, ValueTask<TElement>> elementSelector, IEqualityComparer<TKey> comparer)
  439. {
  440. _source = source ?? throw Error.ArgumentNull(nameof(source));
  441. _keySelector = keySelector ?? throw Error.ArgumentNull(nameof(keySelector));
  442. _elementSelector = elementSelector ?? throw Error.ArgumentNull(nameof(elementSelector));
  443. _comparer = comparer;
  444. }
  445. public override AsyncIteratorBase<IAsyncGrouping<TKey, TElement>> Clone()
  446. {
  447. return new GroupedAsyncEnumerableWithTask<TSource, TKey, TElement>(_source, _keySelector, _elementSelector, _comparer);
  448. }
  449. public override async ValueTask DisposeAsync()
  450. {
  451. if (_enumerator != null)
  452. {
  453. _enumerator.Dispose();
  454. _enumerator = null;
  455. _lookup = null;
  456. }
  457. await base.DisposeAsync().ConfigureAwait(false);
  458. }
  459. protected override async ValueTask<bool> MoveNextCore()
  460. {
  461. switch (_state)
  462. {
  463. case AsyncIteratorState.Allocated:
  464. _lookup = await Internal.LookupWithTask<TKey, TElement>.CreateAsync(_source, _keySelector, _elementSelector, _comparer, _cancellationToken).ConfigureAwait(false);
  465. _enumerator = _lookup.GetEnumerator();
  466. _state = AsyncIteratorState.Iterating;
  467. goto case AsyncIteratorState.Iterating;
  468. case AsyncIteratorState.Iterating:
  469. if (_enumerator.MoveNext())
  470. {
  471. _current = (IAsyncGrouping<TKey, TElement>)_enumerator.Current;
  472. return true;
  473. }
  474. await DisposeAsync().ConfigureAwait(false);
  475. break;
  476. }
  477. return false;
  478. }
  479. public async ValueTask<IAsyncGrouping<TKey, TElement>[]> ToArrayAsync(CancellationToken cancellationToken)
  480. {
  481. IAsyncIListProvider<IAsyncGrouping<TKey, TElement>> l = await Internal.LookupWithTask<TKey, TElement>.CreateAsync(_source, _keySelector, _elementSelector, _comparer, cancellationToken).ConfigureAwait(false);
  482. return await l.ToArrayAsync(cancellationToken).ConfigureAwait(false);
  483. }
  484. public async ValueTask<List<IAsyncGrouping<TKey, TElement>>> ToListAsync(CancellationToken cancellationToken)
  485. {
  486. IAsyncIListProvider<IAsyncGrouping<TKey, TElement>> l = await Internal.LookupWithTask<TKey, TElement>.CreateAsync(_source, _keySelector, _elementSelector, _comparer, cancellationToken).ConfigureAwait(false);
  487. return await l.ToListAsync(cancellationToken).ConfigureAwait(false);
  488. }
  489. public ValueTask<int> GetCountAsync(bool onlyIfCheap, CancellationToken cancellationToken)
  490. {
  491. if (onlyIfCheap)
  492. {
  493. return new ValueTask<int>(-1);
  494. }
  495. return Core();
  496. async ValueTask<int> Core()
  497. {
  498. var l = await Internal.LookupWithTask<TKey, TElement>.CreateAsync(_source, _keySelector, _elementSelector, _comparer, cancellationToken).ConfigureAwait(false);
  499. return l.Count;
  500. }
  501. }
  502. }
  503. #if !NO_DEEP_CANCELLATION
  504. private sealed class GroupedAsyncEnumerableWithTaskAndCancellation<TSource, TKey, TElement> : AsyncIterator<IAsyncGrouping<TKey, TElement>>, IAsyncIListProvider<IAsyncGrouping<TKey, TElement>>
  505. {
  506. private readonly IAsyncEnumerable<TSource> _source;
  507. private readonly Func<TSource, CancellationToken, ValueTask<TKey>> _keySelector;
  508. private readonly Func<TSource, CancellationToken, ValueTask<TElement>> _elementSelector;
  509. private readonly IEqualityComparer<TKey> _comparer;
  510. private Internal.LookupWithTask<TKey, TElement> _lookup;
  511. private IEnumerator<IGrouping<TKey, TElement>> _enumerator;
  512. public GroupedAsyncEnumerableWithTaskAndCancellation(IAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, ValueTask<TKey>> keySelector, Func<TSource, CancellationToken, ValueTask<TElement>> elementSelector, IEqualityComparer<TKey> comparer)
  513. {
  514. _source = source ?? throw Error.ArgumentNull(nameof(source));
  515. _keySelector = keySelector ?? throw Error.ArgumentNull(nameof(keySelector));
  516. _elementSelector = elementSelector ?? throw Error.ArgumentNull(nameof(elementSelector));
  517. _comparer = comparer;
  518. }
  519. public override AsyncIteratorBase<IAsyncGrouping<TKey, TElement>> Clone()
  520. {
  521. return new GroupedAsyncEnumerableWithTaskAndCancellation<TSource, TKey, TElement>(_source, _keySelector, _elementSelector, _comparer);
  522. }
  523. public override async ValueTask DisposeAsync()
  524. {
  525. if (_enumerator != null)
  526. {
  527. _enumerator.Dispose();
  528. _enumerator = null;
  529. _lookup = null;
  530. }
  531. await base.DisposeAsync().ConfigureAwait(false);
  532. }
  533. protected override async ValueTask<bool> MoveNextCore()
  534. {
  535. switch (_state)
  536. {
  537. case AsyncIteratorState.Allocated:
  538. _lookup = await Internal.LookupWithTask<TKey, TElement>.CreateAsync(_source, _keySelector, _elementSelector, _comparer, _cancellationToken).ConfigureAwait(false);
  539. _enumerator = _lookup.GetEnumerator();
  540. _state = AsyncIteratorState.Iterating;
  541. goto case AsyncIteratorState.Iterating;
  542. case AsyncIteratorState.Iterating:
  543. if (_enumerator.MoveNext())
  544. {
  545. _current = (IAsyncGrouping<TKey, TElement>)_enumerator.Current;
  546. return true;
  547. }
  548. await DisposeAsync().ConfigureAwait(false);
  549. break;
  550. }
  551. return false;
  552. }
  553. public async ValueTask<IAsyncGrouping<TKey, TElement>[]> ToArrayAsync(CancellationToken cancellationToken)
  554. {
  555. IAsyncIListProvider<IAsyncGrouping<TKey, TElement>> l = await Internal.LookupWithTask<TKey, TElement>.CreateAsync(_source, _keySelector, _elementSelector, _comparer, cancellationToken).ConfigureAwait(false);
  556. return await l.ToArrayAsync(cancellationToken).ConfigureAwait(false);
  557. }
  558. public async ValueTask<List<IAsyncGrouping<TKey, TElement>>> ToListAsync(CancellationToken cancellationToken)
  559. {
  560. IAsyncIListProvider<IAsyncGrouping<TKey, TElement>> l = await Internal.LookupWithTask<TKey, TElement>.CreateAsync(_source, _keySelector, _elementSelector, _comparer, cancellationToken).ConfigureAwait(false);
  561. return await l.ToListAsync(cancellationToken).ConfigureAwait(false);
  562. }
  563. public ValueTask<int> GetCountAsync(bool onlyIfCheap, CancellationToken cancellationToken)
  564. {
  565. if (onlyIfCheap)
  566. {
  567. return new ValueTask<int>(-1);
  568. }
  569. return Core();
  570. async ValueTask<int> Core()
  571. {
  572. var l = await Internal.LookupWithTask<TKey, TElement>.CreateAsync(_source, _keySelector, _elementSelector, _comparer, cancellationToken).ConfigureAwait(false);
  573. return l.Count;
  574. }
  575. }
  576. }
  577. #endif
  578. private sealed class GroupedAsyncEnumerable<TSource, TKey> : AsyncIterator<IAsyncGrouping<TKey, TSource>>, IAsyncIListProvider<IAsyncGrouping<TKey, TSource>>
  579. {
  580. private readonly IAsyncEnumerable<TSource> _source;
  581. private readonly Func<TSource, TKey> _keySelector;
  582. private readonly IEqualityComparer<TKey> _comparer;
  583. private Internal.Lookup<TKey, TSource> _lookup;
  584. private IEnumerator<IGrouping<TKey, TSource>> _enumerator;
  585. public GroupedAsyncEnumerable(IAsyncEnumerable<TSource> source, Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer)
  586. {
  587. _source = source ?? throw Error.ArgumentNull(nameof(source));
  588. _keySelector = keySelector ?? throw Error.ArgumentNull(nameof(keySelector));
  589. _comparer = comparer;
  590. }
  591. public override AsyncIteratorBase<IAsyncGrouping<TKey, TSource>> Clone()
  592. {
  593. return new GroupedAsyncEnumerable<TSource, TKey>(_source, _keySelector, _comparer);
  594. }
  595. public override async ValueTask DisposeAsync()
  596. {
  597. if (_enumerator != null)
  598. {
  599. _enumerator.Dispose();
  600. _enumerator = null;
  601. _lookup = null;
  602. }
  603. await base.DisposeAsync().ConfigureAwait(false);
  604. }
  605. protected override async ValueTask<bool> MoveNextCore()
  606. {
  607. switch (_state)
  608. {
  609. case AsyncIteratorState.Allocated:
  610. _lookup = await Internal.Lookup<TKey, TSource>.CreateAsync(_source, _keySelector, _comparer, _cancellationToken).ConfigureAwait(false);
  611. _enumerator = _lookup.GetEnumerator();
  612. _state = AsyncIteratorState.Iterating;
  613. goto case AsyncIteratorState.Iterating;
  614. case AsyncIteratorState.Iterating:
  615. if (_enumerator.MoveNext())
  616. {
  617. _current = (IAsyncGrouping<TKey, TSource>)_enumerator.Current;
  618. return true;
  619. }
  620. await DisposeAsync().ConfigureAwait(false);
  621. break;
  622. }
  623. return false;
  624. }
  625. public async ValueTask<IAsyncGrouping<TKey, TSource>[]> ToArrayAsync(CancellationToken cancellationToken)
  626. {
  627. IAsyncIListProvider<IAsyncGrouping<TKey, TSource>> l = await Internal.Lookup<TKey, TSource>.CreateAsync(_source, _keySelector, _comparer, cancellationToken).ConfigureAwait(false);
  628. return await l.ToArrayAsync(cancellationToken).ConfigureAwait(false);
  629. }
  630. public async ValueTask<List<IAsyncGrouping<TKey, TSource>>> ToListAsync(CancellationToken cancellationToken)
  631. {
  632. IAsyncIListProvider<IAsyncGrouping<TKey, TSource>> l = await Internal.Lookup<TKey, TSource>.CreateAsync(_source, _keySelector, _comparer, cancellationToken).ConfigureAwait(false);
  633. return await l.ToListAsync(cancellationToken).ConfigureAwait(false);
  634. }
  635. public ValueTask<int> GetCountAsync(bool onlyIfCheap, CancellationToken cancellationToken)
  636. {
  637. if (onlyIfCheap)
  638. {
  639. return new ValueTask<int>(-1);
  640. }
  641. return Core();
  642. async ValueTask<int> Core()
  643. {
  644. var l = await Internal.Lookup<TKey, TSource>.CreateAsync(_source, _keySelector, _comparer, cancellationToken).ConfigureAwait(false);
  645. return l.Count;
  646. }
  647. }
  648. }
  649. private sealed class GroupedAsyncEnumerableWithTask<TSource, TKey> : AsyncIterator<IAsyncGrouping<TKey, TSource>>, IAsyncIListProvider<IAsyncGrouping<TKey, TSource>>
  650. {
  651. private readonly IAsyncEnumerable<TSource> _source;
  652. private readonly Func<TSource, ValueTask<TKey>> _keySelector;
  653. private readonly IEqualityComparer<TKey> _comparer;
  654. private Internal.LookupWithTask<TKey, TSource> _lookup;
  655. private IEnumerator<IGrouping<TKey, TSource>> _enumerator;
  656. public GroupedAsyncEnumerableWithTask(IAsyncEnumerable<TSource> source, Func<TSource, ValueTask<TKey>> keySelector, IEqualityComparer<TKey> comparer)
  657. {
  658. _source = source ?? throw Error.ArgumentNull(nameof(source));
  659. _keySelector = keySelector ?? throw Error.ArgumentNull(nameof(keySelector));
  660. _comparer = comparer;
  661. }
  662. public override AsyncIteratorBase<IAsyncGrouping<TKey, TSource>> Clone()
  663. {
  664. return new GroupedAsyncEnumerableWithTask<TSource, TKey>(_source, _keySelector, _comparer);
  665. }
  666. public override async ValueTask DisposeAsync()
  667. {
  668. if (_enumerator != null)
  669. {
  670. _enumerator.Dispose();
  671. _enumerator = null;
  672. _lookup = null;
  673. }
  674. await base.DisposeAsync().ConfigureAwait(false);
  675. }
  676. protected override async ValueTask<bool> MoveNextCore()
  677. {
  678. switch (_state)
  679. {
  680. case AsyncIteratorState.Allocated:
  681. _lookup = await Internal.LookupWithTask<TKey, TSource>.CreateAsync(_source, _keySelector, _comparer, _cancellationToken).ConfigureAwait(false);
  682. _enumerator = _lookup.GetEnumerator();
  683. _state = AsyncIteratorState.Iterating;
  684. goto case AsyncIteratorState.Iterating;
  685. case AsyncIteratorState.Iterating:
  686. if (_enumerator.MoveNext())
  687. {
  688. _current = (IAsyncGrouping<TKey, TSource>)_enumerator.Current;
  689. return true;
  690. }
  691. await DisposeAsync().ConfigureAwait(false);
  692. break;
  693. }
  694. return false;
  695. }
  696. public async ValueTask<IAsyncGrouping<TKey, TSource>[]> ToArrayAsync(CancellationToken cancellationToken)
  697. {
  698. IAsyncIListProvider<IAsyncGrouping<TKey, TSource>> l = await Internal.LookupWithTask<TKey, TSource>.CreateAsync(_source, _keySelector, _comparer, cancellationToken).ConfigureAwait(false);
  699. return await l.ToArrayAsync(cancellationToken).ConfigureAwait(false);
  700. }
  701. public async ValueTask<List<IAsyncGrouping<TKey, TSource>>> ToListAsync(CancellationToken cancellationToken)
  702. {
  703. IAsyncIListProvider<IAsyncGrouping<TKey, TSource>> l = await Internal.LookupWithTask<TKey, TSource>.CreateAsync(_source, _keySelector, _comparer, cancellationToken).ConfigureAwait(false);
  704. return await l.ToListAsync(cancellationToken).ConfigureAwait(false);
  705. }
  706. public ValueTask<int> GetCountAsync(bool onlyIfCheap, CancellationToken cancellationToken)
  707. {
  708. if (onlyIfCheap)
  709. {
  710. return new ValueTask<int>(-1);
  711. }
  712. return Core();
  713. async ValueTask<int> Core()
  714. {
  715. var l = await Internal.LookupWithTask<TKey, TSource>.CreateAsync(_source, _keySelector, _comparer, cancellationToken).ConfigureAwait(false);
  716. return l.Count;
  717. }
  718. }
  719. }
  720. #if !NO_DEEP_CANCELLATION
  721. private sealed class GroupedAsyncEnumerableWithTaskAndCancellation<TSource, TKey> : AsyncIterator<IAsyncGrouping<TKey, TSource>>, IAsyncIListProvider<IAsyncGrouping<TKey, TSource>>
  722. {
  723. private readonly IAsyncEnumerable<TSource> _source;
  724. private readonly Func<TSource, CancellationToken, ValueTask<TKey>> _keySelector;
  725. private readonly IEqualityComparer<TKey> _comparer;
  726. private Internal.LookupWithTask<TKey, TSource> _lookup;
  727. private IEnumerator<IGrouping<TKey, TSource>> _enumerator;
  728. public GroupedAsyncEnumerableWithTaskAndCancellation(IAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, ValueTask<TKey>> keySelector, IEqualityComparer<TKey> comparer)
  729. {
  730. _source = source ?? throw Error.ArgumentNull(nameof(source));
  731. _keySelector = keySelector ?? throw Error.ArgumentNull(nameof(keySelector));
  732. _comparer = comparer;
  733. }
  734. public override AsyncIteratorBase<IAsyncGrouping<TKey, TSource>> Clone()
  735. {
  736. return new GroupedAsyncEnumerableWithTaskAndCancellation<TSource, TKey>(_source, _keySelector, _comparer);
  737. }
  738. public override async ValueTask DisposeAsync()
  739. {
  740. if (_enumerator != null)
  741. {
  742. _enumerator.Dispose();
  743. _enumerator = null;
  744. _lookup = null;
  745. }
  746. await base.DisposeAsync().ConfigureAwait(false);
  747. }
  748. protected override async ValueTask<bool> MoveNextCore()
  749. {
  750. switch (_state)
  751. {
  752. case AsyncIteratorState.Allocated:
  753. _lookup = await Internal.LookupWithTask<TKey, TSource>.CreateAsync(_source, _keySelector, _comparer, _cancellationToken).ConfigureAwait(false);
  754. _enumerator = _lookup.GetEnumerator();
  755. _state = AsyncIteratorState.Iterating;
  756. goto case AsyncIteratorState.Iterating;
  757. case AsyncIteratorState.Iterating:
  758. if (_enumerator.MoveNext())
  759. {
  760. _current = (IAsyncGrouping<TKey, TSource>)_enumerator.Current;
  761. return true;
  762. }
  763. await DisposeAsync().ConfigureAwait(false);
  764. break;
  765. }
  766. return false;
  767. }
  768. public async ValueTask<IAsyncGrouping<TKey, TSource>[]> ToArrayAsync(CancellationToken cancellationToken)
  769. {
  770. IAsyncIListProvider<IAsyncGrouping<TKey, TSource>> l = await Internal.LookupWithTask<TKey, TSource>.CreateAsync(_source, _keySelector, _comparer, cancellationToken).ConfigureAwait(false);
  771. return await l.ToArrayAsync(cancellationToken).ConfigureAwait(false);
  772. }
  773. public async ValueTask<List<IAsyncGrouping<TKey, TSource>>> ToListAsync(CancellationToken cancellationToken)
  774. {
  775. IAsyncIListProvider<IAsyncGrouping<TKey, TSource>> l = await Internal.LookupWithTask<TKey, TSource>.CreateAsync(_source, _keySelector, _comparer, cancellationToken).ConfigureAwait(false);
  776. return await l.ToListAsync(cancellationToken).ConfigureAwait(false);
  777. }
  778. public ValueTask<int> GetCountAsync(bool onlyIfCheap, CancellationToken cancellationToken)
  779. {
  780. if (onlyIfCheap)
  781. {
  782. return new ValueTask<int>(-1);
  783. }
  784. return Core();
  785. async ValueTask<int> Core()
  786. {
  787. var l = await Internal.LookupWithTask<TKey, TSource>.CreateAsync(_source, _keySelector, _comparer, cancellationToken).ConfigureAwait(false);
  788. return l.Count;
  789. }
  790. }
  791. }
  792. #endif
  793. }
  794. }