//-----------------------------------------------------------------------
//
// 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);
}
}
}
}