// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT License. // See the LICENSE file in the project root for more information. #nullable disable // TODO: Substitute for implementation that doesn't use DictionaryK, V>. using System.Collections; using System.Collections.Generic; using System.Linq; namespace System.Reactive { internal sealed class Lookup : ILookup { private readonly Dictionary> _dictionary; public Lookup(IEqualityComparer comparer) { _dictionary = new Dictionary>(comparer); } public void Add(K key, E element) { if (!_dictionary.TryGetValue(key, out var list)) { _dictionary[key] = list = new List(); } list.Add(element); } public bool Contains(K key) => _dictionary.ContainsKey(key); public int Count => _dictionary.Count; public IEnumerable this[K key] { get { if (!_dictionary.TryGetValue(key, out var list)) { return Enumerable.Empty(); } return Hide(list); } } // Instead of yielding the elements in a foreach loop, zero // elements are skipped. Technically the result is the same // with the benefit that the LINQ implementation can internally // generate a type that keeps track of count of the enumerable. // Consecutive operators can benefit from that knowledge. private static IEnumerable Hide(List elements) => elements.Skip(0); public IEnumerator> GetEnumerator() { foreach (var kv in _dictionary) { yield return new Grouping(kv); } } private sealed class Grouping : IGrouping { private readonly KeyValuePair> _keyValuePair; public Grouping(KeyValuePair> keyValuePair) { _keyValuePair = keyValuePair; } public K Key => _keyValuePair.Key; public IEnumerator GetEnumerator() => _keyValuePair.Value.GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); } }