using System; using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; using System.Linq; // ReSharper disable once CheckNamespace namespace GameDevWare.Serialization { [Serializable, DebuggerDisplay("IndexedDictionary, Count: {Count}")] public class IndexedDictionary : IDictionary, IDictionary { [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)] private readonly Dictionary dictionary; [DebuggerBrowsable(DebuggerBrowsableState.Never)] private readonly List keys; [DebuggerBrowsable(DebuggerBrowsableState.Never), NonSerialized] private ReadOnlyCollection keysReadOnly; /// public int Count { get { return this.dictionary.Count; } } /// public ValueT this[KeyT key] { get { return this.dictionary[key]; } set { if (this.dictionary.ContainsKey(key) == false) this.keys.Add(key); this.dictionary[key] = value; } } /// [DebuggerBrowsable(DebuggerBrowsableState.Never)] object IDictionary.this[object key] { get { var value = default(ValueT); return this.TryGetValue((KeyT)key, out value) ? value : default(object); } set { this[(KeyT)key] = (ValueT)value; } } /// [DebuggerBrowsable(DebuggerBrowsableState.Never)] object ICollection.SyncRoot { get { return this.dictionary; } } /// [DebuggerBrowsable(DebuggerBrowsableState.Never)] bool ICollection.IsSynchronized { get { return false; } } /// [DebuggerBrowsable(DebuggerBrowsableState.Never)] public ReadOnlyCollection Keys { get { return this.keysReadOnly ?? (this.keysReadOnly = new ReadOnlyCollection(this.keys)); } } /// [DebuggerBrowsable(DebuggerBrowsableState.Never)] public ReadOnlyCollection Values { get { return this.GetValues(); } } /// [DebuggerBrowsable(DebuggerBrowsableState.Never)] ICollection IDictionary.Values { get { return this.GetValues(); } } /// [DebuggerBrowsable(DebuggerBrowsableState.Never)] ICollection IDictionary.Keys { get { return this.keys; } } /// [DebuggerBrowsable(DebuggerBrowsableState.Never)] bool IDictionary.IsReadOnly { get { return false; } } /// [DebuggerBrowsable(DebuggerBrowsableState.Never)] bool IDictionary.IsFixedSize { get { return false; } } /// [DebuggerBrowsable(DebuggerBrowsableState.Never)] bool ICollection>.IsReadOnly { get { return false; } } /// [DebuggerBrowsable(DebuggerBrowsableState.Never)] ICollection IDictionary.Keys { get { return this.keysReadOnly; } } /// [DebuggerBrowsable(DebuggerBrowsableState.Never)] ICollection IDictionary.Values { get { return this.GetValues(); } } public IndexedDictionary() { this.dictionary = new Dictionary(); this.keys = new List(); this.keysReadOnly = new ReadOnlyCollection(this.keys); } public IndexedDictionary(int count) { if (count < 0) throw new ArgumentOutOfRangeException("count"); if (count == 0) count = 30; this.dictionary = new Dictionary(count); this.keys = new List(count); this.keysReadOnly = new ReadOnlyCollection(this.keys); } public IndexedDictionary(IDictionary dictionary) { if (dictionary == null) throw new ArgumentNullException("dictionary"); this.dictionary = new Dictionary(dictionary); this.keys = new List(dictionary.Keys); this.keysReadOnly = new ReadOnlyCollection(this.keys); } public IndexedDictionary(IEnumerable> pairs) { if (pairs == null) throw new ArgumentNullException("pairs"); this.dictionary = new Dictionary(); this.keys = new List(); this.keysReadOnly = new ReadOnlyCollection(this.keys); foreach (var pair in pairs) this.Add(pair.Key, pair.Value); } public IndexedDictionary(IDictionary dictionary, ICollection keys) { if (dictionary == null) throw new ArgumentNullException("dictionary"); if (keys == null) throw new ArgumentNullException("keys"); this.dictionary = new Dictionary(dictionary); this.keys = new List(keys); this.keysReadOnly = new ReadOnlyCollection(this.keys); } /// public void Add(KeyT key, ValueT value) { this.dictionary.Add(key, value); this.keys.Add(key); } /// public void Add(IndexedDictionary other) { if (other == null) throw new ArgumentNullException("other"); if (this.Count == 0) { this.keys.AddRange(other.keys); foreach (var kv in other.dictionary) this.dictionary.Add(kv.Key, kv.Value); } else { foreach (var kv in other.dictionary) { this.dictionary.Add(kv.Key, kv.Value); this.keys.Add(kv.Key); } } } /// public void Insert(int index, KeyT key, ValueT value) { // Dictionary operation first, so exception thrown if key already exists. this.dictionary.Add(key, value); this.keys.Insert(index, key); } /// public bool ContainsKey(KeyT key) { return this.dictionary.ContainsKey(key); } /// public bool ContainsKey(KeyT key, IEqualityComparer keyComparer) { foreach (var k in this.keys) if (keyComparer.Equals(k, key)) return true; return false; } /// public bool ContainsValue(ValueT value) { foreach (var kv in this.dictionary) if (Equals(value, kv.Value)) return true; return false; } /// public bool ContainsValue(ValueT value, IEqualityComparer comparer) { if (comparer == null) throw new ArgumentNullException("comparer"); foreach (var kv in this.dictionary) if (comparer.Equals(value, kv.Value)) return true; return false; } /// public bool Remove(KeyT key) { var wasInDictionary = this.dictionary.Remove(key); this.keys.Remove(key); return wasInDictionary; } /// public bool TryGetValue(KeyT key, out ValueT value) { return this.dictionary.TryGetValue(key, out value); } /// public int IndexOf(KeyT key) { return this.keys.IndexOf(key); } /// public void RemoveAt(int index) { if (index >= this.Count || index < 0) throw new ArgumentOutOfRangeException("index"); var key = this.keys[index]; this.dictionary.Remove(key); this.keys.RemoveAt(index); } public void SortKeys(IComparer comparer) { if (comparer == null) throw new ArgumentNullException("comparer"); this.keys.Sort(comparer); } /// public void Clear() { this.dictionary.Clear(); this.keys.Clear(); } private ReadOnlyCollection GetValues() { var values = new ValueT[this.Count]; var index = 0; foreach (var key in this.keys) values[index++] = this.dictionary[key]; return new ReadOnlyCollection(values); } /// bool IDictionary.Contains(object key) { return this.ContainsKey((KeyT)key); } /// void IDictionary.Add(object key, object value) { this.Add((KeyT)key, (ValueT)value); } /// IDictionaryEnumerator IDictionary.GetEnumerator() { return this.GetEnumerator(); } /// void IDictionary.Remove(object key) { this.Remove((KeyT)key); } /// void ICollection.CopyTo(Array array, int index) { if (array == null) throw new ArgumentNullException("array"); if (index >= array.Length) throw new ArgumentOutOfRangeException("index"); if (index + this.Count > array.Length) throw new ArgumentOutOfRangeException("index"); var end = index + this.Count; for (var i = 0; i < end; i++) array.SetValue(new DictionaryEntry(this.keys[i], this.dictionary[this.keys[i]]), index + i); } /// void ICollection>.Add(KeyValuePair item) { this.Add(item.Key, item.Value); } /// bool ICollection>.Contains(KeyValuePair item) { var value = default(ValueT); return this.dictionary.TryGetValue(item.Key, out value) && Equals(value, item.Value); } /// void ICollection>.CopyTo(KeyValuePair[] array, int arrayIndex) { foreach (var pair in this) { array[arrayIndex] = pair; arrayIndex++; } } /// bool ICollection>.Remove(KeyValuePair item) { if (!this.Contains(item)) return false; return this.Remove(item.Key); } /// IEnumerator> IEnumerable>.GetEnumerator() { return this.GetEnumerator(); } /// IEnumerator IEnumerable.GetEnumerator() { return this.GetEnumerator(); } public Enumerator GetEnumerator() { return new Enumerator(this); } /// public override string ToString() { return "Count: " + this.Count.ToString(); } public struct Enumerator : IEnumerator>, IDictionaryEnumerator { private List.Enumerator innerEnumerator; private readonly IndexedDictionary owner; private KeyValuePair current; public Enumerator(IndexedDictionary owner) { this.owner = owner; this.innerEnumerator = owner.keys.GetEnumerator(); this.current = new KeyValuePair(); } /// public object Key { get { return this.current.Key; } } /// public object Value { get { return this.current.Value; } } /// public DictionaryEntry Entry { get { return new DictionaryEntry(this.current.Key, this.current.Value); } } /// public KeyValuePair Current { get { return this.current; } } /// object IEnumerator.Current { get { return this.Entry; } } /// public bool MoveNext() { if (!this.innerEnumerator.MoveNext()) return false; var key = this.innerEnumerator.Current; this.current = new KeyValuePair(key, this.owner.dictionary[key]); return true; } /// public void Reset() { this.innerEnumerator = this.owner.keys.GetEnumerator(); } /// public void Dispose() { this.innerEnumerator.Dispose(); } } } }