SkipWhile.cs 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562
  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 Error.ArgumentNull(nameof(source));
  16. if (predicate == null)
  17. throw Error.ArgumentNull(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 Error.ArgumentNull(nameof(source));
  24. if (predicate == null)
  25. throw Error.ArgumentNull(nameof(predicate));
  26. return new SkipWhileWithIndexAsyncIterator<TSource>(source, predicate);
  27. }
  28. public static IAsyncEnumerable<TSource> SkipWhile<TSource>(this IAsyncEnumerable<TSource> source, Func<TSource, ValueTask<bool>> predicate)
  29. {
  30. if (source == null)
  31. throw Error.ArgumentNull(nameof(source));
  32. if (predicate == null)
  33. throw Error.ArgumentNull(nameof(predicate));
  34. return new SkipWhileAsyncIteratorWithTask<TSource>(source, predicate);
  35. }
  36. #if !NO_DEEP_CANCELLATION
  37. public static IAsyncEnumerable<TSource> SkipWhile<TSource>(this IAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, ValueTask<bool>> predicate)
  38. {
  39. if (source == null)
  40. throw Error.ArgumentNull(nameof(source));
  41. if (predicate == null)
  42. throw Error.ArgumentNull(nameof(predicate));
  43. return new SkipWhileAsyncIteratorWithTaskAndCancellation<TSource>(source, predicate);
  44. }
  45. #endif
  46. public static IAsyncEnumerable<TSource> SkipWhile<TSource>(this IAsyncEnumerable<TSource> source, Func<TSource, int, ValueTask<bool>> predicate)
  47. {
  48. if (source == null)
  49. throw Error.ArgumentNull(nameof(source));
  50. if (predicate == null)
  51. throw Error.ArgumentNull(nameof(predicate));
  52. return new SkipWhileWithIndexAsyncIteratorWithTask<TSource>(source, predicate);
  53. }
  54. #if !NO_DEEP_CANCELLATION
  55. public static IAsyncEnumerable<TSource> SkipWhile<TSource>(this IAsyncEnumerable<TSource> source, Func<TSource, int, CancellationToken, ValueTask<bool>> predicate)
  56. {
  57. if (source == null)
  58. throw Error.ArgumentNull(nameof(source));
  59. if (predicate == null)
  60. throw Error.ArgumentNull(nameof(predicate));
  61. return new SkipWhileWithIndexAsyncIteratorWithTaskAndCancellation<TSource>(source, predicate);
  62. }
  63. #endif
  64. private sealed class SkipWhileAsyncIterator<TSource> : AsyncIterator<TSource>
  65. {
  66. private readonly Func<TSource, bool> _predicate;
  67. private readonly IAsyncEnumerable<TSource> _source;
  68. private bool _doMoveNext;
  69. private IAsyncEnumerator<TSource> _enumerator;
  70. public SkipWhileAsyncIterator(IAsyncEnumerable<TSource> source, Func<TSource, bool> predicate)
  71. {
  72. Debug.Assert(predicate != null);
  73. Debug.Assert(source != null);
  74. _source = source;
  75. _predicate = predicate;
  76. }
  77. public override AsyncIteratorBase<TSource> Clone()
  78. {
  79. return new SkipWhileAsyncIterator<TSource>(_source, _predicate);
  80. }
  81. public override async ValueTask DisposeAsync()
  82. {
  83. if (_enumerator != null)
  84. {
  85. await _enumerator.DisposeAsync().ConfigureAwait(false);
  86. _enumerator = null;
  87. }
  88. await base.DisposeAsync().ConfigureAwait(false);
  89. }
  90. protected override async ValueTask<bool> MoveNextCore()
  91. {
  92. switch (_state)
  93. {
  94. case AsyncIteratorState.Allocated:
  95. _enumerator = _source.GetAsyncEnumerator(_cancellationToken);
  96. // skip elements as requested
  97. while (await _enumerator.MoveNextAsync().ConfigureAwait(false))
  98. {
  99. var element = _enumerator.Current;
  100. if (!_predicate(element))
  101. {
  102. _doMoveNext = false;
  103. _state = AsyncIteratorState.Iterating;
  104. goto case AsyncIteratorState.Iterating;
  105. }
  106. }
  107. break;
  108. case AsyncIteratorState.Iterating:
  109. if (_doMoveNext && await _enumerator.MoveNextAsync().ConfigureAwait(false))
  110. {
  111. _current = _enumerator.Current;
  112. return true;
  113. }
  114. if (!_doMoveNext)
  115. {
  116. _current = _enumerator.Current;
  117. _doMoveNext = true;
  118. return true;
  119. }
  120. break;
  121. }
  122. await DisposeAsync().ConfigureAwait(false);
  123. return false;
  124. }
  125. }
  126. private sealed class SkipWhileWithIndexAsyncIterator<TSource> : AsyncIterator<TSource>
  127. {
  128. private readonly Func<TSource, int, bool> _predicate;
  129. private readonly IAsyncEnumerable<TSource> _source;
  130. private bool _doMoveNext;
  131. private IAsyncEnumerator<TSource> _enumerator;
  132. private int _index;
  133. public SkipWhileWithIndexAsyncIterator(IAsyncEnumerable<TSource> source, Func<TSource, int, bool> predicate)
  134. {
  135. Debug.Assert(predicate != null);
  136. Debug.Assert(source != null);
  137. _source = source;
  138. _predicate = predicate;
  139. }
  140. public override AsyncIteratorBase<TSource> Clone()
  141. {
  142. return new SkipWhileWithIndexAsyncIterator<TSource>(_source, _predicate);
  143. }
  144. public override async ValueTask DisposeAsync()
  145. {
  146. if (_enumerator != null)
  147. {
  148. await _enumerator.DisposeAsync().ConfigureAwait(false);
  149. _enumerator = null;
  150. }
  151. await base.DisposeAsync().ConfigureAwait(false);
  152. }
  153. protected override async ValueTask<bool> MoveNextCore()
  154. {
  155. switch (_state)
  156. {
  157. case AsyncIteratorState.Allocated:
  158. _enumerator = _source.GetAsyncEnumerator(_cancellationToken);
  159. _index = -1;
  160. // skip elements as requested
  161. while (await _enumerator.MoveNextAsync().ConfigureAwait(false))
  162. {
  163. var element = _enumerator.Current;
  164. checked
  165. {
  166. _index++;
  167. }
  168. if (!_predicate(element, _index))
  169. {
  170. _doMoveNext = false;
  171. _state = AsyncIteratorState.Iterating;
  172. goto case AsyncIteratorState.Iterating;
  173. }
  174. }
  175. break;
  176. case AsyncIteratorState.Iterating:
  177. if (_doMoveNext && await _enumerator.MoveNextAsync().ConfigureAwait(false))
  178. {
  179. _current = _enumerator.Current;
  180. return true;
  181. }
  182. if (!_doMoveNext)
  183. {
  184. _current = _enumerator.Current;
  185. _doMoveNext = true;
  186. return true;
  187. }
  188. break;
  189. }
  190. await DisposeAsync().ConfigureAwait(false);
  191. return false;
  192. }
  193. }
  194. private sealed class SkipWhileAsyncIteratorWithTask<TSource> : AsyncIterator<TSource>
  195. {
  196. private readonly Func<TSource, ValueTask<bool>> _predicate;
  197. private readonly IAsyncEnumerable<TSource> _source;
  198. private bool _doMoveNext;
  199. private IAsyncEnumerator<TSource> _enumerator;
  200. public SkipWhileAsyncIteratorWithTask(IAsyncEnumerable<TSource> source, Func<TSource, ValueTask<bool>> predicate)
  201. {
  202. Debug.Assert(predicate != null);
  203. Debug.Assert(source != null);
  204. _source = source;
  205. _predicate = predicate;
  206. }
  207. public override AsyncIteratorBase<TSource> Clone()
  208. {
  209. return new SkipWhileAsyncIteratorWithTask<TSource>(_source, _predicate);
  210. }
  211. public override async ValueTask DisposeAsync()
  212. {
  213. if (_enumerator != null)
  214. {
  215. await _enumerator.DisposeAsync().ConfigureAwait(false);
  216. _enumerator = null;
  217. }
  218. await base.DisposeAsync().ConfigureAwait(false);
  219. }
  220. protected override async ValueTask<bool> MoveNextCore()
  221. {
  222. switch (_state)
  223. {
  224. case AsyncIteratorState.Allocated:
  225. _enumerator = _source.GetAsyncEnumerator(_cancellationToken);
  226. // skip elements as requested
  227. while (await _enumerator.MoveNextAsync().ConfigureAwait(false))
  228. {
  229. var element = _enumerator.Current;
  230. if (!await _predicate(element).ConfigureAwait(false))
  231. {
  232. _doMoveNext = false;
  233. _state = AsyncIteratorState.Iterating;
  234. goto case AsyncIteratorState.Iterating;
  235. }
  236. }
  237. break;
  238. case AsyncIteratorState.Iterating:
  239. if (_doMoveNext && await _enumerator.MoveNextAsync().ConfigureAwait(false))
  240. {
  241. _current = _enumerator.Current;
  242. return true;
  243. }
  244. if (!_doMoveNext)
  245. {
  246. _current = _enumerator.Current;
  247. _doMoveNext = true;
  248. return true;
  249. }
  250. break;
  251. }
  252. await DisposeAsync().ConfigureAwait(false);
  253. return false;
  254. }
  255. }
  256. #if !NO_DEEP_CANCELLATION
  257. private sealed class SkipWhileAsyncIteratorWithTaskAndCancellation<TSource> : AsyncIterator<TSource>
  258. {
  259. private readonly Func<TSource, CancellationToken, ValueTask<bool>> _predicate;
  260. private readonly IAsyncEnumerable<TSource> _source;
  261. private bool _doMoveNext;
  262. private IAsyncEnumerator<TSource> _enumerator;
  263. public SkipWhileAsyncIteratorWithTaskAndCancellation(IAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, ValueTask<bool>> predicate)
  264. {
  265. Debug.Assert(predicate != null);
  266. Debug.Assert(source != null);
  267. _source = source;
  268. _predicate = predicate;
  269. }
  270. public override AsyncIteratorBase<TSource> Clone()
  271. {
  272. return new SkipWhileAsyncIteratorWithTaskAndCancellation<TSource>(_source, _predicate);
  273. }
  274. public override async ValueTask DisposeAsync()
  275. {
  276. if (_enumerator != null)
  277. {
  278. await _enumerator.DisposeAsync().ConfigureAwait(false);
  279. _enumerator = null;
  280. }
  281. await base.DisposeAsync().ConfigureAwait(false);
  282. }
  283. protected override async ValueTask<bool> MoveNextCore()
  284. {
  285. switch (_state)
  286. {
  287. case AsyncIteratorState.Allocated:
  288. _enumerator = _source.GetAsyncEnumerator(_cancellationToken);
  289. // skip elements as requested
  290. while (await _enumerator.MoveNextAsync().ConfigureAwait(false))
  291. {
  292. var element = _enumerator.Current;
  293. if (!await _predicate(element, _cancellationToken).ConfigureAwait(false))
  294. {
  295. _doMoveNext = false;
  296. _state = AsyncIteratorState.Iterating;
  297. goto case AsyncIteratorState.Iterating;
  298. }
  299. }
  300. break;
  301. case AsyncIteratorState.Iterating:
  302. if (_doMoveNext && await _enumerator.MoveNextAsync().ConfigureAwait(false))
  303. {
  304. _current = _enumerator.Current;
  305. return true;
  306. }
  307. if (!_doMoveNext)
  308. {
  309. _current = _enumerator.Current;
  310. _doMoveNext = true;
  311. return true;
  312. }
  313. break;
  314. }
  315. await DisposeAsync().ConfigureAwait(false);
  316. return false;
  317. }
  318. }
  319. #endif
  320. private sealed class SkipWhileWithIndexAsyncIteratorWithTask<TSource> : AsyncIterator<TSource>
  321. {
  322. private readonly Func<TSource, int, ValueTask<bool>> _predicate;
  323. private readonly IAsyncEnumerable<TSource> _source;
  324. private bool _doMoveNext;
  325. private IAsyncEnumerator<TSource> _enumerator;
  326. private int _index;
  327. public SkipWhileWithIndexAsyncIteratorWithTask(IAsyncEnumerable<TSource> source, Func<TSource, int, ValueTask<bool>> predicate)
  328. {
  329. Debug.Assert(predicate != null);
  330. Debug.Assert(source != null);
  331. _source = source;
  332. _predicate = predicate;
  333. }
  334. public override AsyncIteratorBase<TSource> Clone()
  335. {
  336. return new SkipWhileWithIndexAsyncIteratorWithTask<TSource>(_source, _predicate);
  337. }
  338. public override async ValueTask DisposeAsync()
  339. {
  340. if (_enumerator != null)
  341. {
  342. await _enumerator.DisposeAsync().ConfigureAwait(false);
  343. _enumerator = null;
  344. }
  345. await base.DisposeAsync().ConfigureAwait(false);
  346. }
  347. protected override async ValueTask<bool> MoveNextCore()
  348. {
  349. switch (_state)
  350. {
  351. case AsyncIteratorState.Allocated:
  352. _enumerator = _source.GetAsyncEnumerator(_cancellationToken);
  353. _index = -1;
  354. // skip elements as requested
  355. while (await _enumerator.MoveNextAsync().ConfigureAwait(false))
  356. {
  357. var element = _enumerator.Current;
  358. checked
  359. {
  360. _index++;
  361. }
  362. if (!await _predicate(element, _index).ConfigureAwait(false))
  363. {
  364. _doMoveNext = false;
  365. _state = AsyncIteratorState.Iterating;
  366. goto case AsyncIteratorState.Iterating;
  367. }
  368. }
  369. break;
  370. case AsyncIteratorState.Iterating:
  371. if (_doMoveNext && await _enumerator.MoveNextAsync().ConfigureAwait(false))
  372. {
  373. _current = _enumerator.Current;
  374. return true;
  375. }
  376. if (!_doMoveNext)
  377. {
  378. _current = _enumerator.Current;
  379. _doMoveNext = true;
  380. return true;
  381. }
  382. break;
  383. }
  384. await DisposeAsync().ConfigureAwait(false);
  385. return false;
  386. }
  387. }
  388. #if !NO_DEEP_CANCELLATION
  389. private sealed class SkipWhileWithIndexAsyncIteratorWithTaskAndCancellation<TSource> : AsyncIterator<TSource>
  390. {
  391. private readonly Func<TSource, int, CancellationToken, ValueTask<bool>> _predicate;
  392. private readonly IAsyncEnumerable<TSource> _source;
  393. private bool _doMoveNext;
  394. private IAsyncEnumerator<TSource> _enumerator;
  395. private int _index;
  396. public SkipWhileWithIndexAsyncIteratorWithTaskAndCancellation(IAsyncEnumerable<TSource> source, Func<TSource, int, CancellationToken, ValueTask<bool>> predicate)
  397. {
  398. Debug.Assert(predicate != null);
  399. Debug.Assert(source != null);
  400. _source = source;
  401. _predicate = predicate;
  402. }
  403. public override AsyncIteratorBase<TSource> Clone()
  404. {
  405. return new SkipWhileWithIndexAsyncIteratorWithTaskAndCancellation<TSource>(_source, _predicate);
  406. }
  407. public override async ValueTask DisposeAsync()
  408. {
  409. if (_enumerator != null)
  410. {
  411. await _enumerator.DisposeAsync().ConfigureAwait(false);
  412. _enumerator = null;
  413. }
  414. await base.DisposeAsync().ConfigureAwait(false);
  415. }
  416. protected override async ValueTask<bool> MoveNextCore()
  417. {
  418. switch (_state)
  419. {
  420. case AsyncIteratorState.Allocated:
  421. _enumerator = _source.GetAsyncEnumerator(_cancellationToken);
  422. _index = -1;
  423. // skip elements as requested
  424. while (await _enumerator.MoveNextAsync().ConfigureAwait(false))
  425. {
  426. var element = _enumerator.Current;
  427. checked
  428. {
  429. _index++;
  430. }
  431. if (!await _predicate(element, _index, _cancellationToken).ConfigureAwait(false))
  432. {
  433. _doMoveNext = false;
  434. _state = AsyncIteratorState.Iterating;
  435. goto case AsyncIteratorState.Iterating;
  436. }
  437. }
  438. break;
  439. case AsyncIteratorState.Iterating:
  440. if (_doMoveNext && await _enumerator.MoveNextAsync().ConfigureAwait(false))
  441. {
  442. _current = _enumerator.Current;
  443. return true;
  444. }
  445. if (!_doMoveNext)
  446. {
  447. _current = _enumerator.Current;
  448. _doMoveNext = true;
  449. return true;
  450. }
  451. break;
  452. }
  453. await DisposeAsync().ConfigureAwait(false);
  454. return false;
  455. }
  456. }
  457. #endif
  458. }
  459. }