Skip to content

Instantly share code, notes, and snippets.

@TheBuzzSaw
Last active May 24, 2019 02:28
Show Gist options
  • Save TheBuzzSaw/f7bee52a3445510d3b188d5d8f2326c7 to your computer and use it in GitHub Desktop.
Save TheBuzzSaw/f7bee52a3445510d3b188d5d8f2326c7 to your computer and use it in GitHub Desktop.
using System;
using System.Collections;
using System.Collections.Generic;
namespace Kelly
{
public class TwoWayDictionary<TKey, TValue> : IDictionary<TKey, TValue>
{
private readonly Dictionary<TKey, TValue> _main;
private readonly Dictionary<TValue, TKey> _reverse;
private IDictionary<TKey, TValue> IMain => _main as IDictionary<TKey, TValue>;
private IDictionary<TValue, TKey> IReverse => _reverse as IDictionary<TValue, TKey>;
public TwoWayDictionary<TValue, TKey> Reverse { get; }
ICollection<TKey> IDictionary<TKey, TValue>.Keys => IMain.Keys;
ICollection<TValue> IDictionary<TKey, TValue>.Values => IMain.Values;
bool ICollection<KeyValuePair<TKey, TValue>>.IsReadOnly => IMain.IsReadOnly;
public int Count => _main.Count;
public Dictionary<TKey, TValue>.KeyCollection Keys => _main.Keys;
public Dictionary<TKey, TValue>.ValueCollection Values => _main.Values;
public TValue this[TKey key]
{
get => _main[key];
set
{
bool hadOldValue = _main.Remove(key, out var oldValue);
if (hadOldValue)
_reverse.Remove(oldValue);
bool hadOldKey = _reverse.Remove(value, out var oldKey);
if (hadOldKey)
_main.Remove(oldKey);
try
{
Add(key, value);
}
catch
{
if (hadOldKey)
Add(oldKey, value);
if (hadOldValue)
Add(key, oldValue);
throw;
}
}
}
public TwoWayDictionary()
{
_main = new Dictionary<TKey, TValue>();
_reverse = new Dictionary<TValue, TKey>();
Reverse = new TwoWayDictionary<TValue, TKey>(this);
}
private TwoWayDictionary(TwoWayDictionary<TValue, TKey> reverse)
{
Reverse = reverse;
_main = reverse._reverse;
_reverse = reverse._main;
}
public void Add(TKey key, TValue value)
{
_main.Add(key, value);
try
{
_reverse.Add(value, key);
}
catch
{
_main.Remove(key);
throw;
}
}
public bool ContainsKey(TKey key) => _main.ContainsKey(key);
public bool ContainsValue(TValue value) => _reverse.ContainsKey(value);
public bool Remove(TKey key)
{
if (_main.Remove(key, out var value))
{
_reverse.Remove(value);
return true;
}
else
{
return false;
}
}
public bool TryGetValue(TKey key, out TValue value) => _main.TryGetValue(key, out value);
void ICollection<KeyValuePair<TKey, TValue>>.Add(KeyValuePair<TKey, TValue> item)
{
IMain.Add(item);
try
{
var pair = KeyValuePair.Create(item.Value, item.Key);
IReverse.Add(pair);
}
catch
{
IMain.Remove(item);
throw;
}
}
public void Clear()
{
_main.Clear();
_reverse.Clear();
}
bool ICollection<KeyValuePair<TKey, TValue>>.Contains(KeyValuePair<TKey, TValue> item) =>
IMain.Contains(item);
void ICollection<KeyValuePair<TKey, TValue>>.CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex) =>
IMain.CopyTo(array, arrayIndex);
bool ICollection<KeyValuePair<TKey, TValue>>.Remove(KeyValuePair<TKey, TValue> item)
{
if (IMain.Remove(item))
{
var pair = KeyValuePair.Create(item.Value, item.Key);
IReverse.Remove(pair);
return true;
}
else
{
return false;
}
}
public Dictionary<TKey, TValue>.Enumerator GetEnumerator() =>
_main.GetEnumerator();
IEnumerator<KeyValuePair<TKey, TValue>> IEnumerable<KeyValuePair<TKey, TValue>>.GetEnumerator() =>
IMain.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => (_main as IEnumerable).GetEnumerator();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment