//----------------------------------------------------------------------- // // Copyright © 2012 Nils Hammar. All rights reserved. // //----------------------------------------------------------------------- /* * Software to access vehicle information via the OBD-II connector. * * Copyright © 2012 Nils Hammar * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program 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 General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Alternative licensing is possible, see the licensing document. * * The above text may not be removed or modified. */ namespace SharedObjects.Misc { using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Text; /// /// Class that allows for long composite keys to data in a dictionary, /// which allows for multi-dimensional keys using recursion. /// /// Be aware that this can cause large allocations of memory. /// /// /// Type of key array. /// Type of value. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1711:IdentifiersShouldNotHaveIncorrectSuffix", Justification = "Correct for this implementation.")] public class StackedDictionary { /// /// Root hashtable implementing the stacked dictionary. /// private Hashtable hashtable = new Hashtable(); /// /// Initializes a new instance of the class. /// public StackedDictionary() { } /// /// Clear the dictionary from all data. /// /// Notice that this relies on garbage collection to free memory. /// /// [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2001:AvoidCallingProblematicMethods", MessageId = "System.GC.Collect", Justification = "Reviewed, Intentional.")] public void Clear() { this.hashtable.Clear(); System.GC.Collect(); } /// /// Get a list of all keys present in the dictionary. /// /// List with arrays of key values. public IList GetKeys() { IList keyList = new List(); IList l1 = new List(); GetKeys(this.hashtable, keyList, l1); return keyList; } /// /// Add one data item with the given key. /// /// Array of key values. /// Value to add. public void Add(TK[] keys, TV value) { if (keys != null) { int levels = keys.Length; Add(this.hashtable, keys, 0, levels, value); } } /// /// Get value for the given key. /// /// Array of key values. /// The value for the given key. public TV Get(TK[] keys) { TV data = default(TV); if (keys != null) { int levels = keys.Length; data = Get(this.hashtable, keys, 0, levels); } return data; } /// /// Replace value on item with the given key. /// /// Array of key values. /// Value to set. public void Set(TK[] keys, TV value) { if (keys != null) { int levels = keys.Length; Set(this.hashtable, keys, 0, levels, value); } } /// /// Recursively populate the list of key arrays. /// /// Hashtable with data. /// Kay list to populate. /// Current key base. private static void GetKeys(Hashtable hashtable, IList keyList, IList l0) { foreach (object keyObj in hashtable.Keys) { TK key = (TK)keyObj; IList l1 = new List(l0); l1.Add(key); if (hashtable[key] is Hashtable) { GetKeys((Hashtable)hashtable[key], keyList, l1); } else { keyList.Add(l1.ToArray()); } } } /// /// Recursively get the value for the given key. /// /// Hashtable with data. /// Array of key values. /// Current recursion level. /// Max recursion level. /// Stored value. private static TV Get(Hashtable hashtable, TK[] keys, int level, int levels) { TV data = default(TV); if (hashtable.ContainsKey(keys[level])) { if (level == levels - 1) { if (hashtable[keys[level]] is TV) { data = (TV)hashtable[keys[level]]; } } else { data = Get((Hashtable)hashtable[keys[level]], keys, level + 1, levels); } } return data; } /// /// Recursively update the value indicated by the given key. /// /// Hashtable with data. /// Array of key values. /// Current recursion level. /// Max recursion level. /// Value to set. private static void Set(Hashtable hashtable, TK[] keys, int level, int levels, TV value) { if (hashtable.ContainsKey(keys[level])) { if (level == levels - 1) { if (hashtable[keys[level]] is TV) { hashtable[keys[level]] = value; } } else { Set((Hashtable)hashtable[keys[level]], keys, level + 1, levels, value); } } } /// /// Recursively add a new value to the dictionary. /// /// Hashtable with data. /// Array of key values. /// Current recursion level. /// Max recursion level. /// Value to set. private static void Add(Hashtable hashtable, TK[] keys, int level, int levels, TV value) { if (level == levels - 1) { hashtable[keys[level]] = value; } else { if (!hashtable.ContainsKey(keys[level])) { hashtable[keys[level]] = new Hashtable(); } Add((Hashtable)hashtable[keys[level]], keys, level + 1, levels, value); } } } }