Files
spectre.console/src/Spectre.Console/Cli/Internal/Collections/MultiMap.cs
Patrik Svensson a23bec4082 Add profile support
Closes #231
2021-01-19 17:53:03 +01:00

174 lines
4.5 KiB
C#

using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
namespace Spectre.Console.Cli
{
[SuppressMessage("Performance", "CA1812: Avoid uninstantiated internal classes")]
internal sealed class MultiMap<TKey, TValue> : IMultiMap, ILookup<TKey, TValue>, IDictionary<TKey, TValue>, IReadOnlyDictionary<TKey, TValue>
where TKey : notnull
{
private readonly IDictionary<TKey, MultiMapGrouping> _lookup;
private readonly IDictionary<TKey, TValue> _dictionary;
public int Count => _lookup.Count;
public bool IsReadOnly => false;
public ICollection<TKey> Keys => _lookup.Keys;
public ICollection<TValue> Values => _dictionary.Values;
IEnumerable<TKey> IReadOnlyDictionary<TKey, TValue>.Keys => _lookup.Keys;
IEnumerable<TValue> IReadOnlyDictionary<TKey, TValue>.Values => _dictionary.Values;
TValue IReadOnlyDictionary<TKey, TValue>.this[TKey key] => _dictionary[key];
TValue IDictionary<TKey, TValue>.this[TKey key]
{
get
{
return _dictionary[key];
}
set
{
Add(key, value);
}
}
public IEnumerable<TValue> this[TKey key]
{
get
{
if (_lookup.TryGetValue(key, out var group))
{
return group;
}
return Array.Empty<TValue>();
}
}
public MultiMap()
{
_lookup = new Dictionary<TKey, MultiMapGrouping>();
_dictionary = new Dictionary<TKey, TValue>();
}
private sealed class MultiMapGrouping : IGrouping<TKey, TValue>
{
private readonly List<TValue> _items;
public TKey Key { get; }
public MultiMapGrouping(TKey key, List<TValue> items)
{
Key = key;
_items = items;
}
public void Add(TValue value)
{
_items.Add(value);
}
public IEnumerator<TValue> GetEnumerator()
{
return _items.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
public bool Contains(TKey key)
{
return _lookup.ContainsKey(key);
}
public IEnumerator<IGrouping<TKey, TValue>> GetEnumerator()
{
foreach (var group in _lookup.Values)
{
yield return group;
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public void Add(TKey key, TValue value)
{
if (!_lookup.ContainsKey(key))
{
_lookup[key] = new MultiMapGrouping(key, new List<TValue>());
}
_lookup[key].Add(value);
_dictionary[key] = value;
}
public bool ContainsKey(TKey key)
{
return Contains(key);
}
public bool Remove(TKey key)
{
return _lookup.Remove(key);
}
public bool TryGetValue(TKey key, [MaybeNullWhen(false)] out TValue value)
{
return _dictionary.TryGetValue(key, out value);
}
public void Add(KeyValuePair<TKey, TValue> item)
{
Add(item.Key, item.Value);
}
public void Clear()
{
_lookup.Clear();
}
public bool Contains(KeyValuePair<TKey, TValue> item)
{
return Contains(item.Key);
}
public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
{
_dictionary.CopyTo(array, arrayIndex);
}
public bool Remove(KeyValuePair<TKey, TValue> item)
{
return Remove(item.Key);
}
IEnumerator<KeyValuePair<TKey, TValue>> IEnumerable<KeyValuePair<TKey, TValue>>.GetEnumerator()
{
return _dictionary.GetEnumerator();
}
public void Add((object? Key, object? Value) pair)
{
if (pair.Key != null)
{
#pragma warning disable CS8604 // Possible null reference argument of value.
Add((TKey)pair.Key, (TValue)pair.Value);
#pragma warning restore CS8604 // Possible null reference argument of value.
}
}
}
}