SkipWhile.cs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. // Licensed to the .NET Foundation under one or more agreements.
  2. // The .NET Foundation licenses this file to you under the MIT License.
  3. // See the LICENSE file in the project root for more information.
  4. using System.Collections.Generic;
  5. using System.Threading;
  6. using System.Threading.Tasks;
  7. namespace System.Linq
  8. {
  9. public static partial class AsyncEnumerable
  10. {
  11. /// <summary>
  12. /// Bypasses elements in an async-enumerable sequence as long as a specified condition is true and then returns the remaining elements.
  13. /// </summary>
  14. /// <typeparam name="TSource">The type of the elements in the source sequence.</typeparam>
  15. /// <param name="source">An async-enumerable sequence to return elements from.</param>
  16. /// <param name="predicate">A function to test each element for a condition.</param>
  17. /// <returns>An async-enumerable sequence that contains the elements from the input sequence starting at the first element in the linear series that does not pass the test specified by predicate.</returns>
  18. /// <exception cref="ArgumentNullException"><paramref name="source"/> or <paramref name="predicate"/> is null.</exception>
  19. public static IAsyncEnumerable<TSource> SkipWhile<TSource>(this IAsyncEnumerable<TSource> source, Func<TSource, bool> predicate)
  20. {
  21. if (source == null)
  22. throw Error.ArgumentNull(nameof(source));
  23. if (predicate == null)
  24. throw Error.ArgumentNull(nameof(predicate));
  25. return Core(source, predicate);
  26. static async IAsyncEnumerable<TSource> Core(IAsyncEnumerable<TSource> source, Func<TSource, bool> predicate, [System.Runtime.CompilerServices.EnumeratorCancellation] CancellationToken cancellationToken = default)
  27. {
  28. await using var e = source.GetConfiguredAsyncEnumerator(cancellationToken, false);
  29. while (await e.MoveNextAsync())
  30. {
  31. var element = e.Current;
  32. if (!predicate(element))
  33. {
  34. yield return element;
  35. while (await e.MoveNextAsync())
  36. {
  37. yield return e.Current;
  38. }
  39. yield break;
  40. }
  41. }
  42. }
  43. }
  44. /// <summary>
  45. /// Bypasses elements in an async-enumerable sequence as long as a specified condition is true and then returns the remaining elements.
  46. /// The element's index is used in the logic of the predicate function.
  47. /// </summary>
  48. /// <typeparam name="TSource">The type of the elements in the source sequence.</typeparam>
  49. /// <param name="source">An async-enumerable sequence to return elements from.</param>
  50. /// <param name="predicate">A function to test each element for a condition; the second parameter of the function represents the index of the source element.</param>
  51. /// <returns>An async-enumerable sequence that contains the elements from the input sequence starting at the first element in the linear series that does not pass the test specified by predicate.</returns>
  52. /// <exception cref="ArgumentNullException"><paramref name="source"/> or <paramref name="predicate"/> is null.</exception>
  53. public static IAsyncEnumerable<TSource> SkipWhile<TSource>(this IAsyncEnumerable<TSource> source, Func<TSource, int, bool> predicate)
  54. {
  55. if (source == null)
  56. throw Error.ArgumentNull(nameof(source));
  57. if (predicate == null)
  58. throw Error.ArgumentNull(nameof(predicate));
  59. return Core(source, predicate);
  60. static async IAsyncEnumerable<TSource> Core(IAsyncEnumerable<TSource> source, Func<TSource, int, bool> predicate, [System.Runtime.CompilerServices.EnumeratorCancellation] CancellationToken cancellationToken = default)
  61. {
  62. await using var e = source.GetConfiguredAsyncEnumerator(cancellationToken, false);
  63. var index = -1;
  64. while (await e.MoveNextAsync())
  65. {
  66. checked
  67. {
  68. index++;
  69. }
  70. var element = e.Current;
  71. if (!predicate(element, index))
  72. {
  73. yield return element;
  74. while (await e.MoveNextAsync())
  75. {
  76. yield return e.Current;
  77. }
  78. yield break;
  79. }
  80. }
  81. }
  82. }
  83. internal static IAsyncEnumerable<TSource> SkipWhileAwaitCore<TSource>(this IAsyncEnumerable<TSource> source, Func<TSource, ValueTask<bool>> predicate)
  84. {
  85. if (source == null)
  86. throw Error.ArgumentNull(nameof(source));
  87. if (predicate == null)
  88. throw Error.ArgumentNull(nameof(predicate));
  89. return Core(source, predicate);
  90. static async IAsyncEnumerable<TSource> Core(IAsyncEnumerable<TSource> source, Func<TSource, ValueTask<bool>> predicate, [System.Runtime.CompilerServices.EnumeratorCancellation] CancellationToken cancellationToken = default)
  91. {
  92. await using var e = source.GetConfiguredAsyncEnumerator(cancellationToken, false);
  93. while (await e.MoveNextAsync())
  94. {
  95. var element = e.Current;
  96. if (!await predicate(element).ConfigureAwait(false))
  97. {
  98. yield return element;
  99. while (await e.MoveNextAsync())
  100. {
  101. yield return e.Current;
  102. }
  103. yield break;
  104. }
  105. }
  106. }
  107. }
  108. #if !NO_DEEP_CANCELLATION
  109. internal static IAsyncEnumerable<TSource> SkipWhileAwaitWithCancellationCore<TSource>(this IAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, ValueTask<bool>> predicate)
  110. {
  111. if (source == null)
  112. throw Error.ArgumentNull(nameof(source));
  113. if (predicate == null)
  114. throw Error.ArgumentNull(nameof(predicate));
  115. return Core(source, predicate);
  116. static async IAsyncEnumerable<TSource> Core(IAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, ValueTask<bool>> predicate, [System.Runtime.CompilerServices.EnumeratorCancellation] CancellationToken cancellationToken = default)
  117. {
  118. await using var e = source.GetConfiguredAsyncEnumerator(cancellationToken, false);
  119. while (await e.MoveNextAsync())
  120. {
  121. var element = e.Current;
  122. if (!await predicate(element, cancellationToken).ConfigureAwait(false))
  123. {
  124. yield return element;
  125. while (await e.MoveNextAsync())
  126. {
  127. yield return e.Current;
  128. }
  129. yield break;
  130. }
  131. }
  132. }
  133. }
  134. #endif
  135. internal static IAsyncEnumerable<TSource> SkipWhileAwaitCore<TSource>(this IAsyncEnumerable<TSource> source, Func<TSource, int, ValueTask<bool>> predicate)
  136. {
  137. if (source == null)
  138. throw Error.ArgumentNull(nameof(source));
  139. if (predicate == null)
  140. throw Error.ArgumentNull(nameof(predicate));
  141. return Core(source, predicate);
  142. static async IAsyncEnumerable<TSource> Core(IAsyncEnumerable<TSource> source, Func<TSource, int, ValueTask<bool>> predicate, [System.Runtime.CompilerServices.EnumeratorCancellation] CancellationToken cancellationToken = default)
  143. {
  144. await using var e = source.GetConfiguredAsyncEnumerator(cancellationToken, false);
  145. var index = -1;
  146. while (await e.MoveNextAsync())
  147. {
  148. checked
  149. {
  150. index++;
  151. }
  152. var element = e.Current;
  153. if (!await predicate(element, index).ConfigureAwait(false))
  154. {
  155. yield return element;
  156. while (await e.MoveNextAsync())
  157. {
  158. yield return e.Current;
  159. }
  160. yield break;
  161. }
  162. }
  163. }
  164. }
  165. #if !NO_DEEP_CANCELLATION
  166. internal static IAsyncEnumerable<TSource> SkipWhileAwaitWithCancellationCore<TSource>(this IAsyncEnumerable<TSource> source, Func<TSource, int, CancellationToken, ValueTask<bool>> predicate)
  167. {
  168. if (source == null)
  169. throw Error.ArgumentNull(nameof(source));
  170. if (predicate == null)
  171. throw Error.ArgumentNull(nameof(predicate));
  172. return Core(source, predicate);
  173. static async IAsyncEnumerable<TSource> Core(IAsyncEnumerable<TSource> source, Func<TSource, int, CancellationToken, ValueTask<bool>> predicate, [System.Runtime.CompilerServices.EnumeratorCancellation] CancellationToken cancellationToken = default)
  174. {
  175. await using var e = source.GetConfiguredAsyncEnumerator(cancellationToken, false);
  176. var index = -1;
  177. while (await e.MoveNextAsync())
  178. {
  179. checked
  180. {
  181. index++;
  182. }
  183. var element = e.Current;
  184. if (!await predicate(element, index, cancellationToken).ConfigureAwait(false))
  185. {
  186. yield return element;
  187. while (await e.MoveNextAsync())
  188. {
  189. yield return e.Current;
  190. }
  191. yield break;
  192. }
  193. }
  194. }
  195. }
  196. #endif
  197. }
  198. }