//----------------------------------------------------------------------- //----------------------------------------------------------------------- // file="BidirectionalDictionary.cs" // Project: StgSharp // AuthorGroup: Nitload Space // Copyright (c) Nitload Space. All rights reserved. // // Permission is hereby granted, free of charge, to any person // obtaining a copy of this software and associated documentation // files (the “Software”), to deal in the Software without restriction, // including without limitation the rights to use, copy, modify, merge, // publish, distribute, sublicense, and/or sell copies of the Software, // and to permit persons to whom the Software is furnished to do so, // subject to the following conditions: // // The above copyright notice and // this permission notice shall be included in all copies // or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED “AS IS”, // WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, // ARISING FROM, OUT OF OR IN CONNECTION WITH // THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // //----------------------------------------------------------------------- //----------------------------------------------------------------------- using System; using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics.CodeAnalysis; using System.Linq; namespace StgSharp.Collections { public sealed class BidirectionalDictionary : IBidirectionalDictionary { private readonly Dictionary _forward; private readonly Dictionary _reverse; public BidirectionalDictionary() { _forward = new Dictionary(); _reverse = new Dictionary(); } public TFirst this[TSecond key] { get { if (_reverse.TryGetValue(key,out TFirst value)) { return value; } throw new ArgumentException($"Cannot find key {key!.ToString()} in dictionary."); } set { if (_reverse.TryGetValue(key,out TFirst origin)) { _reverse[key] = value; _forward.Remove(origin); } else { _reverse.Add(key, value); } _forward.Add(value, key); } } public TSecond this[TFirst key] { get { if (_forward.TryGetValue(key, out TSecond value)) { return value; } throw new ArgumentException($"Cannot find key {key!.ToString()} in dictionary."); } set { if (_forward.TryGetValue(key, out TSecond origin)) { _forward[key] = value; _reverse.Remove(origin); } else { _forward.Add(key, value); } _reverse.Add(value, key); } } public bool IsReadOnly => false; public ICollection FirstIndex => _forward.Keys; public ICollection SecondIndex => _reverse.Keys; public int Count => _forward.Count; public IReadOnlyDictionary Forward => new ReadOnlyDictionary(_forward); public IReadOnlyDictionary Reverse => new ReadOnlyDictionary(_reverse); public void Add( KeyValuePair item ) { if (_forward.ContainsKey(item.Key) || _reverse.ContainsKey(item.Value)) { throw new ArgumentException("Duplicate key or value."); } _forward.Add(item.Key,item.Value); _reverse.Add(item.Value, item.Key); } public void Add( TFirst key, TSecond value ) { if (_forward.ContainsKey(key) || _reverse.ContainsKey(value)) { throw new ArgumentException("Duplicate key or value."); } _forward.Add(key, value); _reverse.Add(value, key); } public void Clear() { _forward.Clear(); _reverse.Clear(); } public bool Contains( KeyValuePair item ) { return _forward.Contains(item) && _reverse.TryGetValue(item.Value, out TFirst var) && var!.Equals(item.Key) ; } public bool Contains(TSecond key) { return _reverse.ContainsKey(key); } public bool Contains(TFirst key) { return _forward.ContainsKey(key); } public void CopyTo( KeyValuePair[] array, int arrayIndex ) { if (array == null) { throw new ArgumentNullException(nameof(array)); } if (arrayIndex < 0 || arrayIndex > array.Length) { throw new ArgumentOutOfRangeException(nameof(arrayIndex)); } if (array.Length - arrayIndex < _forward.Count) { throw new ArgumentException("The array is too small to copy the elements."); } foreach (var pair in _forward) { array[arrayIndex ++] = pair; } } public IEnumerator> GetEnumerator() { foreach (var pair in _forward) { yield return pair; } } public bool Remove( TFirst key ) { throw new NotImplementedException(); } public bool Remove( KeyValuePair item ) { if (_forward.Remove(item.Key)) { return _reverse.Remove(item.Value); } return false; } public bool TryGetValue( TFirst key, out TSecond value ) { return _forward.TryGetValue(key, out value); } public bool TryGetValue(TSecond key, out TFirst value) { return _reverse.TryGetValue(key, out value); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } } }