Select.cs 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451
  1. // Licensed to the .NET Foundation under one or more agreements.
  2. // The .NET Foundation licenses this file to you under the Apache 2.0 License.
  3. // See the LICENSE file in the project root for more information.
  4. using System.Collections.Generic;
  5. using System.Diagnostics;
  6. using System.Threading.Tasks;
  7. namespace System.Linq
  8. {
  9. public static partial class AsyncEnumerable
  10. {
  11. public static IAsyncEnumerable<TResult> Select<TSource, TResult>(this IAsyncEnumerable<TSource> source, Func<TSource, TResult> selector)
  12. {
  13. if (source == null)
  14. throw new ArgumentNullException(nameof(source));
  15. if (selector == null)
  16. throw new ArgumentNullException(nameof(selector));
  17. if (source is AsyncIterator<TSource> iterator)
  18. {
  19. return iterator.Select(selector);
  20. }
  21. if (source is IList<TSource> ilist)
  22. {
  23. return new SelectIListIterator<TSource, TResult>(ilist, selector);
  24. }
  25. return new SelectEnumerableAsyncIterator<TSource, TResult>(source, selector);
  26. }
  27. public static IAsyncEnumerable<TResult> Select<TSource, TResult>(this IAsyncEnumerable<TSource> source, Func<TSource, int, TResult> selector)
  28. {
  29. if (source == null)
  30. throw new ArgumentNullException(nameof(source));
  31. if (selector == null)
  32. throw new ArgumentNullException(nameof(selector));
  33. return new SelectEnumerableWithIndexAsyncIterator<TSource, TResult>(source, selector);
  34. }
  35. public static IAsyncEnumerable<TResult> Select<TSource, TResult>(this IAsyncEnumerable<TSource> source, Func<TSource, Task<TResult>> selector)
  36. {
  37. if (source == null)
  38. throw new ArgumentNullException(nameof(source));
  39. if (selector == null)
  40. throw new ArgumentNullException(nameof(selector));
  41. if (source is AsyncIterator<TSource> iterator)
  42. {
  43. return iterator.Select(selector);
  44. }
  45. if (source is IList<TSource> ilist)
  46. {
  47. return new SelectIListIteratorWithTask<TSource, TResult>(ilist, selector);
  48. }
  49. return new SelectEnumerableAsyncIteratorWithTask<TSource, TResult>(source, selector);
  50. }
  51. public static IAsyncEnumerable<TResult> Select<TSource, TResult>(this IAsyncEnumerable<TSource> source, Func<TSource, int, Task<TResult>> selector)
  52. {
  53. if (source == null)
  54. throw new ArgumentNullException(nameof(source));
  55. if (selector == null)
  56. throw new ArgumentNullException(nameof(selector));
  57. return new SelectEnumerableWithIndexAsyncIteratorWithTask<TSource, TResult>(source, selector);
  58. }
  59. private static Func<TSource, TResult> CombineSelectors<TSource, TMiddle, TResult>(Func<TSource, TMiddle> selector1, Func<TMiddle, TResult> selector2)
  60. {
  61. return x => selector2(selector1(x));
  62. }
  63. private static Func<TSource, Task<TResult>> CombineSelectors<TSource, TMiddle, TResult>(Func<TSource, Task<TMiddle>> selector1, Func<TMiddle, Task<TResult>> selector2)
  64. {
  65. return async x => await selector2(await selector1(x).ConfigureAwait(false)).ConfigureAwait(false);
  66. }
  67. internal sealed class SelectEnumerableAsyncIterator<TSource, TResult> : AsyncIterator<TResult>
  68. {
  69. private readonly Func<TSource, TResult> selector;
  70. private readonly IAsyncEnumerable<TSource> source;
  71. private IAsyncEnumerator<TSource> enumerator;
  72. public SelectEnumerableAsyncIterator(IAsyncEnumerable<TSource> source, Func<TSource, TResult> selector)
  73. {
  74. Debug.Assert(source != null);
  75. Debug.Assert(selector != null);
  76. this.source = source;
  77. this.selector = selector;
  78. }
  79. public override AsyncIterator<TResult> Clone()
  80. {
  81. return new SelectEnumerableAsyncIterator<TSource, TResult>(source, selector);
  82. }
  83. public override async Task DisposeAsync()
  84. {
  85. if (enumerator != null)
  86. {
  87. await enumerator.DisposeAsync().ConfigureAwait(false);
  88. enumerator = null;
  89. }
  90. await base.DisposeAsync().ConfigureAwait(false);
  91. }
  92. public override IAsyncEnumerable<TResult1> Select<TResult1>(Func<TResult, TResult1> selector)
  93. {
  94. return new SelectEnumerableAsyncIterator<TSource, TResult1>(source, CombineSelectors(this.selector, selector));
  95. }
  96. protected override async Task<bool> MoveNextCore()
  97. {
  98. switch (state)
  99. {
  100. case AsyncIteratorState.Allocated:
  101. enumerator = source.GetAsyncEnumerator();
  102. state = AsyncIteratorState.Iterating;
  103. goto case AsyncIteratorState.Iterating;
  104. case AsyncIteratorState.Iterating:
  105. if (await enumerator.MoveNextAsync()
  106. .ConfigureAwait(false))
  107. {
  108. current = selector(enumerator.Current);
  109. return true;
  110. }
  111. await DisposeAsync().ConfigureAwait(false);
  112. break;
  113. }
  114. return false;
  115. }
  116. }
  117. internal sealed class SelectEnumerableWithIndexAsyncIterator<TSource, TResult> : AsyncIterator<TResult>
  118. {
  119. private readonly Func<TSource, int, TResult> selector;
  120. private readonly IAsyncEnumerable<TSource> source;
  121. private IAsyncEnumerator<TSource> enumerator;
  122. private int index;
  123. public SelectEnumerableWithIndexAsyncIterator(IAsyncEnumerable<TSource> source, Func<TSource, int, TResult> selector)
  124. {
  125. Debug.Assert(source != null);
  126. Debug.Assert(selector != null);
  127. this.source = source;
  128. this.selector = selector;
  129. }
  130. public override AsyncIterator<TResult> Clone()
  131. {
  132. return new SelectEnumerableWithIndexAsyncIterator<TSource, TResult>(source, selector);
  133. }
  134. public override async Task DisposeAsync()
  135. {
  136. if (enumerator != null)
  137. {
  138. await enumerator.DisposeAsync().ConfigureAwait(false);
  139. enumerator = null;
  140. }
  141. await base.DisposeAsync().ConfigureAwait(false);
  142. }
  143. protected override async Task<bool> MoveNextCore()
  144. {
  145. switch (state)
  146. {
  147. case AsyncIteratorState.Allocated:
  148. enumerator = source.GetAsyncEnumerator();
  149. index = -1;
  150. state = AsyncIteratorState.Iterating;
  151. goto case AsyncIteratorState.Iterating;
  152. case AsyncIteratorState.Iterating:
  153. if (await enumerator.MoveNextAsync()
  154. .ConfigureAwait(false))
  155. {
  156. checked
  157. {
  158. index++;
  159. }
  160. current = selector(enumerator.Current, index);
  161. return true;
  162. }
  163. await DisposeAsync().ConfigureAwait(false);
  164. break;
  165. }
  166. return false;
  167. }
  168. }
  169. internal sealed class SelectIListIterator<TSource, TResult> : AsyncIterator<TResult>
  170. {
  171. private readonly Func<TSource, TResult> selector;
  172. private readonly IList<TSource> source;
  173. private IEnumerator<TSource> enumerator;
  174. public SelectIListIterator(IList<TSource> source, Func<TSource, TResult> selector)
  175. {
  176. Debug.Assert(source != null);
  177. Debug.Assert(selector != null);
  178. this.source = source;
  179. this.selector = selector;
  180. }
  181. public override AsyncIterator<TResult> Clone()
  182. {
  183. return new SelectIListIterator<TSource, TResult>(source, selector);
  184. }
  185. public override async Task DisposeAsync()
  186. {
  187. if (enumerator != null)
  188. {
  189. enumerator.Dispose();
  190. enumerator = null;
  191. }
  192. await base.DisposeAsync().ConfigureAwait(false);
  193. }
  194. public override IAsyncEnumerable<TResult1> Select<TResult1>(Func<TResult, TResult1> selector)
  195. {
  196. return new SelectIListIterator<TSource, TResult1>(source, CombineSelectors(this.selector, selector));
  197. }
  198. protected override async Task<bool> MoveNextCore()
  199. {
  200. switch (state)
  201. {
  202. case AsyncIteratorState.Allocated:
  203. enumerator = source.GetEnumerator();
  204. state = AsyncIteratorState.Iterating;
  205. goto case AsyncIteratorState.Iterating;
  206. case AsyncIteratorState.Iterating:
  207. if (enumerator.MoveNext())
  208. {
  209. current = selector(enumerator.Current);
  210. return true;
  211. }
  212. await DisposeAsync().ConfigureAwait(false);
  213. break;
  214. }
  215. return false;
  216. }
  217. }
  218. internal sealed class SelectEnumerableAsyncIteratorWithTask<TSource, TResult> : AsyncIterator<TResult>
  219. {
  220. private readonly Func<TSource, Task<TResult>> selector;
  221. private readonly IAsyncEnumerable<TSource> source;
  222. private IAsyncEnumerator<TSource> enumerator;
  223. public SelectEnumerableAsyncIteratorWithTask(IAsyncEnumerable<TSource> source, Func<TSource, Task<TResult>> selector)
  224. {
  225. Debug.Assert(source != null);
  226. Debug.Assert(selector != null);
  227. this.source = source;
  228. this.selector = selector;
  229. }
  230. public override AsyncIterator<TResult> Clone()
  231. {
  232. return new SelectEnumerableAsyncIteratorWithTask<TSource, TResult>(source, selector);
  233. }
  234. public override async Task DisposeAsync()
  235. {
  236. if (enumerator != null)
  237. {
  238. await enumerator.DisposeAsync().ConfigureAwait(false);
  239. enumerator = null;
  240. }
  241. await base.DisposeAsync().ConfigureAwait(false);
  242. }
  243. public override IAsyncEnumerable<TResult1> Select<TResult1>(Func<TResult, Task<TResult1>> selector)
  244. {
  245. return new SelectEnumerableAsyncIteratorWithTask<TSource, TResult1>(source, CombineSelectors(this.selector, selector));
  246. }
  247. protected override async Task<bool> MoveNextCore()
  248. {
  249. switch (state)
  250. {
  251. case AsyncIteratorState.Allocated:
  252. enumerator = source.GetAsyncEnumerator();
  253. state = AsyncIteratorState.Iterating;
  254. goto case AsyncIteratorState.Iterating;
  255. case AsyncIteratorState.Iterating:
  256. if (await enumerator.MoveNextAsync()
  257. .ConfigureAwait(false))
  258. {
  259. current = await selector(enumerator.Current).ConfigureAwait(false);
  260. return true;
  261. }
  262. await DisposeAsync().ConfigureAwait(false);
  263. break;
  264. }
  265. return false;
  266. }
  267. }
  268. internal sealed class SelectEnumerableWithIndexAsyncIteratorWithTask<TSource, TResult> : AsyncIterator<TResult>
  269. {
  270. private readonly Func<TSource, int, Task<TResult>> selector;
  271. private readonly IAsyncEnumerable<TSource> source;
  272. private IAsyncEnumerator<TSource> enumerator;
  273. private int index;
  274. public SelectEnumerableWithIndexAsyncIteratorWithTask(IAsyncEnumerable<TSource> source, Func<TSource, int, Task<TResult>> selector)
  275. {
  276. Debug.Assert(source != null);
  277. Debug.Assert(selector != null);
  278. this.source = source;
  279. this.selector = selector;
  280. }
  281. public override AsyncIterator<TResult> Clone()
  282. {
  283. return new SelectEnumerableWithIndexAsyncIteratorWithTask<TSource, TResult>(source, selector);
  284. }
  285. public override async Task DisposeAsync()
  286. {
  287. if (enumerator != null)
  288. {
  289. await enumerator.DisposeAsync().ConfigureAwait(false);
  290. enumerator = null;
  291. }
  292. await base.DisposeAsync().ConfigureAwait(false);
  293. }
  294. protected override async Task<bool> MoveNextCore()
  295. {
  296. switch (state)
  297. {
  298. case AsyncIteratorState.Allocated:
  299. enumerator = source.GetAsyncEnumerator();
  300. index = -1;
  301. state = AsyncIteratorState.Iterating;
  302. goto case AsyncIteratorState.Iterating;
  303. case AsyncIteratorState.Iterating:
  304. if (await enumerator.MoveNextAsync()
  305. .ConfigureAwait(false))
  306. {
  307. checked
  308. {
  309. index++;
  310. }
  311. current = await selector(enumerator.Current, index).ConfigureAwait(false);
  312. return true;
  313. }
  314. await DisposeAsync().ConfigureAwait(false);
  315. break;
  316. }
  317. return false;
  318. }
  319. }
  320. internal sealed class SelectIListIteratorWithTask<TSource, TResult> : AsyncIterator<TResult>
  321. {
  322. private readonly Func<TSource, Task<TResult>> selector;
  323. private readonly IList<TSource> source;
  324. private IEnumerator<TSource> enumerator;
  325. public SelectIListIteratorWithTask(IList<TSource> source, Func<TSource, Task<TResult>> selector)
  326. {
  327. Debug.Assert(source != null);
  328. Debug.Assert(selector != null);
  329. this.source = source;
  330. this.selector = selector;
  331. }
  332. public override AsyncIterator<TResult> Clone()
  333. {
  334. return new SelectIListIteratorWithTask<TSource, TResult>(source, selector);
  335. }
  336. public override async Task DisposeAsync()
  337. {
  338. if (enumerator != null)
  339. {
  340. enumerator.Dispose();
  341. enumerator = null;
  342. }
  343. await base.DisposeAsync().ConfigureAwait(false);
  344. }
  345. public override IAsyncEnumerable<TResult1> Select<TResult1>(Func<TResult, Task<TResult1>> selector)
  346. {
  347. return new SelectIListIteratorWithTask<TSource, TResult1>(source, CombineSelectors(this.selector, selector));
  348. }
  349. protected override async Task<bool> MoveNextCore()
  350. {
  351. switch (state)
  352. {
  353. case AsyncIteratorState.Allocated:
  354. enumerator = source.GetEnumerator();
  355. state = AsyncIteratorState.Iterating;
  356. goto case AsyncIteratorState.Iterating;
  357. case AsyncIteratorState.Iterating:
  358. if (enumerator.MoveNext())
  359. {
  360. current = await selector(enumerator.Current).ConfigureAwait(false);
  361. return true;
  362. }
  363. await DisposeAsync().ConfigureAwait(false);
  364. break;
  365. }
  366. return false;
  367. }
  368. }
  369. }
  370. }