123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289 |
- #nullable disable
- using System.Collections;
- using System.Runtime.CompilerServices;
- namespace Jint.Collections;
- internal sealed class HybridDictionary<TValue> : IEngineDictionary<Key, TValue>, IEnumerable<KeyValuePair<Key, TValue>>
- {
- private const int CutoverPoint = 9;
- private const int InitialDictionarySize = 13;
- private const int FixedSizeCutoverPoint = 6;
- private readonly bool _checkExistingKeys;
- private ListDictionary<TValue> _list;
- internal StringDictionarySlim<TValue> _dictionary;
- public HybridDictionary() : this(0, checkExistingKeys: true)
- {
- }
- public HybridDictionary(int initialSize, bool checkExistingKeys)
- {
- _checkExistingKeys = checkExistingKeys;
- if (initialSize >= FixedSizeCutoverPoint)
- {
- _dictionary = new StringDictionarySlim<TValue>(initialSize);
- }
- }
- public HybridDictionary(StringDictionarySlim<TValue> dictionary)
- {
- _checkExistingKeys = true;
- _dictionary = dictionary;
- }
- public ref TValue this[Key key]
- {
- get
- {
- if (_dictionary != null)
- {
- return ref _dictionary[key];
- }
- if (_list != null)
- {
- if (_list.Count >= CutoverPoint - 1)
- {
- return ref SwitchToDictionary(key);
- }
- return ref _list[key];
- }
- var head = new ListDictionary<TValue>.DictionaryNode { Key = key, Value = default };
- _list = new ListDictionary<TValue>(head, _checkExistingKeys);
- return ref head.Value;
- }
- }
- 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 ref TValue GetValueRefOrNullRef(Key key)
- {
- if (_dictionary != null)
- {
- return ref _dictionary.GetValueRefOrNullRef(key);
- }
- if (_list != null)
- {
- return ref _list.GetValueRefOrNullRef(key);
- }
- return ref Unsafe.NullRef<TValue>();
- }
- public ref TValue GetValueRefOrAddDefault(Key key, out bool exists)
- {
- if (_dictionary != null)
- {
- return ref _dictionary.GetValueRefOrAddDefault(key, out exists);
- }
- if (_list != null)
- {
- return ref _list.GetValueRefOrAddDefault(key, out exists);
- }
- var head = new ListDictionary<TValue>.DictionaryNode
- {
- Key = key,
- };
- _list = new ListDictionary<TValue>(head, _checkExistingKeys);
- exists = false;
- return ref head.Value;
- }
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void SetOrUpdateValue<TState>(Key key, Func<TValue, TState, TValue> updater, TState state)
- {
- ref var currentValue = ref GetValueRefOrAddDefault(key, out _);
- currentValue = updater(currentValue, state);
- }
- private bool SwitchToDictionary(Key key, TValue value, bool tryAdd, int capacity = InitialDictionarySize)
- {
- SwitchToDictionary(capacity);
- if (tryAdd)
- {
- return _dictionary.TryAdd(key, value);
- }
- _dictionary[key] = value;
- return true;
- }
- private ref TValue SwitchToDictionary(Key key, int capacity = InitialDictionarySize)
- {
- SwitchToDictionary(capacity);
- return ref _dictionary[key];
- }
- private void SwitchToDictionary(int capacity = InitialDictionarySize)
- {
- var dictionary = new StringDictionarySlim<TValue>(capacity);
- if (_list is not null)
- {
- foreach (var pair in _list)
- {
- dictionary[pair.Key] = pair.Value;
- }
- }
- _dictionary = dictionary;
- _list = null;
- }
- public int Count
- {
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- get => _dictionary?.Count ?? _list?.Count ?? 0;
- }
- public void EnsureCapacity(int capacity)
- {
- if (_dictionary is not null)
- {
- // not implemented yet
- return;
- }
- if (capacity >= CutoverPoint)
- {
- SwitchToDictionary(capacity);
- }
- }
- public bool TryAdd(Key key, TValue value)
- {
- if (_dictionary != null)
- {
- return _dictionary.TryAdd(key, value);
- }
- _list ??= new ListDictionary<TValue>(key, value, _checkExistingKeys);
- if (_list.Count + 1 >= CutoverPoint)
- {
- return SwitchToDictionary(key, value, tryAdd: true);
- }
- return _list.Add(key, value, tryAdd: true);
- }
- /// <summary>
- /// Adds a new item and expects key to not exist.
- /// </summary>
- public void AddDangerous(Key key, TValue value)
- {
- if (_dictionary != null)
- {
- _dictionary.AddDangerous(key, value);
- }
- else
- {
- if (_list == null)
- {
- _list = new ListDictionary<TValue>(key, value, _checkExistingKeys);
- }
- else
- {
- if (_list.Count + 1 >= CutoverPoint)
- {
- SwitchToDictionary(key) = value;
- }
- else
- {
- _list.AddDangerous(key, value);
- }
- }
- }
- }
- public void Clear()
- {
- _dictionary?.Clear();
- _list?.Clear();
- }
- public bool ContainsKey(Key key)
- {
- ref var valueRefOrNullRef = ref GetValueRefOrNullRef(key);
- return !Unsafe.IsNullRef(ref valueRefOrNullRef);
- }
- IEnumerator<KeyValuePair<Key, TValue>> IEnumerable<KeyValuePair<Key, TValue>>.GetEnumerator()
- {
- if (_dictionary != null)
- {
- return _dictionary.GetEnumerator();
- }
- if (_list != null)
- {
- return _list.GetEnumerator();
- }
- return System.Linq.Enumerable.Empty<KeyValuePair<Key, TValue>>().GetEnumerator();
- }
- IEnumerator IEnumerable.GetEnumerator()
- {
- if (_dictionary != null)
- {
- return _dictionary.GetEnumerator();
- }
- if (_list != null)
- {
- return _list.GetEnumerator();
- }
- return System.Linq.Enumerable.Empty<KeyValuePair<Key, TValue>>().GetEnumerator();
- }
- public bool Remove(Key key)
- {
- if (_dictionary != null)
- {
- return _dictionary.Remove(key);
- }
- return _list != null && _list.Remove(key);
- }
- /// <summary>
- /// Optimization when no need to check for existing items.
- /// </summary>
- public bool CheckExistingKeys
- {
- set
- {
- if (_list != null)
- {
- _list.CheckExistingKeys = value;
- }
- }
- }
- }
|