diff --git a/CHANGELOG.md b/CHANGELOG.md index d618bea..7cf80f6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ### Added - Added ZIP features for examining the contents of an archive - Added FileNameEqualityComparer + - Added BiDictionary for one-to-one maps ## [3.5.1] - 2018-06-04 ### Changed diff --git a/ICD.Common.Utils/Collections/BiDictionary.cs b/ICD.Common.Utils/Collections/BiDictionary.cs new file mode 100644 index 0000000..b9770b6 --- /dev/null +++ b/ICD.Common.Utils/Collections/BiDictionary.cs @@ -0,0 +1,184 @@ +using System; +using System.Collections; +using System.Collections.Generic; + +namespace ICD.Common.Utils.Collections +{ + /// + /// Provides a 1-to-1 map of keys to values with O(1) Value->Key lookup time. + /// + /// + /// + public sealed class BiDictionary : IDictionary + { + private readonly Dictionary m_KeyToValue; + private readonly Dictionary m_ValueToKey; + + #region Properties + + public int Count { get { return m_KeyToValue.Count; } } + + public bool IsReadOnly { get { return false; } } + + public ICollection Keys { get { return m_KeyToValue.Keys; } } + + public ICollection Values { get { return m_ValueToKey.Keys; } } + + #endregion + + /// + /// Constructor. + /// + public BiDictionary() + { + m_KeyToValue = new Dictionary(); + m_ValueToKey = new Dictionary(); + } + + #region Methods + + public void Clear() + { + m_KeyToValue.Clear(); + m_ValueToKey.Clear(); + } + + public bool ContainsKey(TKey key) + { + return m_KeyToValue.ContainsKey(key); + } + + public bool ContainsValue(TValue value) + { + return m_ValueToKey.ContainsKey(value); + } + + public void Add(TKey key, TValue value) + { +// ReSharper disable once CompareNonConstrainedGenericWithNull + if (key == null) + throw new ArgumentNullException("key"); + +// ReSharper disable once CompareNonConstrainedGenericWithNull + if (value == null) + throw new ArgumentNullException("value"); + + if (m_KeyToValue.ContainsKey(key)) + throw new ArgumentException("Key is already present in the dictionary", "key"); + + if (m_ValueToKey.ContainsKey(value)) + throw new ArgumentException("Value is already present in the collection", "value"); + + m_KeyToValue.Add(key, value); + m_ValueToKey.Add(value, key); + } + + public void Set(TKey key, TValue value) + { +// ReSharper disable once CompareNonConstrainedGenericWithNull + if (key == null) + throw new ArgumentNullException("key"); + +// ReSharper disable once CompareNonConstrainedGenericWithNull + if (value == null) + throw new ArgumentNullException("value"); + + m_KeyToValue[key] = value; + m_ValueToKey[value] = key; + } + + public TKey GetKey(TValue value) + { + return m_ValueToKey[value]; + } + + public TValue GetValue(TKey key) + { + return m_KeyToValue[key]; + } + + public bool RemoveKey(TKey key) + { + if (!ContainsKey(key)) + return false; + + TValue value = m_KeyToValue[key]; + + m_KeyToValue.Remove(key); + m_ValueToKey.Remove(value); + + return true; + } + + public bool RemoveValue(TValue value) + { + if (!ContainsValue(value)) + return false; + + TKey key = m_ValueToKey[value]; + + return RemoveKey(key); + } + + public bool TryGetValue(TKey key, out TValue value) + { + return m_KeyToValue.TryGetValue(key, out value); + } + + public bool TryGetKey(TValue value, out TKey key) + { + return m_ValueToKey.TryGetValue(value, out key); + } + + #endregion + + #region IDictionary + + TValue IDictionary.this[TKey key] { get { return GetValue(key); } set { Set(key, value); } } + + bool IDictionary.Remove(TKey key) + { + return RemoveKey(key); + } + + #endregion + + #region ICollection + + void ICollection>.Add(KeyValuePair item) + { + Add(item.Key, item.Value); + } + + bool ICollection>.Contains(KeyValuePair item) + { + return (m_KeyToValue as IDictionary).Contains(item); + } + + bool ICollection>.Remove(KeyValuePair item) + { + return RemoveKey(item.Key); + } + + void ICollection>.CopyTo(KeyValuePair[] array, int arrayIndex) + { + (m_KeyToValue as IDictionary).CopyTo(array, arrayIndex); + } + + #endregion + + #region IEnumerable + + public IEnumerator> GetEnumerator() + { + return m_KeyToValue.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + #endregion + } +} diff --git a/ICD.Common.Utils/ICD.Common.Utils_SimplSharp.csproj b/ICD.Common.Utils/ICD.Common.Utils_SimplSharp.csproj index 9d0bd60..ed696f1 100644 --- a/ICD.Common.Utils/ICD.Common.Utils_SimplSharp.csproj +++ b/ICD.Common.Utils/ICD.Common.Utils_SimplSharp.csproj @@ -74,6 +74,7 @@ +