SkipWhile.cs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372
  1. // Licensed to the .NET Foundation under one or more agreements.
  2. // The .NET Foundation licenses this file to you under the Apache 2.0 License.
  3. // See the LICENSE file in the project root for more information.
  4. using System.Collections.Generic;
  5. using System.Diagnostics;
  6. using System.Threading;
  7. using System.Threading.Tasks;
  8. namespace System.Linq
  9. {
  10. public static partial class AsyncEnumerable
  11. {
  12. public static IAsyncEnumerable<TSource> SkipWhile<TSource>(this IAsyncEnumerable<TSource> source, Func<TSource, bool> predicate)
  13. {
  14. if (source == null)
  15. throw new ArgumentNullException(nameof(source));
  16. if (predicate == null)
  17. throw new ArgumentNullException(nameof(predicate));
  18. return new SkipWhileAsyncIterator<TSource>(source, predicate);
  19. }
  20. public static IAsyncEnumerable<TSource> SkipWhile<TSource>(this IAsyncEnumerable<TSource> source, Func<TSource, int, bool> predicate)
  21. {
  22. if (source == null)
  23. throw new ArgumentNullException(nameof(source));
  24. if (predicate == null)
  25. throw new ArgumentNullException(nameof(predicate));
  26. return new SkipWhileWithIndexAsyncIterator<TSource>(source, predicate);
  27. }
  28. public static IAsyncEnumerable<TSource> SkipWhile<TSource>(this IAsyncEnumerable<TSource> source, Func<TSource, Task<bool>> predicate)
  29. {
  30. if (source == null)
  31. throw new ArgumentNullException(nameof(source));
  32. if (predicate == null)
  33. throw new ArgumentNullException(nameof(predicate));
  34. return new SkipWhileAsyncIteratorWithTask<TSource>(source, predicate);
  35. }
  36. public static IAsyncEnumerable<TSource> SkipWhile<TSource>(this IAsyncEnumerable<TSource> source, Func<TSource, int, Task<bool>> predicate)
  37. {
  38. if (source == null)
  39. throw new ArgumentNullException(nameof(source));
  40. if (predicate == null)
  41. throw new ArgumentNullException(nameof(predicate));
  42. return new SkipWhileWithIndexAsyncIteratorWithTask<TSource>(source, predicate);
  43. }
  44. private sealed class SkipWhileAsyncIterator<TSource> : AsyncIterator<TSource>
  45. {
  46. private readonly Func<TSource, bool> predicate;
  47. private readonly IAsyncEnumerable<TSource> source;
  48. private bool doMoveNext;
  49. private IAsyncEnumerator<TSource> enumerator;
  50. public SkipWhileAsyncIterator(IAsyncEnumerable<TSource> source, Func<TSource, bool> predicate)
  51. {
  52. Debug.Assert(predicate != null);
  53. Debug.Assert(source != null);
  54. this.source = source;
  55. this.predicate = predicate;
  56. }
  57. public override AsyncIterator<TSource> Clone()
  58. {
  59. return new SkipWhileAsyncIterator<TSource>(source, predicate);
  60. }
  61. public override async ValueTask DisposeAsync()
  62. {
  63. if (enumerator != null)
  64. {
  65. await enumerator.DisposeAsync().ConfigureAwait(false);
  66. enumerator = null;
  67. }
  68. await base.DisposeAsync().ConfigureAwait(false);
  69. }
  70. protected override async ValueTask<bool> MoveNextCore(CancellationToken cancellationToken)
  71. {
  72. switch (state)
  73. {
  74. case AsyncIteratorState.Allocated:
  75. enumerator = source.GetAsyncEnumerator(cancellationToken);
  76. // skip elements as requested
  77. while (await enumerator.MoveNextAsync().ConfigureAwait(false))
  78. {
  79. var element = enumerator.Current;
  80. if (!predicate(element))
  81. {
  82. doMoveNext = false;
  83. state = AsyncIteratorState.Iterating;
  84. goto case AsyncIteratorState.Iterating;
  85. }
  86. }
  87. break;
  88. case AsyncIteratorState.Iterating:
  89. if (doMoveNext && await enumerator.MoveNextAsync().ConfigureAwait(false))
  90. {
  91. current = enumerator.Current;
  92. return true;
  93. }
  94. if (!doMoveNext)
  95. {
  96. current = enumerator.Current;
  97. doMoveNext = true;
  98. return true;
  99. }
  100. break;
  101. }
  102. await DisposeAsync().ConfigureAwait(false);
  103. return false;
  104. }
  105. }
  106. private sealed class SkipWhileWithIndexAsyncIterator<TSource> : AsyncIterator<TSource>
  107. {
  108. private readonly Func<TSource, int, bool> predicate;
  109. private readonly IAsyncEnumerable<TSource> source;
  110. private bool doMoveNext;
  111. private IAsyncEnumerator<TSource> enumerator;
  112. private int index;
  113. public SkipWhileWithIndexAsyncIterator(IAsyncEnumerable<TSource> source, Func<TSource, int, bool> predicate)
  114. {
  115. Debug.Assert(predicate != null);
  116. Debug.Assert(source != null);
  117. this.source = source;
  118. this.predicate = predicate;
  119. }
  120. public override AsyncIterator<TSource> Clone()
  121. {
  122. return new SkipWhileWithIndexAsyncIterator<TSource>(source, predicate);
  123. }
  124. public override async ValueTask DisposeAsync()
  125. {
  126. if (enumerator != null)
  127. {
  128. await enumerator.DisposeAsync().ConfigureAwait(false);
  129. enumerator = null;
  130. }
  131. await base.DisposeAsync().ConfigureAwait(false);
  132. }
  133. protected override async ValueTask<bool> MoveNextCore(CancellationToken cancellationToken)
  134. {
  135. switch (state)
  136. {
  137. case AsyncIteratorState.Allocated:
  138. enumerator = source.GetAsyncEnumerator(cancellationToken);
  139. index = -1;
  140. // skip elements as requested
  141. while (await enumerator.MoveNextAsync().ConfigureAwait(false))
  142. {
  143. checked
  144. {
  145. index++;
  146. }
  147. var element = enumerator.Current;
  148. if (!predicate(element, index))
  149. {
  150. doMoveNext = false;
  151. state = AsyncIteratorState.Iterating;
  152. goto case AsyncIteratorState.Iterating;
  153. }
  154. }
  155. break;
  156. case AsyncIteratorState.Iterating:
  157. if (doMoveNext && await enumerator.MoveNextAsync().ConfigureAwait(false))
  158. {
  159. current = enumerator.Current;
  160. return true;
  161. }
  162. if (!doMoveNext)
  163. {
  164. current = enumerator.Current;
  165. doMoveNext = true;
  166. return true;
  167. }
  168. break;
  169. }
  170. await DisposeAsync().ConfigureAwait(false);
  171. return false;
  172. }
  173. }
  174. private sealed class SkipWhileAsyncIteratorWithTask<TSource> : AsyncIterator<TSource>
  175. {
  176. private readonly Func<TSource, Task<bool>> predicate;
  177. private readonly IAsyncEnumerable<TSource> source;
  178. private bool doMoveNext;
  179. private IAsyncEnumerator<TSource> enumerator;
  180. public SkipWhileAsyncIteratorWithTask(IAsyncEnumerable<TSource> source, Func<TSource, Task<bool>> predicate)
  181. {
  182. Debug.Assert(predicate != null);
  183. Debug.Assert(source != null);
  184. this.source = source;
  185. this.predicate = predicate;
  186. }
  187. public override AsyncIterator<TSource> Clone()
  188. {
  189. return new SkipWhileAsyncIteratorWithTask<TSource>(source, predicate);
  190. }
  191. public override async ValueTask DisposeAsync()
  192. {
  193. if (enumerator != null)
  194. {
  195. await enumerator.DisposeAsync().ConfigureAwait(false);
  196. enumerator = null;
  197. }
  198. await base.DisposeAsync().ConfigureAwait(false);
  199. }
  200. protected override async ValueTask<bool> MoveNextCore(CancellationToken cancellationToken)
  201. {
  202. switch (state)
  203. {
  204. case AsyncIteratorState.Allocated:
  205. enumerator = source.GetAsyncEnumerator(cancellationToken);
  206. // skip elements as requested
  207. while (await enumerator.MoveNextAsync().ConfigureAwait(false))
  208. {
  209. var element = enumerator.Current;
  210. if (!await predicate(element).ConfigureAwait(false))
  211. {
  212. doMoveNext = false;
  213. state = AsyncIteratorState.Iterating;
  214. goto case AsyncIteratorState.Iterating;
  215. }
  216. }
  217. break;
  218. case AsyncIteratorState.Iterating:
  219. if (doMoveNext && await enumerator.MoveNextAsync().ConfigureAwait(false))
  220. {
  221. current = enumerator.Current;
  222. return true;
  223. }
  224. if (!doMoveNext)
  225. {
  226. current = enumerator.Current;
  227. doMoveNext = true;
  228. return true;
  229. }
  230. break;
  231. }
  232. await DisposeAsync().ConfigureAwait(false);
  233. return false;
  234. }
  235. }
  236. private sealed class SkipWhileWithIndexAsyncIteratorWithTask<TSource> : AsyncIterator<TSource>
  237. {
  238. private readonly Func<TSource, int, Task<bool>> predicate;
  239. private readonly IAsyncEnumerable<TSource> source;
  240. private bool doMoveNext;
  241. private IAsyncEnumerator<TSource> enumerator;
  242. private int index;
  243. public SkipWhileWithIndexAsyncIteratorWithTask(IAsyncEnumerable<TSource> source, Func<TSource, int, Task<bool>> predicate)
  244. {
  245. Debug.Assert(predicate != null);
  246. Debug.Assert(source != null);
  247. this.source = source;
  248. this.predicate = predicate;
  249. }
  250. public override AsyncIterator<TSource> Clone()
  251. {
  252. return new SkipWhileWithIndexAsyncIteratorWithTask<TSource>(source, predicate);
  253. }
  254. public override async ValueTask DisposeAsync()
  255. {
  256. if (enumerator != null)
  257. {
  258. await enumerator.DisposeAsync().ConfigureAwait(false);
  259. enumerator = null;
  260. }
  261. await base.DisposeAsync().ConfigureAwait(false);
  262. }
  263. protected override async ValueTask<bool> MoveNextCore(CancellationToken cancellationToken)
  264. {
  265. switch (state)
  266. {
  267. case AsyncIteratorState.Allocated:
  268. enumerator = source.GetAsyncEnumerator(cancellationToken);
  269. index = -1;
  270. // skip elements as requested
  271. while (await enumerator.MoveNextAsync().ConfigureAwait(false))
  272. {
  273. checked
  274. {
  275. index++;
  276. }
  277. var element = enumerator.Current;
  278. if (!await predicate(element, index).ConfigureAwait(false))
  279. {
  280. doMoveNext = false;
  281. state = AsyncIteratorState.Iterating;
  282. goto case AsyncIteratorState.Iterating;
  283. }
  284. }
  285. break;
  286. case AsyncIteratorState.Iterating:
  287. if (doMoveNext && await enumerator.MoveNextAsync().ConfigureAwait(false))
  288. {
  289. current = enumerator.Current;
  290. return true;
  291. }
  292. if (!doMoveNext)
  293. {
  294. current = enumerator.Current;
  295. doMoveNext = true;
  296. return true;
  297. }
  298. break;
  299. }
  300. await DisposeAsync().ConfigureAwait(false);
  301. return false;
  302. }
  303. }
  304. }
  305. }