Distinct.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  1. using Cysharp.Threading.Tasks.Internal;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Threading;
  5. namespace Cysharp.Threading.Tasks.Linq
  6. {
  7. public static partial class UniTaskAsyncEnumerable
  8. {
  9. public static IUniTaskAsyncEnumerable<TSource> Distinct<TSource>(this IUniTaskAsyncEnumerable<TSource> source)
  10. {
  11. return Distinct(source, EqualityComparer<TSource>.Default);
  12. }
  13. public static IUniTaskAsyncEnumerable<TSource> Distinct<TSource>(this IUniTaskAsyncEnumerable<TSource> source, IEqualityComparer<TSource> comparer)
  14. {
  15. Error.ThrowArgumentNullException(source, nameof(source));
  16. Error.ThrowArgumentNullException(comparer, nameof(comparer));
  17. return new Distinct<TSource>(source, comparer);
  18. }
  19. public static IUniTaskAsyncEnumerable<TSource> Distinct<TSource, TKey>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, TKey> keySelector)
  20. {
  21. return Distinct(source, keySelector, EqualityComparer<TKey>.Default);
  22. }
  23. public static IUniTaskAsyncEnumerable<TSource> Distinct<TSource, TKey>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer)
  24. {
  25. Error.ThrowArgumentNullException(source, nameof(source));
  26. Error.ThrowArgumentNullException(keySelector, nameof(keySelector));
  27. Error.ThrowArgumentNullException(comparer, nameof(comparer));
  28. return new Distinct<TSource, TKey>(source, keySelector, comparer);
  29. }
  30. public static IUniTaskAsyncEnumerable<TSource> DistinctAwait<TSource, TKey>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask<TKey>> keySelector)
  31. {
  32. return DistinctAwait(source, keySelector, EqualityComparer<TKey>.Default);
  33. }
  34. public static IUniTaskAsyncEnumerable<TSource> DistinctAwait<TSource, TKey>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask<TKey>> keySelector, IEqualityComparer<TKey> comparer)
  35. {
  36. Error.ThrowArgumentNullException(source, nameof(source));
  37. Error.ThrowArgumentNullException(keySelector, nameof(keySelector));
  38. Error.ThrowArgumentNullException(comparer, nameof(comparer));
  39. return new DistinctAwait<TSource, TKey>(source, keySelector, comparer);
  40. }
  41. public static IUniTaskAsyncEnumerable<TSource> DistinctAwaitWithCancellation<TSource, TKey>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask<TKey>> keySelector)
  42. {
  43. return DistinctAwaitWithCancellation(source, keySelector, EqualityComparer<TKey>.Default);
  44. }
  45. public static IUniTaskAsyncEnumerable<TSource> DistinctAwaitWithCancellation<TSource, TKey>(this IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask<TKey>> keySelector, IEqualityComparer<TKey> comparer)
  46. {
  47. Error.ThrowArgumentNullException(source, nameof(source));
  48. Error.ThrowArgumentNullException(keySelector, nameof(keySelector));
  49. Error.ThrowArgumentNullException(comparer, nameof(comparer));
  50. return new DistinctAwaitWithCancellation<TSource, TKey>(source, keySelector, comparer);
  51. }
  52. }
  53. internal sealed class Distinct<TSource> : IUniTaskAsyncEnumerable<TSource>
  54. {
  55. readonly IUniTaskAsyncEnumerable<TSource> source;
  56. readonly IEqualityComparer<TSource> comparer;
  57. public Distinct(IUniTaskAsyncEnumerable<TSource> source, IEqualityComparer<TSource> comparer)
  58. {
  59. this.source = source;
  60. this.comparer = comparer;
  61. }
  62. public IUniTaskAsyncEnumerator<TSource> GetAsyncEnumerator(CancellationToken cancellationToken = default)
  63. {
  64. return new _Distinct(source, comparer, cancellationToken);
  65. }
  66. class _Distinct : AsyncEnumeratorBase<TSource, TSource>
  67. {
  68. readonly HashSet<TSource> set;
  69. public _Distinct(IUniTaskAsyncEnumerable<TSource> source, IEqualityComparer<TSource> comparer, CancellationToken cancellationToken)
  70. : base(source, cancellationToken)
  71. {
  72. this.set = new HashSet<TSource>(comparer);
  73. }
  74. protected override bool TryMoveNextCore(bool sourceHasCurrent, out bool result)
  75. {
  76. if (sourceHasCurrent)
  77. {
  78. var v = SourceCurrent;
  79. if (set.Add(v))
  80. {
  81. Current = v;
  82. result = true;
  83. return true;
  84. }
  85. else
  86. {
  87. result = default;
  88. return false;
  89. }
  90. }
  91. result = false;
  92. return true;
  93. }
  94. }
  95. }
  96. internal sealed class Distinct<TSource, TKey> : IUniTaskAsyncEnumerable<TSource>
  97. {
  98. readonly IUniTaskAsyncEnumerable<TSource> source;
  99. readonly Func<TSource, TKey> keySelector;
  100. readonly IEqualityComparer<TKey> comparer;
  101. public Distinct(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer)
  102. {
  103. this.source = source;
  104. this.keySelector = keySelector;
  105. this.comparer = comparer;
  106. }
  107. public IUniTaskAsyncEnumerator<TSource> GetAsyncEnumerator(CancellationToken cancellationToken = default)
  108. {
  109. return new _Distinct(source, keySelector, comparer, cancellationToken);
  110. }
  111. class _Distinct : AsyncEnumeratorBase<TSource, TSource>
  112. {
  113. readonly HashSet<TKey> set;
  114. readonly Func<TSource, TKey> keySelector;
  115. public _Distinct(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer, CancellationToken cancellationToken)
  116. : base(source, cancellationToken)
  117. {
  118. this.set = new HashSet<TKey>(comparer);
  119. this.keySelector = keySelector;
  120. }
  121. protected override bool TryMoveNextCore(bool sourceHasCurrent, out bool result)
  122. {
  123. if (sourceHasCurrent)
  124. {
  125. var v = SourceCurrent;
  126. if (set.Add(keySelector(v)))
  127. {
  128. Current = v;
  129. result = true;
  130. return true;
  131. }
  132. else
  133. {
  134. result = default;
  135. return false;
  136. }
  137. }
  138. result = false;
  139. return true;
  140. }
  141. }
  142. }
  143. internal sealed class DistinctAwait<TSource, TKey> : IUniTaskAsyncEnumerable<TSource>
  144. {
  145. readonly IUniTaskAsyncEnumerable<TSource> source;
  146. readonly Func<TSource, UniTask<TKey>> keySelector;
  147. readonly IEqualityComparer<TKey> comparer;
  148. public DistinctAwait(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask<TKey>> keySelector, IEqualityComparer<TKey> comparer)
  149. {
  150. this.source = source;
  151. this.keySelector = keySelector;
  152. this.comparer = comparer;
  153. }
  154. public IUniTaskAsyncEnumerator<TSource> GetAsyncEnumerator(CancellationToken cancellationToken = default)
  155. {
  156. return new _DistinctAwait(source, keySelector, comparer, cancellationToken);
  157. }
  158. class _DistinctAwait : AsyncEnumeratorAwaitSelectorBase<TSource, TSource, TKey>
  159. {
  160. readonly HashSet<TKey> set;
  161. readonly Func<TSource, UniTask<TKey>> keySelector;
  162. public _DistinctAwait(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, UniTask<TKey>> keySelector, IEqualityComparer<TKey> comparer, CancellationToken cancellationToken)
  163. : base(source, cancellationToken)
  164. {
  165. this.set = new HashSet<TKey>(comparer);
  166. this.keySelector = keySelector;
  167. }
  168. protected override UniTask<TKey> TransformAsync(TSource sourceCurrent)
  169. {
  170. return keySelector(sourceCurrent);
  171. }
  172. protected override bool TrySetCurrentCore(TKey awaitResult, out bool terminateIteration)
  173. {
  174. if (set.Add(awaitResult))
  175. {
  176. Current = SourceCurrent;
  177. terminateIteration = false;
  178. return true;
  179. }
  180. else
  181. {
  182. terminateIteration = false;
  183. return false;
  184. }
  185. }
  186. }
  187. }
  188. internal sealed class DistinctAwaitWithCancellation<TSource, TKey> : IUniTaskAsyncEnumerable<TSource>
  189. {
  190. readonly IUniTaskAsyncEnumerable<TSource> source;
  191. readonly Func<TSource, CancellationToken, UniTask<TKey>> keySelector;
  192. readonly IEqualityComparer<TKey> comparer;
  193. public DistinctAwaitWithCancellation(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask<TKey>> keySelector, IEqualityComparer<TKey> comparer)
  194. {
  195. this.source = source;
  196. this.keySelector = keySelector;
  197. this.comparer = comparer;
  198. }
  199. public IUniTaskAsyncEnumerator<TSource> GetAsyncEnumerator(CancellationToken cancellationToken = default)
  200. {
  201. return new _DistinctAwaitWithCancellation(source, keySelector, comparer, cancellationToken);
  202. }
  203. class _DistinctAwaitWithCancellation : AsyncEnumeratorAwaitSelectorBase<TSource, TSource, TKey>
  204. {
  205. readonly HashSet<TKey> set;
  206. readonly Func<TSource, CancellationToken, UniTask<TKey>> keySelector;
  207. public _DistinctAwaitWithCancellation(IUniTaskAsyncEnumerable<TSource> source, Func<TSource, CancellationToken, UniTask<TKey>> keySelector, IEqualityComparer<TKey> comparer, CancellationToken cancellationToken)
  208. : base(source, cancellationToken)
  209. {
  210. this.set = new HashSet<TKey>(comparer);
  211. this.keySelector = keySelector;
  212. }
  213. protected override UniTask<TKey> TransformAsync(TSource sourceCurrent)
  214. {
  215. return keySelector(sourceCurrent, cancellationToken);
  216. }
  217. protected override bool TrySetCurrentCore(TKey awaitResult, out bool terminateIteration)
  218. {
  219. if (set.Add(awaitResult))
  220. {
  221. Current = SourceCurrent;
  222. terminateIteration = false;
  223. return true;
  224. }
  225. else
  226. {
  227. terminateIteration = false;
  228. return false;
  229. }
  230. }
  231. }
  232. }
  233. }