diff --git a/CHANGELOG.md b/CHANGELOG.md index f744978..b6061b6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,8 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). ## [Unreleased] +### Added + - Adding IcdOrderedDictionary collection ## [3.2.0] - 2018-05-09 ### Added diff --git a/ICD.Common.Utils.Tests/Collections/IcdOrderedDictionaryTest.cs b/ICD.Common.Utils.Tests/Collections/IcdOrderedDictionaryTest.cs new file mode 100644 index 0000000..a32b648 --- /dev/null +++ b/ICD.Common.Utils.Tests/Collections/IcdOrderedDictionaryTest.cs @@ -0,0 +1,126 @@ +using System.Linq; +using ICD.Common.Utils.Collections; +using NUnit.Framework; + +namespace ICD.Common.Utils.Tests.Collections +{ + [TestFixture] + public sealed class IcdOrderedDictionaryTest + { + #region Properties + + [Test] + public void CountTest() + { + IcdOrderedDictionary dict = new IcdOrderedDictionary + { + {0, 0}, + {1, 1}, + {2, 2} + }; + + Assert.AreEqual(3, dict.Count); + } + + [Test] + public void IsReadOnlyTest() + { + IcdOrderedDictionary dict = new IcdOrderedDictionary(); + + Assert.IsFalse(dict.IsReadOnly); + } + + [Test] + public void KeysTest() + { + IcdOrderedDictionary dict = new IcdOrderedDictionary + { + {0, 0}, + {1, 1}, + {-1, -1} + }; + + int[] keys = dict.Keys.ToArray(); + + Assert.AreEqual(3, keys.Length); + Assert.AreEqual(-1, keys[0]); + Assert.AreEqual(0, keys[1]); + Assert.AreEqual(1, keys[2]); + } + + [Test] + public void ValuesTest() + { + IcdOrderedDictionary dict = new IcdOrderedDictionary + { + {0, 0}, + {1, 1}, + {-1, -1} + }; + + int[] keys = dict.Values.ToArray(); + + Assert.AreEqual(3, keys.Length); + Assert.AreEqual(-1, keys[0]); + Assert.AreEqual(0, keys[1]); + Assert.AreEqual(1, keys[2]); + } + + [Test] + public void IndexerTest() + { + IcdOrderedDictionary dict = new IcdOrderedDictionary + { + {0, 0}, + {1, 1}, + {-1, -1} + }; + + Assert.AreEqual(0, dict[0]); + Assert.AreEqual(1, dict[1]); + Assert.AreEqual(-1, dict[-1]); + } + + #endregion + + #region Methods + + [Test] + public void GetEnumeratorTest() + { + Assert.Inconclusive(); + } + + [Test] + public void AddTest() + { + Assert.Inconclusive(); + } + + [Test] + public void ClearTest() + { + Assert.Inconclusive(); + } + + [Test] + public void ContainsKeyTest() + { + Assert.Inconclusive(); + } + + [Test] + public void RemoveTest() + { + Assert.Inconclusive(); + } + + [Test] + public void TryGetValueTest() + { + Assert.Inconclusive(); + } + + #endregion + } +} diff --git a/ICD.Common.Utils/Collections/IcdOrderedDictionary.cs b/ICD.Common.Utils/Collections/IcdOrderedDictionary.cs new file mode 100644 index 0000000..a688522 --- /dev/null +++ b/ICD.Common.Utils/Collections/IcdOrderedDictionary.cs @@ -0,0 +1,159 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using ICD.Common.Utils.Extensions; + +namespace ICD.Common.Utils.Collections +{ + public sealed class IcdOrderedDictionary : IDictionary + { + private readonly List m_OrderedKeys; + private readonly Dictionary m_Dictionary; + private readonly IComparer m_Comparer; + + #region Properties + + public int Count { get { return m_Dictionary.Count; } } + + public bool IsReadOnly { get { return false; } } + + public ICollection Keys { get { return m_OrderedKeys; } } + + public ICollection Values + { + get + { + return m_OrderedKeys.Select(k => m_Dictionary[k]) + .ToArray(Count); + } + } + + public TValue this[TKey key] + { + get { return m_Dictionary[key]; } + set + { +// ReSharper disable once CompareNonConstrainedGenericWithNull + if (key == null) + throw new ArgumentNullException("key"); + + if (!ContainsKey(key)) + m_OrderedKeys.AddSorted(key, m_Comparer); + + m_Dictionary[key] = value; + } + } + + #endregion + + /// + /// Constructor. + /// + public IcdOrderedDictionary() + : this(Comparer.Default) + { + } + + /// + /// Constructor. + /// + /// + public IcdOrderedDictionary(IComparer comparer) + { + if (comparer == null) + throw new ArgumentNullException("comparer"); + + m_Comparer = comparer; + m_OrderedKeys = new List(); + m_Dictionary = new Dictionary(); + } + + #region Methods + + public IEnumerator> GetEnumerator() + { + return m_OrderedKeys.Select(k => new KeyValuePair(k, m_Dictionary[k])) + .GetEnumerator(); + } + + public void Add(TKey key, TValue value) + { +// ReSharper disable once CompareNonConstrainedGenericWithNull + if (key == null) + throw new ArgumentNullException("key"); + + if (m_Dictionary.ContainsKey(key)) + throw new ArgumentException("An item with the same key has already been added.", "key"); + + this[key] = value; + } + + public void Clear() + { + m_OrderedKeys.Clear(); + m_Dictionary.Clear(); + } + + public bool ContainsKey(TKey key) + { + return m_Dictionary.ContainsKey(key); + } + + public bool Remove(TKey key) + { +// ReSharper disable once CompareNonConstrainedGenericWithNull + if (key == null) + throw new ArgumentNullException("key"); + + if (!m_Dictionary.Remove(key)) + return false; + + m_OrderedKeys.Remove(key); + + return true; + } + + public bool TryGetValue(TKey key, out TValue value) + { + return m_Dictionary.TryGetValue(key, out value); + } + + #endregion + + #region Private Methods + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + void ICollection>.Add(KeyValuePair item) + { + Add(item.Key, item.Value); + } + + bool ICollection>.Contains(KeyValuePair item) + { + TValue value; + return TryGetValue(item.Key, out value) && + EqualityComparer.Default.Equals(value, item.Value); + } + + void ICollection>.CopyTo(KeyValuePair[] array, int index) + { + foreach (KeyValuePair kvp in this) + { + array.SetValue(kvp, index); + index++; + } + } + + bool ICollection>.Remove(KeyValuePair item) + { + return (this as ICollection>).Contains(item) && Remove(item.Key); + } + + #endregion + } +} diff --git a/ICD.Common.Utils/ICD.Common.Utils_SimplSharp.csproj b/ICD.Common.Utils/ICD.Common.Utils_SimplSharp.csproj index ece69a3..3a062cd 100644 --- a/ICD.Common.Utils/ICD.Common.Utils_SimplSharp.csproj +++ b/ICD.Common.Utils/ICD.Common.Utils_SimplSharp.csproj @@ -74,6 +74,7 @@ +