// Accord Core Library // The Accord.NET Framework // http://accord-framework.net // // Copyright © César Souza, 2009-2017 // cesarsouza at gmail.com // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 2.1 of the License, or (at your option) any later version. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License along with this library; if not, write to the Free Software // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA // using System; using System.Collections; using System.Collections.Generic; using System.Runtime.Serialization; using System.Linq; using System.Reflection; using System.Runtime.InteropServices.WindowsRuntime; namespace CaeGlobals { /// /// Ordered dictionary. /// /// /// /// This class provides a ordered dictionary implementation for C#/.NET. Unlike the rest /// of the framework, this class is available under a MIT license, so please feel free to /// re-use its source code in your own projects. /// /// /// The types of the keys in the dictionary. /// The type of values in the dictionary. /// [Serializable] public class OrderedDictionary : IDictionary, ISerializable { // Variables private string _name; //ISerializable private List _list; //ISerializable private Dictionary _dictionary; //ISerializable // Constructors /// /// Initializes a new instance of the class. /// public OrderedDictionary(string name) { _name = name; _dictionary = new Dictionary(); _list = new List(); } /// /// Initializes a new instance of the class. /// /// /// The initial number of elements that the can contain. /// public OrderedDictionary(string name, int capacity) { _name = name; _dictionary = new Dictionary(capacity); _list = new List(capacity); } /// /// Initializes a new instance of the class. /// /// /// The IEqualityComparer implementation to use when comparing keys, or null to use /// the default EqualityComparer for the type of the key. /// public OrderedDictionary(string name, IEqualityComparer comparer) { _name = name; _dictionary = new Dictionary(comparer); _list = new List(); } /// /// Initializes a new instance of the class. /// /// /// The initial number of elements that the can contain. /// The IEqualityComparer implementation to use when comparing keys, or null to use /// the default EqualityComparer for the type of the key. /// public OrderedDictionary(string name, int capacity, IEqualityComparer comparer) { _name = name; _dictionary = new Dictionary(capacity, comparer); _list = new List(); } /// /// Initializes a new instance of the class. /// /// /// The System.Collections.Generic.IDictionary`2 whose elements are copied to the /// new . /// public OrderedDictionary(string name, IDictionary dictionary) { _name = name; _dictionary = new Dictionary(dictionary); _list = new List(_dictionary.Keys); } /// /// Initializes a new instance of the class. /// /// /// The System.Collections.Generic.IDictionary`2 whose elements are copied to the /// new . /// The IEqualityComparer implementation to use when comparing keys, or null to use /// the default EqualityComparer for the type of the key. /// public OrderedDictionary(string name, IDictionary dictionary, IEqualityComparer comparer) { _name = name; _dictionary = new Dictionary(dictionary, comparer); _list = new List(_dictionary.Keys); } public OrderedDictionary(OrderedDictionary dictionary) { _name = dictionary._name; _dictionary = new Dictionary(dictionary._dictionary); _list = new List(_dictionary.Keys); } //ISerializable public OrderedDictionary(SerializationInfo info, StreamingContext context) { int count = 0; foreach (SerializationEntry entry in info) { switch (entry.Name) { case "_name": _name = (string)entry.Value; count++; break; case "list": // Compatibility v1.3.4 case "_list": _list = (List)entry.Value; count++; break; case "dictionary": // Compatibility v1.3.4 case "_dictionary": _dictionary = (Dictionary)entry.Value; //_dictionary.OnDeserialization(null); count++; break; } // Compatibility v1.3.4 if (_name == null || _name == "") _name = "Ordered dictionary"; } } // Methods /// /// Gets the at the specified index. /// /// /// The index. /// public TKey GetKeyByIndex(int index) { return _list[index]; } /// /// Gets the at the specified index. /// /// /// The index. /// public TValue GetValueByIndex(int index) { return this[GetKeyByIndex(index)]; } /// /// Gets or sets the with the specified key. /// /// /// The key. /// public TValue this[TKey key] { get { TValue value; if (_dictionary.TryGetValue(key, out value)) return value; else throw new CaeException("The given key '" + key.ToString() + "' was not present in the dictionary."); } set { if (!_dictionary.ContainsKey(key)) _list.Add(key); _dictionary[key] = value; } } /// /// Gets an containing the keys of the . /// /// /// The keys. /// public ICollection Keys { get { return _list; } } public void SortKeysAs(ICollection keys) { foreach (var key in keys) { if (_list.IndexOf(key) < 0) throw new NotSupportedException(); } _list.Clear(); _list.AddRange(keys); } /// /// Gets an containing the values in the . /// /// public ICollection Values { get { return _list.Select(x => _dictionary[x]).ToList(); } } /// /// Gets the number of elements contained in the . /// /// public int Count { get { return _dictionary.Count; } } /// /// Gets a value indicating whether the is read-only. /// /// /// true if this instance is read only; otherwise, false. /// public bool IsReadOnly { get { return ((IDictionary)_dictionary).IsReadOnly; } } /// /// Adds an element with the provided key and value to the . /// /// /// The object to use as the key of the element to add. /// The object to use as the value of the element to add. /// public void Add(TKey key, TValue value) { if (_dictionary.ContainsKey(key))// || _list.Contains(key)) { string name = _name; if (name != null && name.Length > 0) name += " "; throw new Exception("The dictionary " + name + "already contains the key " + key.ToString() + "."); } // _dictionary.Add(key, value); _list.Add(key); } /// /// Adds an item to the . /// /// /// The object to add to the . /// public void Add(KeyValuePair item) { Add(item.Key, item.Value); } /// /// Inserts an element with the provided index and key and value to the . /// /// /// The zero-based index at which item should be inserted. /// The object to use as the key of the element to add. /// The object to use as the value of the element to add. /// public void Insert(int index, TKey key, TValue value) { if (index < 0 || index >= _list.Count) throw new IndexOutOfRangeException(); // if (_dictionary.ContainsKey(key)) // || _list.Contains(key)) { string name = _name; if (name != null && name.Length > 0) name += " "; throw new Exception("The dictionary " + name + "already contains the key " + key.ToString() + "."); } // _dictionary.Add(key, value); _list.Insert(index, key); } /// /// Adds another dictionary to the . /// /// /// The dictionary to add. /// public void AddRange(Dictionary dicToAdd) { foreach (var item in dicToAdd) Add(item.Key, item.Value); } /// /// Replace an element with the provided key and value to the . /// /// /// The object to use as the key of the element to remove. /// The object to use as the key of the element to add. /// The object to use as the value of the element to add. /// public bool Replace(TKey oldKey, TKey newKey, TValue value) { if (_dictionary.Remove(oldKey)) { _dictionary.Add(newKey, value); // int index = -1; if (_dictionary.Comparer != null) index = _list.FindIndex(s => _dictionary.Comparer.Equals(s, oldKey)); else index = _list.IndexOf(oldKey); // _list.RemoveAt(index); _list.Insert(index, newKey); return true; } // return false; } /// /// Removes all items from the . /// /// public void Clear() { _dictionary.Clear(); _list.Clear(); } /// /// Determines whether the contains a specific value. /// /// /// The object to locate in the . /// /// true if is found in the ; otherwise, false. /// public bool Contains(KeyValuePair item) { return ((IDictionary)_dictionary).Contains(item); } /// /// Determines whether the contains an element with the specified key. /// /// /// The key to locate in the . /// /// true if the contains an element with the key; otherwise, false. /// public bool ContainsKey(TKey key) { return _dictionary.ContainsKey(key); } /// /// Copies the elements of the to an , starting at a particular index. /// /// /// The one-dimensional that is the destination of the elements copied from . The must have zero-based indexing. /// The zero-based index in at which copying begins. /// public void CopyTo(KeyValuePair[] array, int arrayIndex) { foreach (KeyValuePair pair in this) array[arrayIndex++] = pair; } /// /// Returns an enumerator that iterates through the collection. /// /// /// An enumerator that can be used to iterate through the collection. /// public IEnumerator> GetEnumerator() { foreach (TKey key in _list) yield return new KeyValuePair(key, _dictionary[key]); } /// /// Removes the element with the specified key from the . /// /// /// The key of the element to remove. /// /// true if the element is successfully removed; otherwise, false. This method also returns false if was not found in the original . /// public bool Remove(TKey key) { if (_dictionary.Remove(key)) { _list.Remove(key); return true; } return false; } public bool TryRemove(TKey key, out TValue value) { if (_dictionary.TryGetValue(key, out value)) { _dictionary.Remove(key); _list.Remove(key); return true; } // return false; } /// /// Removes the first occurrence of a specific object from the . /// /// /// The object to remove from the . /// /// true if was successfully removed from the ; otherwise, false. This method also returns false if is not found in the original . /// public bool Remove(KeyValuePair item) { if (((IDictionary)_dictionary).Remove(item)) { _list.Remove(item.Key); return true; } return false; } /// /// Gets the value associated with the specified key. /// /// /// The key whose value to get. /// When this method returns, the value associated with the specified key, if the key is found; otherwise, the default value for the type of the parameter. This parameter is passed uninitialized. /// /// true if the object that implements contains an element with the specified key; otherwise, false. /// public bool TryGetValue(TKey key, out TValue value) { value = default(TValue); if (key == null) return false; else return ((IDictionary)_dictionary).TryGetValue(key, out value); } /// /// Returns an enumerator that iterates through a collection. /// /// /// An object that can be used to iterate through the collection. /// IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } // public OrderedDictionary DeepCopy() { return new OrderedDictionary(this); } // ISerialization public void OnDeserialization(object sender) { _dictionary.OnDeserialization(sender); } public void GetObjectData(SerializationInfo info, StreamingContext context) { // Using typeof() works also for null fields info.AddValue("_name", _name, typeof(string)); info.AddValue("_list", _list, typeof(List)); info.AddValue("_dictionary", _dictionary, typeof(Dictionary)); } } }