GroupBy.cs 54 KB

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