GroupBy.cs 60 KB

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