GroupBy.cs 64 KB

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