SkipWhile.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  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. #if INCLUDE_SYSTEM_LINQ_ASYNCENUMERABLE_DUPLICATES
  12. // https://learn.microsoft.com/en-us/dotnet/api/system.linq.asyncenumerable.skipwhile?view=net-9.0-pp#system-linq-asyncenumerable-skipwhile-1(system-collections-generic-iasyncenumerable((-0))-system-func((-0-system-boolean)))
  13. /// <summary>
  14. /// Bypasses elements in an async-enumerable sequence as long as a specified condition is true and then returns the remaining elements.
  15. /// </summary>
  16. /// <typeparam name="TSource">The type of the elements in the source sequence.</typeparam>
  17. /// <param name="source">An async-enumerable sequence to return elements from.</param>
  18. /// <param name="predicate">A function to test each element for a condition.</param>
  19. /// <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>
  20. /// <exception cref="ArgumentNullException"><paramref name="source"/> or <paramref name="predicate"/> is null.</exception>
  21. public static IAsyncEnumerable<TSource> SkipWhile<TSource>(this IAsyncEnumerable<TSource> source, Func<TSource, bool> predicate)
  22. {
  23. if (source == null)
  24. throw Error.ArgumentNull(nameof(source));
  25. if (predicate == null)
  26. throw Error.ArgumentNull(nameof(predicate));
  27. return Core(source, predicate);
  28. static async IAsyncEnumerable<TSource> Core(IAsyncEnumerable<TSource> source, Func<TSource, bool> predicate, [System.Runtime.CompilerServices.EnumeratorCancellation] CancellationToken cancellationToken = default)
  29. {
  30. await using var e = source.GetConfiguredAsyncEnumerator(cancellationToken, false);
  31. while (await e.MoveNextAsync())
  32. {
  33. var element = e.Current;
  34. if (!predicate(element))
  35. {
  36. yield return element;
  37. while (await e.MoveNextAsync())
  38. {
  39. yield return e.Current;
  40. }
  41. yield break;
  42. }
  43. }
  44. }
  45. }
  46. // https://learn.microsoft.com/en-us/dotnet/api/system.linq.asyncenumerable.skipwhile?view=net-9.0-pp#system-linq-asyncenumerable-skipwhile-1(system-collections-generic-iasyncenumerable((-0))-system-func((-0-system-int32-system-boolean)))
  47. /// <summary>
  48. /// Bypasses elements in an async-enumerable sequence as long as a specified condition is true and then returns the remaining elements.
  49. /// The element's index is used in the logic of the predicate function.
  50. /// </summary>
  51. /// <typeparam name="TSource">The type of the elements in the source sequence.</typeparam>
  52. /// <param name="source">An async-enumerable sequence to return elements from.</param>
  53. /// <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>
  54. /// <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>
  55. /// <exception cref="ArgumentNullException"><paramref name="source"/> or <paramref name="predicate"/> is null.</exception>
  56. public static IAsyncEnumerable<TSource> SkipWhile<TSource>(this IAsyncEnumerable<TSource> source, Func<TSource, int, bool> predicate)
  57. {
  58. if (source == null)
  59. throw Error.ArgumentNull(nameof(source));
  60. if (predicate == null)
  61. throw Error.ArgumentNull(nameof(predicate));
  62. return Core(source, predicate);
  63. static async IAsyncEnumerable<TSource> Core(IAsyncEnumerable<TSource> source, Func<TSource, int, bool> predicate, [System.Runtime.CompilerServices.EnumeratorCancellation] CancellationToken cancellationToken = default)
  64. {
  65. await using var e = source.GetConfiguredAsyncEnumerator(cancellationToken, false);
  66. var index = -1;
  67. while (await e.MoveNextAsync())
  68. {
  69. checked
  70. {
  71. index++;
  72. }
  73. var element = e.Current;
  74. if (!predicate(element, index))
  75. {
  76. yield return element;
  77. while (await e.MoveNextAsync())
  78. {
  79. yield return e.Current;
  80. }
  81. yield break;
  82. }
  83. }
  84. }
  85. }
  86. #endif // INCLUDE_SYSTEM_LINQ_ASYNCENUMERABLE_DUPLICATES
  87. /// <summary>
  88. /// Bypasses elements in an async-enumerable sequence as long as a condition is true, and then returns the remaining elements.
  89. /// </summary>
  90. /// <typeparam name="TSource">The type of elements in the source sequence.</typeparam>
  91. /// <param name="source">An async-enumerable sequence to return elements from.</param>
  92. /// <param name="predicate">An asynchronous function to test each element for a condition.</param>
  93. /// <returns>An async-enumerable sequence containing the elements in the source sequence starting at the first element that does not pass the test specified by the predicate.</returns>
  94. /// <exception cref="ArgumentNullException"><paramref name="source"/> or <paramref name="predicate"/> is <see langword="null"/>.</exception>
  95. [GenerateAsyncOverload]
  96. [Obsolete("Use SkipWhile. IAsyncEnumerable LINQ is now in System.Linq.AsyncEnumerable, and the SkipWhileAwait functionality now exists as overloads of SkipWhile.")]
  97. private static IAsyncEnumerable<TSource> SkipWhileAwaitCore<TSource>(this IAsyncEnumerable<TSource> source, Func<TSource, ValueTask<bool>> predicate)
  98. {
  99. if (source == null)
  100. throw Error.ArgumentNull(nameof(source));
  101. if (predicate == null)
  102. throw Error.ArgumentNull(nameof(predicate));
  103. return Core(source, predicate);
  104. static async IAsyncEnumerable<TSource> Core(IAsyncEnumerable<TSource> source, Func<TSource, ValueTask<bool>> predicate, [System.Runtime.CompilerServices.EnumeratorCancellation] CancellationToken cancellationToken = default)
  105. {
  106. await using var e = source.GetConfiguredAsyncEnumerator(cancellationToken, false);
  107. while (await e.MoveNextAsync())
  108. {
  109. var element = e.Current;
  110. if (!await predicate(element).ConfigureAwait(false))
  111. {
  112. yield return element;
  113. while (await e.MoveNextAsync())
  114. {
  115. yield return e.Current;
  116. }
  117. yield break;
  118. }
  119. }
  120. }
  121. }
  122. #if !NO_DEEP_CANCELLATION
  123. [GenerateAsyncOverload]
  124. [Obsolete("Use SkipWhile. IAsyncEnumerable LINQ is now in System.Linq.AsyncEnumerable, and the SkipWhileAwaitWithCancellation functionality now exists as overloads of SkipWhile.")]
  125. private static IAsyncEnumerable<TSource> SkipWhileAwaitWithCancellationCore<TSource>(this IAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, ValueTask<bool>> predicate)
  126. {
  127. if (source == null)
  128. throw Error.ArgumentNull(nameof(source));
  129. if (predicate == null)
  130. throw Error.ArgumentNull(nameof(predicate));
  131. return Core(source, predicate);
  132. static async IAsyncEnumerable<TSource> Core(IAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, ValueTask<bool>> predicate, [System.Runtime.CompilerServices.EnumeratorCancellation] CancellationToken cancellationToken = default)
  133. {
  134. await using var e = source.GetConfiguredAsyncEnumerator(cancellationToken, false);
  135. while (await e.MoveNextAsync())
  136. {
  137. var element = e.Current;
  138. if (!await predicate(element, cancellationToken).ConfigureAwait(false))
  139. {
  140. yield return element;
  141. while (await e.MoveNextAsync())
  142. {
  143. yield return e.Current;
  144. }
  145. yield break;
  146. }
  147. }
  148. }
  149. }
  150. #endif
  151. /// <summary>
  152. /// Bypasses elements in an async-enumerable sequence as long as a condition is true, and then returns the remaining elements.
  153. /// The index of the element is used by the predicate.
  154. /// </summary>
  155. /// <typeparam name="TSource">The type of elements in the source sequence.</typeparam>
  156. /// <param name="source">An async-enumerable sequence to return elements from.</param>
  157. /// <param name="predicate">An asynchronous function to test each element for a condition; the second parameter of the function represents the index of the element.</param>
  158. /// <returns>An async-enumerable sequence containing the elements in the source sequence starting at the first element that does not pass the test specified by the predicate.</returns>
  159. /// <exception cref="ArgumentNullException"><paramref name="source"/> or <paramref name="predicate"/> is <see langword="null"/>.</exception>
  160. [GenerateAsyncOverload]
  161. [Obsolete("Use SkipWhile. IAsyncEnumerable LINQ is now in System.Linq.AsyncEnumerable, and the SkipWhileAwait functionality now exists as overloads of SkipWhile.")]
  162. private static IAsyncEnumerable<TSource> SkipWhileAwaitCore<TSource>(this IAsyncEnumerable<TSource> source, Func<TSource, int, ValueTask<bool>> predicate)
  163. {
  164. if (source == null)
  165. throw Error.ArgumentNull(nameof(source));
  166. if (predicate == null)
  167. throw Error.ArgumentNull(nameof(predicate));
  168. return Core(source, predicate);
  169. static async IAsyncEnumerable<TSource> Core(IAsyncEnumerable<TSource> source, Func<TSource, int, ValueTask<bool>> predicate, [System.Runtime.CompilerServices.EnumeratorCancellation] CancellationToken cancellationToken = default)
  170. {
  171. await using var e = source.GetConfiguredAsyncEnumerator(cancellationToken, false);
  172. var index = -1;
  173. while (await e.MoveNextAsync())
  174. {
  175. checked
  176. {
  177. index++;
  178. }
  179. var element = e.Current;
  180. if (!await predicate(element, index).ConfigureAwait(false))
  181. {
  182. yield return element;
  183. while (await e.MoveNextAsync())
  184. {
  185. yield return e.Current;
  186. }
  187. yield break;
  188. }
  189. }
  190. }
  191. }
  192. #if !NO_DEEP_CANCELLATION
  193. [GenerateAsyncOverload]
  194. [Obsolete("Use SkipWhile. IAsyncEnumerable LINQ is now in System.Linq.AsyncEnumerable, and the SkipWhileAwaitWithCancellation functionality now exists as overloads of SkipWhile.")]
  195. private static IAsyncEnumerable<TSource> SkipWhileAwaitWithCancellationCore<TSource>(this IAsyncEnumerable<TSource> source, Func<TSource, int, CancellationToken, ValueTask<bool>> predicate)
  196. {
  197. if (source == null)
  198. throw Error.ArgumentNull(nameof(source));
  199. if (predicate == null)
  200. throw Error.ArgumentNull(nameof(predicate));
  201. return Core(source, predicate);
  202. static async IAsyncEnumerable<TSource> Core(IAsyncEnumerable<TSource> source, Func<TSource, int, CancellationToken, ValueTask<bool>> predicate, [System.Runtime.CompilerServices.EnumeratorCancellation] CancellationToken cancellationToken = default)
  203. {
  204. await using var e = source.GetConfiguredAsyncEnumerator(cancellationToken, false);
  205. var index = -1;
  206. while (await e.MoveNextAsync())
  207. {
  208. checked
  209. {
  210. index++;
  211. }
  212. var element = e.Current;
  213. if (!await predicate(element, index, cancellationToken).ConfigureAwait(false))
  214. {
  215. yield return element;
  216. while (await e.MoveNextAsync())
  217. {
  218. yield return e.Current;
  219. }
  220. yield break;
  221. }
  222. }
  223. }
  224. }
  225. #endif
  226. }
  227. }