Count.cs 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  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;
  5. using System.Collections.Generic;
  6. using System.Threading;
  7. using System.Threading.Tasks;
  8. namespace System.Linq
  9. {
  10. public static partial class AsyncEnumerable
  11. {
  12. public static Task<int> CountAsync<TSource>(this IAsyncEnumerable<TSource> source, CancellationToken cancellationToken = default)
  13. {
  14. if (source == null)
  15. throw Error.ArgumentNull(nameof(source));
  16. switch (source)
  17. {
  18. case ICollection<TSource> collection:
  19. return Task.FromResult(collection.Count);
  20. case IAsyncIListProvider<TSource> listProv:
  21. return listProv.GetCountAsync(onlyIfCheap: false, cancellationToken).AsTask();
  22. case ICollection collection:
  23. return Task.FromResult(collection.Count);
  24. }
  25. return Core(source, cancellationToken);
  26. async Task<int> Core(IAsyncEnumerable<TSource> _source, CancellationToken _cancellationToken)
  27. {
  28. var count = 0;
  29. #if CSHARP8 && AETOR_HAS_CT // CS0656 Missing compiler required member 'System.Collections.Generic.IAsyncEnumerable`1.GetAsyncEnumerator'
  30. await foreach (TSource item in _source.WithCancellation(_cancellationToken).ConfigureAwait(false))
  31. {
  32. checked
  33. {
  34. count++;
  35. }
  36. }
  37. #else
  38. var e = _source.GetAsyncEnumerator(_cancellationToken);
  39. try
  40. {
  41. while (await e.MoveNextAsync().ConfigureAwait(false))
  42. {
  43. checked
  44. {
  45. count++;
  46. }
  47. }
  48. }
  49. finally
  50. {
  51. await e.DisposeAsync().ConfigureAwait(false);
  52. }
  53. #endif
  54. return count;
  55. }
  56. }
  57. public static Task<int> CountAsync<TSource>(this IAsyncEnumerable<TSource> source, Func<TSource, bool> predicate, CancellationToken cancellationToken = default)
  58. {
  59. if (source == null)
  60. throw Error.ArgumentNull(nameof(source));
  61. if (predicate == null)
  62. throw Error.ArgumentNull(nameof(predicate));
  63. return Core(source, predicate, cancellationToken);
  64. async Task<int> Core(IAsyncEnumerable<TSource> _source, Func<TSource, bool> _predicate, CancellationToken _cancellationToken)
  65. {
  66. var count = 0;
  67. #if CSHARP8 && AETOR_HAS_CT // CS0656 Missing compiler required member 'System.Collections.Generic.IAsyncEnumerable`1.GetAsyncEnumerator'
  68. await foreach (TSource item in _source.WithCancellation(_cancellationToken).ConfigureAwait(false))
  69. {
  70. if (_predicate(item))
  71. {
  72. checked
  73. {
  74. count++;
  75. }
  76. }
  77. }
  78. #else
  79. var e = _source.GetAsyncEnumerator(_cancellationToken);
  80. try
  81. {
  82. while (await e.MoveNextAsync().ConfigureAwait(false))
  83. {
  84. if (_predicate(e.Current))
  85. {
  86. checked
  87. {
  88. count++;
  89. }
  90. }
  91. }
  92. }
  93. finally
  94. {
  95. await e.DisposeAsync().ConfigureAwait(false);
  96. }
  97. #endif
  98. return count;
  99. }
  100. }
  101. public static Task<int> CountAsync<TSource>(this IAsyncEnumerable<TSource> source, Func<TSource, ValueTask<bool>> predicate, CancellationToken cancellationToken = default)
  102. {
  103. if (source == null)
  104. throw Error.ArgumentNull(nameof(source));
  105. if (predicate == null)
  106. throw Error.ArgumentNull(nameof(predicate));
  107. return Core(source, predicate, cancellationToken);
  108. async Task<int> Core(IAsyncEnumerable<TSource> _source, Func<TSource, ValueTask<bool>> _predicate, CancellationToken _cancellationToken)
  109. {
  110. var count = 0;
  111. #if CSHARP8 && AETOR_HAS_CT // CS0656 Missing compiler required member 'System.Collections.Generic.IAsyncEnumerable`1.GetAsyncEnumerator'
  112. await foreach (TSource item in _source.WithCancellation(_cancellationToken).ConfigureAwait(false))
  113. {
  114. if (await _predicate(item).ConfigureAwait(false))
  115. {
  116. checked
  117. {
  118. count++;
  119. }
  120. }
  121. }
  122. #else
  123. var e = _source.GetAsyncEnumerator(_cancellationToken);
  124. try
  125. {
  126. while (await e.MoveNextAsync().ConfigureAwait(false))
  127. {
  128. if (await _predicate(e.Current).ConfigureAwait(false))
  129. {
  130. checked
  131. {
  132. count++;
  133. }
  134. }
  135. }
  136. }
  137. finally
  138. {
  139. await e.DisposeAsync().ConfigureAwait(false);
  140. }
  141. #endif
  142. return count;
  143. }
  144. }
  145. #if !NO_DEEP_CANCELLATION
  146. public static Task<int> CountAsync<TSource>(this IAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, ValueTask<bool>> predicate, CancellationToken cancellationToken = default)
  147. {
  148. if (source == null)
  149. throw Error.ArgumentNull(nameof(source));
  150. if (predicate == null)
  151. throw Error.ArgumentNull(nameof(predicate));
  152. return Core(source, predicate, cancellationToken);
  153. async Task<int> Core(IAsyncEnumerable<TSource> _source, Func<TSource, CancellationToken, ValueTask<bool>> _predicate, CancellationToken _cancellationToken)
  154. {
  155. var count = 0;
  156. #if CSHARP8 && AETOR_HAS_CT // CS0656 Missing compiler required member 'System.Collections.Generic.IAsyncEnumerable`1.GetAsyncEnumerator'
  157. await foreach (TSource item in _source.WithCancellation(_cancellationToken).ConfigureAwait(false))
  158. {
  159. if (await _predicate(item, _cancellationToken).ConfigureAwait(false))
  160. {
  161. checked
  162. {
  163. count++;
  164. }
  165. }
  166. }
  167. #else
  168. var e = _source.GetAsyncEnumerator(_cancellationToken);
  169. try
  170. {
  171. while (await e.MoveNextAsync().ConfigureAwait(false))
  172. {
  173. if (await _predicate(e.Current, _cancellationToken).ConfigureAwait(false))
  174. {
  175. checked
  176. {
  177. count++;
  178. }
  179. }
  180. }
  181. }
  182. finally
  183. {
  184. await e.DisposeAsync().ConfigureAwait(false);
  185. }
  186. #endif
  187. return count;
  188. }
  189. }
  190. #endif
  191. }
  192. }