#nullable disable using System.Collections; using System.Runtime.CompilerServices; namespace Jint.Collections { internal class HybridDictionary : IEnumerable> { private const int CutoverPoint = 9; private const int InitialDictionarySize = 13; private const int FixedSizeCutoverPoint = 6; private readonly bool _checkExistingKeys; private ListDictionary _list; internal StringDictionarySlim _dictionary; public HybridDictionary() : this(0, checkExistingKeys: true) { } public HybridDictionary(int initialSize, bool checkExistingKeys) { _checkExistingKeys = checkExistingKeys; if (initialSize >= FixedSizeCutoverPoint) { _dictionary = new StringDictionarySlim(initialSize); } } protected HybridDictionary(StringDictionarySlim dictionary) { _checkExistingKeys = true; _dictionary = dictionary; } public TValue this[Key key] { get { TryGetValue(key, out var value); return value; } set { if (_dictionary != null) { _dictionary[key] = value; } else if (_list != null) { if (_list.Count >= CutoverPoint - 1) { SwitchToDictionary(key, value, tryAdd: false); } else { _list[key] = value; } } else { _list = new ListDictionary(key, value, _checkExistingKeys); } } } public bool TryGetValue(Key key, out TValue value) { if (_dictionary != null) { return _dictionary.TryGetValue(key, out value); } if (_list != null) { return _list.TryGetValue(key, out value); } value = default; return false; } public void SetOrUpdateValue(Key key, Func updater, TState state) { if (_dictionary != null) { _dictionary.SetOrUpdateValue(key, updater, state); } else if (_list != null) { _list.SetOrUpdateValue(key, updater, state); } else { _list = new ListDictionary(key, updater(default, state), _checkExistingKeys); } } private bool SwitchToDictionary(Key key, TValue value, bool tryAdd) { var dictionary = new StringDictionarySlim(InitialDictionarySize); foreach (var pair in _list) { dictionary[pair.Key] = pair.Value; } bool result; if (tryAdd) { result = dictionary.TryAdd(key, value); } else { dictionary[key] = value; result = true; } _dictionary = dictionary; _list = null; return result; } public int Count { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => _dictionary?.Count ?? _list?.Count ?? 0; } public bool TryAdd(Key key, TValue value) { if (_dictionary != null) { return _dictionary.TryAdd(key, value); } else { _list ??= new ListDictionary(key, value, _checkExistingKeys); if (_list.Count + 1 >= CutoverPoint) { return SwitchToDictionary(key, value, tryAdd: true); } else { return _list.Add(key, value, tryAdd: true); } } } public void Add(Key key, TValue value) { if (_dictionary != null) { _dictionary.GetOrAddValueRef(key) = value; } else { if (_list == null) { _list = new ListDictionary(key, value, _checkExistingKeys); } else { if (_list.Count + 1 >= CutoverPoint) { SwitchToDictionary(key, value, tryAdd: false); } else { _list.Add(key, value); } } } } public void Clear() { _dictionary?.Clear(); _list?.Clear(); } public bool ContainsKey(Key key) { if (_dictionary != null) { return _dictionary.ContainsKey(key); } if (_list != null) { return _list.ContainsKey(key); } return false; } IEnumerator> IEnumerable>.GetEnumerator() { if (_dictionary != null) { return _dictionary.GetEnumerator(); } if (_list != null) { return _list.GetEnumerator(); } return System.Linq.Enumerable.Empty>().GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { if (_dictionary != null) { return _dictionary.GetEnumerator(); } if (_list != null) { return _list.GetEnumerator(); } return System.Linq.Enumerable.Empty>().GetEnumerator(); } public bool Remove(Key key) { if (_dictionary != null) { return _dictionary.Remove(key); } return _list != null && _list.Remove(key); } /// /// Optimization when no need to check for existing items. /// public bool CheckExistingKeys { set { if (_list != null) { _list.CheckExistingKeys = value; } } } } }