|  | @@ -32,6 +32,26 @@ namespace System.Linq
 | 
	
		
			
				|  |  |              return source.ToLookup(keySelector, x => x, EqualityComparer<TKey>.Default, cancellationToken);
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +        public static Task<ILookup<TKey, TSource>> ToLookup<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 ToLookup(source, keySelector, CancellationToken.None);
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        public static Task<ILookup<TKey, TSource>> ToLookup<TSource, TKey>(this IAsyncEnumerable<TSource> source, Func<TSource, Task<TKey>> keySelector, CancellationToken cancellationToken)
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            if (source == null)
 | 
	
		
			
				|  |  | +                throw new ArgumentNullException(nameof(source));
 | 
	
		
			
				|  |  | +            if (keySelector == null)
 | 
	
		
			
				|  |  | +                throw new ArgumentNullException(nameof(keySelector));
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            return source.ToLookup(keySelector, x => Task.FromResult(x), EqualityComparer<TKey>.Default, cancellationToken);
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |          public static Task<ILookup<TKey, TSource>> ToLookup<TSource, TKey>(this IAsyncEnumerable<TSource> source, Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer)
 | 
	
		
			
				|  |  |          {
 | 
	
		
			
				|  |  |              if (source == null)
 | 
	
	
		
			
				|  | @@ -56,6 +76,30 @@ namespace System.Linq
 | 
	
		
			
				|  |  |              return source.ToLookup(keySelector, x => x, comparer, cancellationToken);
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +        public static Task<ILookup<TKey, TSource>> ToLookup<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 ToLookup(source, keySelector, comparer, CancellationToken.None);
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        public static Task<ILookup<TKey, TSource>> ToLookup<TSource, TKey>(this IAsyncEnumerable<TSource> source, Func<TSource, Task<TKey>> keySelector, IEqualityComparer<TKey> comparer, CancellationToken cancellationToken)
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            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.ToLookup(keySelector, x => Task.FromResult(x), comparer, cancellationToken);
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |          public static Task<ILookup<TKey, TElement>> ToLookup<TSource, TKey, TElement>(this IAsyncEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector)
 | 
	
		
			
				|  |  |          {
 | 
	
		
			
				|  |  |              if (source == null)
 | 
	
	
		
			
				|  | @@ -80,6 +124,30 @@ namespace System.Linq
 | 
	
		
			
				|  |  |              return source.ToLookup(keySelector, elementSelector, EqualityComparer<TKey>.Default, cancellationToken);
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +        public static Task<ILookup<TKey, TElement>> ToLookup<TSource, TKey, TElement>(this IAsyncEnumerable<TSource> source, Func<TSource, Task<TKey>> keySelector, Func<TSource, Task<TElement>> elementSelector)
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            if (source == null)
 | 
	
		
			
				|  |  | +                throw new ArgumentNullException(nameof(source));
 | 
	
		
			
				|  |  | +            if (keySelector == null)
 | 
	
		
			
				|  |  | +                throw new ArgumentNullException(nameof(keySelector));
 | 
	
		
			
				|  |  | +            if (elementSelector == null)
 | 
	
		
			
				|  |  | +                throw new ArgumentNullException(nameof(elementSelector));
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            return ToLookup(source, keySelector, elementSelector, CancellationToken.None);
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        public static Task<ILookup<TKey, TElement>> ToLookup<TSource, TKey, TElement>(this IAsyncEnumerable<TSource> source, Func<TSource, Task<TKey>> keySelector, Func<TSource, Task<TElement>> elementSelector, CancellationToken cancellationToken)
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            if (source == null)
 | 
	
		
			
				|  |  | +                throw new ArgumentNullException(nameof(source));
 | 
	
		
			
				|  |  | +            if (keySelector == null)
 | 
	
		
			
				|  |  | +                throw new ArgumentNullException(nameof(keySelector));
 | 
	
		
			
				|  |  | +            if (elementSelector == null)
 | 
	
		
			
				|  |  | +                throw new ArgumentNullException(nameof(elementSelector));
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            return source.ToLookup(keySelector, elementSelector, EqualityComparer<TKey>.Default, cancellationToken);
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |          public static Task<ILookup<TKey, TElement>> ToLookup<TSource, TKey, TElement>(this IAsyncEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector, IEqualityComparer<TKey> comparer)
 | 
	
		
			
				|  |  |          {
 | 
	
		
			
				|  |  |              if (source == null)
 | 
	
	
		
			
				|  | @@ -109,6 +177,36 @@ namespace System.Linq
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |              return lookup;
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        public static Task<ILookup<TKey, TElement>> ToLookup<TSource, TKey, TElement>(this IAsyncEnumerable<TSource> source, Func<TSource, Task<TKey>> keySelector, Func<TSource, Task<TElement>> elementSelector, IEqualityComparer<TKey> comparer)
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            if (source == null)
 | 
	
		
			
				|  |  | +                throw new ArgumentNullException(nameof(source));
 | 
	
		
			
				|  |  | +            if (keySelector == null)
 | 
	
		
			
				|  |  | +                throw new ArgumentNullException(nameof(keySelector));
 | 
	
		
			
				|  |  | +            if (elementSelector == null)
 | 
	
		
			
				|  |  | +                throw new ArgumentNullException(nameof(elementSelector));
 | 
	
		
			
				|  |  | +            if (comparer == null)
 | 
	
		
			
				|  |  | +                throw new ArgumentNullException(nameof(comparer));
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            return ToLookup(source, keySelector, elementSelector, comparer, CancellationToken.None);
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        public static async Task<ILookup<TKey, TElement>> ToLookup<TSource, TKey, TElement>(this IAsyncEnumerable<TSource> source, Func<TSource, Task<TKey>> keySelector, Func<TSource, Task<TElement>> elementSelector, IEqualityComparer<TKey> comparer, CancellationToken cancellationToken)
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            if (source == null)
 | 
	
		
			
				|  |  | +                throw new ArgumentNullException(nameof(source));
 | 
	
		
			
				|  |  | +            if (keySelector == null)
 | 
	
		
			
				|  |  | +                throw new ArgumentNullException(nameof(keySelector));
 | 
	
		
			
				|  |  | +            if (elementSelector == null)
 | 
	
		
			
				|  |  | +                throw new ArgumentNullException(nameof(elementSelector));
 | 
	
		
			
				|  |  | +            if (comparer == null)
 | 
	
		
			
				|  |  | +                throw new ArgumentNullException(nameof(comparer));
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            var lookup = await Internal.LookupWithTask<TKey, TElement>.CreateAsync(source, keySelector, elementSelector, comparer).ConfigureAwait(false);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            return lookup;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -201,7 +299,11 @@ namespace System.Linq.Internal
 | 
	
		
			
				|  |  |              {
 | 
	
		
			
				|  |  |                  while (await enu.MoveNextAsync(cancellationToken).ConfigureAwait(false))
 | 
	
		
			
				|  |  |                  {
 | 
	
		
			
				|  |  | -                    lookup.GetGrouping(keySelector(enu.Current), create: true).Add(elementSelector(enu.Current));
 | 
	
		
			
				|  |  | +                    var key = keySelector(enu.Current);
 | 
	
		
			
				|  |  | +                    var group = lookup.GetGrouping(key, create: true);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                    var element = elementSelector(enu.Current);
 | 
	
		
			
				|  |  | +                    group.Add(element);
 | 
	
		
			
				|  |  |                  }
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  |              finally
 | 
	
	
		
			
				|  | @@ -413,4 +515,306 @@ namespace System.Linq.Internal
 | 
	
		
			
				|  |  |              return Task.FromResult(array);
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    internal class LookupWithTask<TKey, TElement> : ILookup<TKey, TElement>, IIListProvider<IAsyncGrouping<TKey, TElement>>
 | 
	
		
			
				|  |  | +    {
 | 
	
		
			
				|  |  | +        private readonly IEqualityComparer<TKey> _comparer;
 | 
	
		
			
				|  |  | +        private Grouping<TKey, TElement>[] _groupings;
 | 
	
		
			
				|  |  | +        private Grouping<TKey, TElement> _lastGrouping;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        private LookupWithTask(IEqualityComparer<TKey> comparer)
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            _comparer = comparer ?? EqualityComparer<TKey>.Default;
 | 
	
		
			
				|  |  | +            _groupings = new Grouping<TKey, TElement>[7];
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        public int Count { get; private set; }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        public IEnumerable<TElement> this[TKey key]
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            get
 | 
	
		
			
				|  |  | +            {
 | 
	
		
			
				|  |  | +                var grouping = GetGrouping(key, create: false);
 | 
	
		
			
				|  |  | +                if (grouping != null)
 | 
	
		
			
				|  |  | +                {
 | 
	
		
			
				|  |  | +                    return grouping;
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +#if NO_ARRAY_EMPTY
 | 
	
		
			
				|  |  | +                return EmptyArray<TElement>.Value;
 | 
	
		
			
				|  |  | +#else
 | 
	
		
			
				|  |  | +                return Array.Empty<TElement>();
 | 
	
		
			
				|  |  | +#endif
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        public bool Contains(TKey key)
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            return GetGrouping(key, create: false) != null;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        IEnumerator IEnumerable.GetEnumerator()
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            return GetEnumerator();
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        public IEnumerator<IGrouping<TKey, TElement>> GetEnumerator()
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            var g = _lastGrouping;
 | 
	
		
			
				|  |  | +            if (g != null)
 | 
	
		
			
				|  |  | +            {
 | 
	
		
			
				|  |  | +                do
 | 
	
		
			
				|  |  | +                {
 | 
	
		
			
				|  |  | +                    g = g._next;
 | 
	
		
			
				|  |  | +                    yield return g;
 | 
	
		
			
				|  |  | +                } while (g != _lastGrouping);
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        public IEnumerable<TResult> ApplyResultSelector<TResult>(Func<TKey, IAsyncEnumerable<TElement>, TResult> resultSelector)
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            var g = _lastGrouping;
 | 
	
		
			
				|  |  | +            if (g != null)
 | 
	
		
			
				|  |  | +            {
 | 
	
		
			
				|  |  | +                do
 | 
	
		
			
				|  |  | +                {
 | 
	
		
			
				|  |  | +                    g = g._next;
 | 
	
		
			
				|  |  | +                    g.Trim();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                    var result = resultSelector(g._key, g._elements.ToAsyncEnumerable());
 | 
	
		
			
				|  |  | +                    yield return result;
 | 
	
		
			
				|  |  | +                } while (g != _lastGrouping);
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        internal static async Task<LookupWithTask<TKey, TElement>> CreateAsync<TSource>(IAsyncEnumerable<TSource> source, Func<TSource, Task<TKey>> keySelector, Func<TSource, Task<TElement>> elementSelector, IEqualityComparer<TKey> comparer, CancellationToken cancellationToken = default(CancellationToken))
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            Debug.Assert(source != null);
 | 
	
		
			
				|  |  | +            Debug.Assert(keySelector != null);
 | 
	
		
			
				|  |  | +            Debug.Assert(elementSelector != null);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            var lookup = new LookupWithTask<TKey, TElement>(comparer);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            var enu = source.GetAsyncEnumerator();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            try
 | 
	
		
			
				|  |  | +            {
 | 
	
		
			
				|  |  | +                while (await enu.MoveNextAsync(cancellationToken).ConfigureAwait(false))
 | 
	
		
			
				|  |  | +                {
 | 
	
		
			
				|  |  | +                    var key = await keySelector(enu.Current).ConfigureAwait(false);
 | 
	
		
			
				|  |  | +                    var group = lookup.GetGrouping(key, create: true);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                    var element = await elementSelector(enu.Current).ConfigureAwait(false);
 | 
	
		
			
				|  |  | +                    group.Add(element);
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +            finally
 | 
	
		
			
				|  |  | +            {
 | 
	
		
			
				|  |  | +                await enu.DisposeAsync().ConfigureAwait(false);
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            return lookup;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        internal static async Task<LookupWithTask<TKey, TElement>> CreateAsync(IAsyncEnumerable<TElement> source, Func<TElement, Task<TKey>> keySelector, IEqualityComparer<TKey> comparer, CancellationToken cancellationToken = default(CancellationToken))
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            Debug.Assert(source != null);
 | 
	
		
			
				|  |  | +            Debug.Assert(keySelector != null);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            var lookup = new LookupWithTask<TKey, TElement>(comparer);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            var enu = source.GetAsyncEnumerator();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            try
 | 
	
		
			
				|  |  | +            {
 | 
	
		
			
				|  |  | +                while (await enu.MoveNextAsync(cancellationToken).ConfigureAwait(false))
 | 
	
		
			
				|  |  | +                {
 | 
	
		
			
				|  |  | +                    var key = await keySelector(enu.Current).ConfigureAwait(false);
 | 
	
		
			
				|  |  | +                    lookup.GetGrouping(key, create: true).Add(enu.Current);
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +            finally
 | 
	
		
			
				|  |  | +            {
 | 
	
		
			
				|  |  | +                await enu.DisposeAsync().ConfigureAwait(false);
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            return lookup;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        internal static async Task<LookupWithTask<TKey, TElement>> CreateForJoinAsync(IAsyncEnumerable<TElement> source, Func<TElement, Task<TKey>> keySelector, IEqualityComparer<TKey> comparer)
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            var lookup = new LookupWithTask<TKey, TElement>(comparer);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            var enu = source.GetAsyncEnumerator();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            try
 | 
	
		
			
				|  |  | +            {
 | 
	
		
			
				|  |  | +                while (await enu.MoveNextAsync().ConfigureAwait(false))
 | 
	
		
			
				|  |  | +                {
 | 
	
		
			
				|  |  | +                    var key = await keySelector(enu.Current).ConfigureAwait(false);
 | 
	
		
			
				|  |  | +                    if (key != null)
 | 
	
		
			
				|  |  | +                    {
 | 
	
		
			
				|  |  | +                        lookup.GetGrouping(key, create: true).Add(enu.Current);
 | 
	
		
			
				|  |  | +                    }
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +            finally
 | 
	
		
			
				|  |  | +            {
 | 
	
		
			
				|  |  | +                await enu.DisposeAsync().ConfigureAwait(false);
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            return lookup;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        internal Grouping<TKey, TElement> GetGrouping(TKey key, bool create)
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            var hashCode = InternalGetHashCode(key);
 | 
	
		
			
				|  |  | +            for (var g = _groupings[hashCode % _groupings.Length]; g != null; g = g._hashNext)
 | 
	
		
			
				|  |  | +            {
 | 
	
		
			
				|  |  | +                if (g._hashCode == hashCode && _comparer.Equals(g._key, key))
 | 
	
		
			
				|  |  | +                {
 | 
	
		
			
				|  |  | +                    return g;
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            if (create)
 | 
	
		
			
				|  |  | +            {
 | 
	
		
			
				|  |  | +                if (Count == _groupings.Length)
 | 
	
		
			
				|  |  | +                {
 | 
	
		
			
				|  |  | +                    Resize();
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                var index = hashCode % _groupings.Length;
 | 
	
		
			
				|  |  | +                var g = new Grouping<TKey, TElement>
 | 
	
		
			
				|  |  | +                {
 | 
	
		
			
				|  |  | +                    _key = key,
 | 
	
		
			
				|  |  | +                    _hashCode = hashCode,
 | 
	
		
			
				|  |  | +                    _elements = new TElement[1],
 | 
	
		
			
				|  |  | +                    _hashNext = _groupings[index]
 | 
	
		
			
				|  |  | +                };
 | 
	
		
			
				|  |  | +                _groupings[index] = g;
 | 
	
		
			
				|  |  | +                if (_lastGrouping == null)
 | 
	
		
			
				|  |  | +                {
 | 
	
		
			
				|  |  | +                    g._next = g;
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +                else
 | 
	
		
			
				|  |  | +                {
 | 
	
		
			
				|  |  | +                    g._next = _lastGrouping._next;
 | 
	
		
			
				|  |  | +                    _lastGrouping._next = g;
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                _lastGrouping = g;
 | 
	
		
			
				|  |  | +                Count++;
 | 
	
		
			
				|  |  | +                return g;
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            return null;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        internal int InternalGetHashCode(TKey key)
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            // Handle comparer implementations that throw when passed null
 | 
	
		
			
				|  |  | +            return (key == null) ? 0 : _comparer.GetHashCode(key) & 0x7FFFFFFF;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        internal async Task<TResult[]> ToArray<TResult>(Func<TKey, IAsyncEnumerable<TElement>, Task<TResult>> resultSelector)
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            var array = new TResult[Count];
 | 
	
		
			
				|  |  | +            var index = 0;
 | 
	
		
			
				|  |  | +            var g = _lastGrouping;
 | 
	
		
			
				|  |  | +            if (g != null)
 | 
	
		
			
				|  |  | +            {
 | 
	
		
			
				|  |  | +                do
 | 
	
		
			
				|  |  | +                {
 | 
	
		
			
				|  |  | +                    g = g._next;
 | 
	
		
			
				|  |  | +                    g.Trim();
 | 
	
		
			
				|  |  | +                    array[index] = await resultSelector(g._key, g._elements.ToAsyncEnumerable()).ConfigureAwait(false);
 | 
	
		
			
				|  |  | +                    ++index;
 | 
	
		
			
				|  |  | +                } while (g != _lastGrouping);
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            return array;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        internal async Task<List<TResult>> ToList<TResult>(Func<TKey, IAsyncEnumerable<TElement>, Task<TResult>> resultSelector)
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            var list = new List<TResult>(Count);
 | 
	
		
			
				|  |  | +            var g = _lastGrouping;
 | 
	
		
			
				|  |  | +            if (g != null)
 | 
	
		
			
				|  |  | +            {
 | 
	
		
			
				|  |  | +                do
 | 
	
		
			
				|  |  | +                {
 | 
	
		
			
				|  |  | +                    g = g._next;
 | 
	
		
			
				|  |  | +                    g.Trim();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                    var result = await resultSelector(g._key, g._elements.ToAsyncEnumerable()).ConfigureAwait(false);
 | 
	
		
			
				|  |  | +                    list.Add(result);
 | 
	
		
			
				|  |  | +                } while (g != _lastGrouping);
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            return list;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        private void Resize()
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            var newSize = checked((Count * 2) + 1);
 | 
	
		
			
				|  |  | +            var newGroupings = new Grouping<TKey, TElement>[newSize];
 | 
	
		
			
				|  |  | +            var g = _lastGrouping;
 | 
	
		
			
				|  |  | +            do
 | 
	
		
			
				|  |  | +            {
 | 
	
		
			
				|  |  | +                g = g._next;
 | 
	
		
			
				|  |  | +                var index = g._hashCode % newSize;
 | 
	
		
			
				|  |  | +                g._hashNext = newGroupings[index];
 | 
	
		
			
				|  |  | +                newGroupings[index] = g;
 | 
	
		
			
				|  |  | +            } while (g != _lastGrouping);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            _groupings = newGroupings;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        public Task<int> GetCountAsync(bool onlyIfCheap, CancellationToken cancellationToken)
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            return Task.FromResult(Count);
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        IAsyncEnumerator<IAsyncGrouping<TKey, TElement>> IAsyncEnumerable<IAsyncGrouping<TKey, TElement>>.GetAsyncEnumerator()
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            return Enumerable.Cast<IAsyncGrouping<TKey, TElement>>(this).ToAsyncEnumerable().GetAsyncEnumerator();
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        Task<List<IAsyncGrouping<TKey, TElement>>> IIListProvider<IAsyncGrouping<TKey, TElement>>.ToListAsync(CancellationToken cancellationToken)
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            var list = new List<IAsyncGrouping<TKey, TElement>>(Count);
 | 
	
		
			
				|  |  | +            var g = _lastGrouping;
 | 
	
		
			
				|  |  | +            if (g != null)
 | 
	
		
			
				|  |  | +            {
 | 
	
		
			
				|  |  | +                do
 | 
	
		
			
				|  |  | +                {
 | 
	
		
			
				|  |  | +                    g = g._next;
 | 
	
		
			
				|  |  | +                    list.Add(g);
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +                while (g != _lastGrouping);
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            return Task.FromResult(list);
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        Task<IAsyncGrouping<TKey, TElement>[]> IIListProvider<IAsyncGrouping<TKey, TElement>>.ToArrayAsync(CancellationToken cancellationToken)
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            var array = new IAsyncGrouping<TKey, TElement>[Count];
 | 
	
		
			
				|  |  | +            var index = 0;
 | 
	
		
			
				|  |  | +            var g = _lastGrouping;
 | 
	
		
			
				|  |  | +            if (g != null)
 | 
	
		
			
				|  |  | +            {
 | 
	
		
			
				|  |  | +                do
 | 
	
		
			
				|  |  | +                {
 | 
	
		
			
				|  |  | +                    g = g._next;
 | 
	
		
			
				|  |  | +                    array[index] = g;
 | 
	
		
			
				|  |  | +                    ++index;
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +                while (g != _lastGrouping);
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            return Task.FromResult(array);
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  |  }
 |