|
|
@@ -73,78 +73,6 @@ namespace System.Linq
|
|
|
return new DistinctAsyncIteratorWithTask<TSource, TKey>(source, keySelector, comparer);
|
|
|
}
|
|
|
|
|
|
- public static IAsyncEnumerable<TSource> DistinctUntilChanged<TSource>(this IAsyncEnumerable<TSource> source)
|
|
|
- {
|
|
|
- if (source == null)
|
|
|
- throw new ArgumentNullException(nameof(source));
|
|
|
-
|
|
|
- return source.DistinctUntilChanged(EqualityComparer<TSource>.Default);
|
|
|
- }
|
|
|
-
|
|
|
- public static IAsyncEnumerable<TSource> DistinctUntilChanged<TSource>(this IAsyncEnumerable<TSource> source, IEqualityComparer<TSource> comparer)
|
|
|
- {
|
|
|
- if (source == null)
|
|
|
- throw new ArgumentNullException(nameof(source));
|
|
|
- if (comparer == null)
|
|
|
- throw new ArgumentNullException(nameof(comparer));
|
|
|
-
|
|
|
- return new DistinctUntilChangedAsyncIterator<TSource>(source, comparer);
|
|
|
- }
|
|
|
-
|
|
|
- public static IAsyncEnumerable<TSource> DistinctUntilChanged<TSource, TKey>(this IAsyncEnumerable<TSource> source, Func<TSource, TKey> keySelector)
|
|
|
- {
|
|
|
- if (source == null)
|
|
|
- throw new ArgumentNullException(nameof(source));
|
|
|
- if (keySelector == null)
|
|
|
- throw new ArgumentNullException(nameof(keySelector));
|
|
|
-
|
|
|
- return source.DistinctUntilChanged_(keySelector, EqualityComparer<TKey>.Default);
|
|
|
- }
|
|
|
-
|
|
|
- public static IAsyncEnumerable<TSource> DistinctUntilChanged<TSource, TKey>(this IAsyncEnumerable<TSource> source, Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer)
|
|
|
- {
|
|
|
- if (source == null)
|
|
|
- throw new ArgumentNullException(nameof(source));
|
|
|
- if (keySelector == null)
|
|
|
- throw new ArgumentNullException(nameof(keySelector));
|
|
|
- if (comparer == null)
|
|
|
- throw new ArgumentNullException(nameof(comparer));
|
|
|
-
|
|
|
- return source.DistinctUntilChanged_(keySelector, comparer);
|
|
|
- }
|
|
|
-
|
|
|
- public static IAsyncEnumerable<TSource> DistinctUntilChanged<TSource, TKey>(this IAsyncEnumerable<TSource> source, Func<TSource, Task<TKey>> keySelector)
|
|
|
- {
|
|
|
- if (source == null)
|
|
|
- throw new ArgumentNullException(nameof(source));
|
|
|
- if (keySelector == null)
|
|
|
- throw new ArgumentNullException(nameof(keySelector));
|
|
|
-
|
|
|
- return source.DistinctUntilChanged_(keySelector, EqualityComparer<TKey>.Default);
|
|
|
- }
|
|
|
-
|
|
|
- public static IAsyncEnumerable<TSource> DistinctUntilChanged<TSource, TKey>(this IAsyncEnumerable<TSource> source, Func<TSource, Task<TKey>> keySelector, IEqualityComparer<TKey> comparer)
|
|
|
- {
|
|
|
- if (source == null)
|
|
|
- throw new ArgumentNullException(nameof(source));
|
|
|
- if (keySelector == null)
|
|
|
- throw new ArgumentNullException(nameof(keySelector));
|
|
|
- if (comparer == null)
|
|
|
- throw new ArgumentNullException(nameof(comparer));
|
|
|
-
|
|
|
- return source.DistinctUntilChanged_(keySelector, comparer);
|
|
|
- }
|
|
|
-
|
|
|
- private static IAsyncEnumerable<TSource> DistinctUntilChanged_<TSource, TKey>(this IAsyncEnumerable<TSource> source, Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer)
|
|
|
- {
|
|
|
- return new DistinctUntilChangedAsyncIterator<TSource, TKey>(source, keySelector, comparer);
|
|
|
- }
|
|
|
-
|
|
|
- private static IAsyncEnumerable<TSource> DistinctUntilChanged_<TSource, TKey>(this IAsyncEnumerable<TSource> source, Func<TSource, Task<TKey>> keySelector, IEqualityComparer<TKey> comparer)
|
|
|
- {
|
|
|
- return new DistinctUntilChangedAsyncIteratorWithTask<TSource, TKey>(source, keySelector, comparer);
|
|
|
- }
|
|
|
-
|
|
|
private sealed class DistinctAsyncIterator<TSource> : AsyncIterator<TSource>, IIListProvider<TSource>
|
|
|
{
|
|
|
private readonly IEqualityComparer<TSource> comparer;
|
|
|
@@ -547,219 +475,5 @@ namespace System.Linq
|
|
|
return r;
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
- private sealed class DistinctUntilChangedAsyncIterator<TSource> : AsyncIterator<TSource>
|
|
|
- {
|
|
|
- private readonly IEqualityComparer<TSource> comparer;
|
|
|
- private readonly IAsyncEnumerable<TSource> source;
|
|
|
-
|
|
|
- private TSource currentValue;
|
|
|
- private IAsyncEnumerator<TSource> enumerator;
|
|
|
- private bool hasCurrentValue;
|
|
|
-
|
|
|
- public DistinctUntilChangedAsyncIterator(IAsyncEnumerable<TSource> source, IEqualityComparer<TSource> comparer)
|
|
|
- {
|
|
|
- Debug.Assert(comparer != null);
|
|
|
- Debug.Assert(source != null);
|
|
|
-
|
|
|
- this.source = source;
|
|
|
- this.comparer = comparer;
|
|
|
- }
|
|
|
-
|
|
|
- public override AsyncIterator<TSource> Clone()
|
|
|
- {
|
|
|
- return new DistinctUntilChangedAsyncIterator<TSource>(source, comparer);
|
|
|
- }
|
|
|
-
|
|
|
- public override async Task DisposeAsync()
|
|
|
- {
|
|
|
- if (enumerator != null)
|
|
|
- {
|
|
|
- await enumerator.DisposeAsync().ConfigureAwait(false);
|
|
|
- enumerator = null;
|
|
|
- currentValue = default(TSource);
|
|
|
- }
|
|
|
-
|
|
|
- await base.DisposeAsync().ConfigureAwait(false);
|
|
|
- }
|
|
|
-
|
|
|
- protected override async Task<bool> MoveNextCore()
|
|
|
- {
|
|
|
- switch (state)
|
|
|
- {
|
|
|
- case AsyncIteratorState.Allocated:
|
|
|
- enumerator = source.GetAsyncEnumerator();
|
|
|
- state = AsyncIteratorState.Iterating;
|
|
|
- goto case AsyncIteratorState.Iterating;
|
|
|
-
|
|
|
- case AsyncIteratorState.Iterating:
|
|
|
- while (await enumerator.MoveNextAsync().ConfigureAwait(false))
|
|
|
- {
|
|
|
- var item = enumerator.Current;
|
|
|
- var comparerEquals = false;
|
|
|
-
|
|
|
- if (hasCurrentValue)
|
|
|
- {
|
|
|
- comparerEquals = comparer.Equals(currentValue, item);
|
|
|
- }
|
|
|
-
|
|
|
- if (!hasCurrentValue || !comparerEquals)
|
|
|
- {
|
|
|
- hasCurrentValue = true;
|
|
|
- currentValue = item;
|
|
|
- current = item;
|
|
|
- return true;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- await DisposeAsync().ConfigureAwait(false);
|
|
|
- return false;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- private sealed class DistinctUntilChangedAsyncIterator<TSource, TKey> : AsyncIterator<TSource>
|
|
|
- {
|
|
|
- private readonly IEqualityComparer<TKey> comparer;
|
|
|
- private readonly Func<TSource, TKey> keySelector;
|
|
|
- private readonly IAsyncEnumerable<TSource> source;
|
|
|
- private TKey currentKeyValue;
|
|
|
-
|
|
|
- private IAsyncEnumerator<TSource> enumerator;
|
|
|
- private bool hasCurrentKey;
|
|
|
-
|
|
|
- public DistinctUntilChangedAsyncIterator(IAsyncEnumerable<TSource> source, Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer)
|
|
|
- {
|
|
|
- this.source = source;
|
|
|
- this.keySelector = keySelector;
|
|
|
- this.comparer = comparer;
|
|
|
- }
|
|
|
-
|
|
|
- public override AsyncIterator<TSource> Clone()
|
|
|
- {
|
|
|
- return new DistinctUntilChangedAsyncIterator<TSource, TKey>(source, keySelector, comparer);
|
|
|
- }
|
|
|
-
|
|
|
- public override async Task DisposeAsync()
|
|
|
- {
|
|
|
- if (enumerator != null)
|
|
|
- {
|
|
|
- await enumerator.DisposeAsync().ConfigureAwait(false);
|
|
|
- enumerator = null;
|
|
|
- currentKeyValue = default(TKey);
|
|
|
- }
|
|
|
-
|
|
|
- await base.DisposeAsync().ConfigureAwait(false);
|
|
|
- }
|
|
|
-
|
|
|
- protected override async Task<bool> MoveNextCore()
|
|
|
- {
|
|
|
- switch (state)
|
|
|
- {
|
|
|
- case AsyncIteratorState.Allocated:
|
|
|
- enumerator = source.GetAsyncEnumerator();
|
|
|
- state = AsyncIteratorState.Iterating;
|
|
|
- goto case AsyncIteratorState.Iterating;
|
|
|
-
|
|
|
- case AsyncIteratorState.Iterating:
|
|
|
- while (await enumerator.MoveNextAsync().ConfigureAwait(false))
|
|
|
- {
|
|
|
- var item = enumerator.Current;
|
|
|
- var key = keySelector(item);
|
|
|
- var comparerEquals = false;
|
|
|
-
|
|
|
- if (hasCurrentKey)
|
|
|
- {
|
|
|
- comparerEquals = comparer.Equals(currentKeyValue, key);
|
|
|
- }
|
|
|
- if (!hasCurrentKey || !comparerEquals)
|
|
|
- {
|
|
|
- hasCurrentKey = true;
|
|
|
- currentKeyValue = key;
|
|
|
- current = item;
|
|
|
- return true;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- break; // case
|
|
|
- }
|
|
|
-
|
|
|
- await DisposeAsync().ConfigureAwait(false);
|
|
|
- return false;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- private sealed class DistinctUntilChangedAsyncIteratorWithTask<TSource, TKey> : AsyncIterator<TSource>
|
|
|
- {
|
|
|
- private readonly IEqualityComparer<TKey> comparer;
|
|
|
- private readonly Func<TSource, Task<TKey>> keySelector;
|
|
|
- private readonly IAsyncEnumerable<TSource> source;
|
|
|
- private TKey currentKeyValue;
|
|
|
-
|
|
|
- private IAsyncEnumerator<TSource> enumerator;
|
|
|
- private bool hasCurrentKey;
|
|
|
-
|
|
|
- public DistinctUntilChangedAsyncIteratorWithTask(IAsyncEnumerable<TSource> source, Func<TSource, Task<TKey>> keySelector, IEqualityComparer<TKey> comparer)
|
|
|
- {
|
|
|
- this.source = source;
|
|
|
- this.keySelector = keySelector;
|
|
|
- this.comparer = comparer;
|
|
|
- }
|
|
|
-
|
|
|
- public override AsyncIterator<TSource> Clone()
|
|
|
- {
|
|
|
- return new DistinctUntilChangedAsyncIteratorWithTask<TSource, TKey>(source, keySelector, comparer);
|
|
|
- }
|
|
|
-
|
|
|
- public override async Task DisposeAsync()
|
|
|
- {
|
|
|
- if (enumerator != null)
|
|
|
- {
|
|
|
- await enumerator.DisposeAsync().ConfigureAwait(false);
|
|
|
- enumerator = null;
|
|
|
- currentKeyValue = default(TKey);
|
|
|
- }
|
|
|
-
|
|
|
- await base.DisposeAsync().ConfigureAwait(false);
|
|
|
- }
|
|
|
-
|
|
|
- protected override async Task<bool> MoveNextCore()
|
|
|
- {
|
|
|
- switch (state)
|
|
|
- {
|
|
|
- case AsyncIteratorState.Allocated:
|
|
|
- enumerator = source.GetAsyncEnumerator();
|
|
|
- state = AsyncIteratorState.Iterating;
|
|
|
- goto case AsyncIteratorState.Iterating;
|
|
|
-
|
|
|
- case AsyncIteratorState.Iterating:
|
|
|
- while (await enumerator.MoveNextAsync().ConfigureAwait(false))
|
|
|
- {
|
|
|
- var item = enumerator.Current;
|
|
|
- var key = await keySelector(item).ConfigureAwait(false);
|
|
|
- var comparerEquals = false;
|
|
|
-
|
|
|
- if (hasCurrentKey)
|
|
|
- {
|
|
|
- comparerEquals = comparer.Equals(currentKeyValue, key);
|
|
|
- }
|
|
|
- if (!hasCurrentKey || !comparerEquals)
|
|
|
- {
|
|
|
- hasCurrentKey = true;
|
|
|
- currentKeyValue = key;
|
|
|
- current = item;
|
|
|
- return true;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- break; // case
|
|
|
- }
|
|
|
-
|
|
|
- await DisposeAsync().ConfigureAwait(false);
|
|
|
- return false;
|
|
|
- }
|
|
|
- }
|
|
|
}
|
|
|
}
|