using System.Collections; using System.Runtime.CompilerServices; namespace Penumbra.Api.Helpers; /// A dictionary that implicitly can be converted to a read-only dictionary with different value type. /// The type of the keys. /// The actual type of the values. /// The read-only type of the values. public abstract class ConvertingDict(IReadOnlyDictionary dict) : IReadOnlyDictionary where TKey : notnull { /// Obtain the original dictionary. public IReadOnlyDictionary Original => dict; /// Conversion between values. [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] protected abstract TValueTo ConvertValue(in TValueFrom from); /// public bool ContainsKey(TKey key) => dict.ContainsKey(key); /// public bool TryGetValue(TKey key, out TValueTo value) { if (dict.TryGetValue(key, out var v)) { value = ConvertValue(v); return true; } value = default!; return false; } /// public TValueTo this[TKey key] => ConvertValue(dict[key]); public IEnumerable Keys => dict.Keys; /// public IEnumerable Values { get { foreach (var value in dict.Values) yield return ConvertValue(value); } } /// public int Count => dict.Count; /// public IEnumerator> GetEnumerator() { foreach (var kvp in dict) yield return new KeyValuePair(kvp.Key, ConvertValue(kvp.Value)); } IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); } /// A dictionary that implicitly can be converted to a read-only dictionary with different value type. /// The actual type of the keys. /// The read-only type of the keys. /// The actual type of the values. /// The read-only type of the values. public abstract class ConvertingDict(IReadOnlyDictionary dict) : IReadOnlyDictionary where TKeyFrom : notnull where TKeyTo : notnull { /// Obtain the original dictionary. public IReadOnlyDictionary Original => dict; /// Conversion between keys. [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] protected abstract TKeyTo ConvertKey(in TKeyFrom from); /// Conversion between keys. [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] protected abstract TKeyFrom ConvertKeyBack(in TKeyTo from); /// Conversion between values. [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] protected abstract TValueTo ConvertValue(in TValueFrom from); /// public bool ContainsKey(TKeyTo key) => dict.ContainsKey(ConvertKeyBack(key)); /// public bool TryGetValue(TKeyTo key, out TValueTo value) { if (dict.TryGetValue(ConvertKeyBack(key), out var v)) { value = ConvertValue(v); return true; } value = default!; return false; } /// public TValueTo this[TKeyTo key] => ConvertValue(dict[ConvertKeyBack(key)]); /// public IEnumerable Keys { get { foreach (var key in dict.Keys) yield return ConvertKey(key); } } /// public IEnumerable Values { get { foreach (var value in dict.Values) yield return ConvertValue(value); } } /// public IEnumerator> GetEnumerator() { foreach (var kvp in dict) yield return new KeyValuePair(ConvertKey(kvp.Key), ConvertValue(kvp.Value)); } /// IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); /// public int Count => dict.Count; }