A cross-platform UI framework for .NET
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

144 lines
3.9 KiB

using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
namespace Avalonia.Utilities
{
/// <summary>
/// Stores either a single key value pair or constructs a dictionary when more than one value is stored.
/// </summary>
/// <typeparam name="TKey">The type of the key.</typeparam>
/// <typeparam name="TValue">The type of the value.</typeparam>
internal class SingleOrDictionary<TKey, TValue> : IEnumerable<KeyValuePair<TKey, TValue>>
where TKey : notnull
{
private KeyValuePair<TKey, TValue>? _singleValue;
private Dictionary<TKey, TValue>? dictionary;
public void Add(TKey key, TValue value)
{
if (_singleValue != null)
{
dictionary = new Dictionary<TKey, TValue>();
((ICollection<KeyValuePair<TKey, TValue>>)dictionary).Add(_singleValue.Value);
_singleValue = null;
}
if (dictionary != null)
{
dictionary.Add(key, value);
}
else
{
_singleValue = new KeyValuePair<TKey, TValue>(key, value);
}
}
public bool TryGetValue(TKey key, [MaybeNullWhen(false)] out TValue value)
{
if (dictionary == null)
{
if (!_singleValue.HasValue || !EqualityComparer<TKey>.Default.Equals(_singleValue.Value.Key, key))
{
value = default;
return false;
}
else
{
value = _singleValue.Value.Value;
return true;
}
}
else
{
return dictionary.TryGetValue(key, out value);
}
}
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
{
if (dictionary == null)
{
if (_singleValue.HasValue)
{
return new SingleEnumerator<KeyValuePair<TKey, TValue>>(_singleValue.Value);
}
}
else
{
return dictionary.GetEnumerator();
}
return Enumerable.Empty<KeyValuePair<TKey, TValue>>().GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public IEnumerable<TValue> Values
{
get
{
if(dictionary == null)
{
if (_singleValue.HasValue)
{
return new[] { _singleValue.Value.Value };
}
}
else
{
return dictionary.Values;
}
return Enumerable.Empty<TValue>();
}
}
private class SingleEnumerator<T> : IEnumerator<T>
{
private readonly T value;
private int index = -1;
public SingleEnumerator(T value)
{
this.value = value;
}
public T Current
{
get
{
if (index == 0)
{
return value;
}
else
{
throw new InvalidOperationException();
}
}
}
object? IEnumerator.Current => Current;
public void Dispose()
{
}
public bool MoveNext()
{
index++;
return index < 1;
}
public void Reset()
{
index = -1;
}
}
}
}