TinyDictionary.cs

Posted on July 30, 2020July 31, 2020Tags , , ,   Leave a comment on TinyDictionary.cs

A Small Dictionary Class

using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
[DebuggerDisplay("Count = {Count}")]
[Serializable]
public class TinyDictionary<TKey, TValue> : IEnumerable<KeyValuePair<TKey, TValue>>
{
    public TinySet<TKey> Keys;
    public int           Resizes;
    public TValue[]      Values;
    public TinyDictionary() : this(101, EqualityComparer<TKey>.Default)
    {
    }
    public TinyDictionary(int size) : this(size, EqualityComparer<TKey>.Default)
    {
    }
    public TinyDictionary(int size, IEqualityComparer<TKey> comparer)
    {
        if (comparer == null)
            comparer = EqualityComparer<TKey>.Default;
        Keys          = new TinySet<TKey>(size);
        Values        = new TValue[size];
        Keys.Comparer = comparer;
    }
    public TinyDictionary(IEnumerable<KeyValuePair<TKey, TValue>> collection, IEqualityComparer<TKey> comparer = null)
    {
        if (comparer == null)
            comparer = EqualityComparer<TKey>.Default;
        Keys.Comparer = comparer;
        foreach (var kp in collection)
            Add(kp.Key, kp.Value);
    }
    public int Count => Keys.Count;
    public TValue this[TKey key]
    {
        get
        {
            var pos = Keys.FindEntry(key);
            return pos == -1 ? default : Values[pos];
        }
        set => Add(key, value);
    }
    IEnumerator<KeyValuePair<TKey, TValue>> IEnumerable<KeyValuePair<TKey, TValue>>.GetEnumerator()
    {
        return new Enumerator(this);
    }
    IEnumerator IEnumerable.GetEnumerator()
    {
        return new Enumerator(this);
    }
    public Enumerator GetEnumerator()
    {
        return new Enumerator(this);
    }
    public bool Add(TKey key, TValue value)
    {
        if (!Keys.Insert(key, true))
        {
            if (Values.Length != Keys.Slots.Length)
            {
                var nValues = new TValue[Keys.Slots.Length];
                Array.Copy(Values, nValues, Values.Length);
                Values = nValues;
                Resizes++;
            }
            Values[Keys.Position] = value;
            return false;
        }
        Values[Keys.Position] = value;
        return true;
    }
    public void Remove(TKey key)
    {
        var pos = Keys.FindEntry(key);
        if (pos != -1)
        {
            Values[pos] = default;
            Keys.Remove(key);
        }
    }
    public bool ContainsKey(TKey key)
    {
        return Keys.FindEntry(key) != -1;
    }
    public int FindKeyIndex(TKey key)
    {
        return Keys.FindEntry(key);
    }
    [Serializable]
    public struct Enumerator : IEnumerator<KeyValuePair<TKey, TValue>>, IDictionaryEnumerator
    {
        private readonly TinyDictionary<TKey, TValue> dictionary;
        private          int                          index;
        internal Enumerator(TinyDictionary<TKey, TValue> dictionary)
        {
            this.dictionary = dictionary;
            index           = 0;
            Current         = new KeyValuePair<TKey, TValue>();
        }
        public bool MoveNext()
        {
            if ((uint) index < (uint) dictionary.Keys.Count)
            {
                Current = new KeyValuePair<TKey, TValue>(dictionary.Keys.Slots[index].Value, dictionary.Values[index]);
                index++;
                return true;
            }
            index   = dictionary.Keys.Count + 1;
            Current = new KeyValuePair<TKey, TValue>();
            return false;
        }
        public KeyValuePair<TKey, TValue> Current
        {
            get;
            private set;
        }
        public void Dispose()
        {
        }
        object IEnumerator.Current
        {
            get
            {
                if (index == 0 || index == dictionary.Keys.Count + 1)
                    throw new Exception("Invalid Index.");
                return new KeyValuePair<TKey, TValue>(Current.Key, Current.Value);
            }
        }
        void IEnumerator.Reset()
        {
            index   = 0;
            Current = new KeyValuePair<TKey, TValue>();
        }
        DictionaryEntry IDictionaryEnumerator.Entry
        {
            get
            {
                if (index == 0 || index == dictionary.Keys.Count + 1)
                    throw new Exception("Invalid Index.");
                return new DictionaryEntry(Current.Key, Current.Value);
            }
        }
        object IDictionaryEnumerator.Key
        {
            get
            {
                if (index == 0 || index == dictionary.Keys.Count + 1)
                    throw new Exception("Invalid Index.");
                return Current.Key;
            }
        }
        object IDictionaryEnumerator.Value
        {
            get
            {
                if (index == 0 || index == dictionary.Keys.Count + 1)
                    throw new Exception("Invalid Index.");
                return Current.Value;
            }
        }
    }
}