1 // 2 // Copyright (c) 2010-2018 Antmicro 3 // Copyright (c) 2011-2015 Realtime Embedded 4 // 5 // This file is licensed under the MIT License. 6 // Full license text is available in 'licenses/MIT.txt'. 7 // 8 using System; 9 using Antmicro.Migrant.Hooks; 10 using System.Collections.Generic; 11 using System.Linq; 12 using Antmicro.Migrant; 13 14 namespace Antmicro.Renode.Utilities.Collections 15 { 16 public class TwoWayDictionary<TLeft, TRight> 17 { Clear()18 public void Clear() 19 { 20 lock(lockObject) 21 { 22 var array = Lefts.ToArray(); 23 foreach(var item in array) 24 { 25 Remove(item); 26 } 27 } 28 } 29 Remove(TLeft left)30 public bool Remove(TLeft left) 31 { 32 TRight tmp; 33 return Remove(left, out tmp); 34 } 35 TryExchange(TLeft left, TRight newRight, out TRight oldRight)36 public bool TryExchange(TLeft left, TRight newRight, out TRight oldRight) 37 { 38 lock(lockObject) 39 { 40 if(!Remove(left, out oldRight)) 41 { 42 return false; 43 } 44 Add(left, newRight); 45 return true; 46 } 47 } 48 TryExchange(TRight right, TLeft newLeft, out TLeft oldLeft)49 public bool TryExchange(TRight right, TLeft newLeft, out TLeft oldLeft) 50 { 51 lock(lockObject) 52 { 53 if(!Remove(right, out oldLeft)) 54 { 55 return false; 56 } 57 Add(newLeft, right); 58 return true; 59 } 60 } 61 Remove(TLeft left, out TRight right)62 public bool Remove(TLeft left, out TRight right) 63 { 64 right = default(TRight); 65 lock(lockObject) 66 { 67 if(!Exists(left)) 68 { 69 return false; 70 } 71 right = lefts[left]; 72 RemoveExistingMapping(left, right); 73 } 74 return true; 75 } 76 Remove(TRight right, out TLeft left)77 public bool Remove(TRight right, out TLeft left) 78 { 79 left = default(TLeft); 80 lock(lockObject) 81 { 82 if(!Exists(right)) 83 { 84 return false; 85 } 86 left = rights[right]; 87 RemoveExistingMapping(left, right); 88 } 89 return true; 90 } 91 Remove(TRight right)92 public bool Remove(TRight right) 93 { 94 lock(lockObject) 95 { 96 if(!Exists(right)) 97 { 98 return false; 99 } 100 RemoveExistingMapping(rights[right], right); 101 } 102 return true; 103 } 104 Add(TLeft left, TRight right)105 public void Add(TLeft left, TRight right) 106 { 107 lock(lockObject) 108 { 109 lefts.Add(left, right); 110 rights.Add(right, left); 111 } 112 113 OnItemAdded(left, right); 114 } 115 TryGetValue(TLeft left, out TRight right)116 public bool TryGetValue(TLeft left, out TRight right) 117 { 118 return lefts.TryGetValue(left, out right); 119 } 120 TryGetValue(TRight right, out TLeft left)121 public bool TryGetValue(TRight right, out TLeft left) 122 { 123 return rights.TryGetValue(right, out left); 124 } 125 ExistsEither(TLeft left, TRight right)126 public bool ExistsEither(TLeft left, TRight right) 127 { 128 lock(lockObject) 129 { 130 return Exists(left) || Exists(right); 131 } 132 } 133 Exists(TLeft left)134 public bool Exists(TLeft left) 135 { 136 return lefts.ContainsKey(left); 137 } 138 Exists(TRight right)139 public bool Exists(TRight right) 140 { 141 return rights.ContainsKey(right); 142 } 143 144 public TLeft this[TRight index] 145 { 146 get 147 { 148 return rights[index]; 149 } 150 } 151 152 public TRight this[TLeft index] 153 { 154 get 155 { 156 return lefts[index]; 157 } 158 } 159 160 public int Count 161 { 162 get { return lefts.Count; } 163 } 164 165 public IEnumerable<TLeft> Lefts { get { return lefts.Keys; } } 166 167 public IEnumerable<TRight> Rights { get { return rights.Keys; } } 168 169 public event Action<TLeft, TRight> ItemAdded; 170 171 public event Action<TLeft, TRight> ItemRemoved; 172 RemoveExistingMapping(TLeft left, TRight right)173 private void RemoveExistingMapping(TLeft left, TRight right) 174 { 175 lefts.Remove(left); 176 rights.Remove(right); 177 OnItemRemoved(left, right); 178 } 179 OnItemAdded(TLeft left, TRight right)180 private void OnItemAdded(TLeft left, TRight right) 181 { 182 var itemAdded = ItemAdded; 183 if(itemAdded != null) 184 { 185 itemAdded(left, right); 186 } 187 } 188 OnItemRemoved(TLeft left, TRight right)189 private void OnItemRemoved(TLeft left, TRight right) 190 { 191 var itemRemoved = ItemRemoved; 192 if(itemRemoved != null) 193 { 194 itemRemoved(left, right); 195 } 196 } 197 198 [PostDeserialization] AfterDeserialization()199 private void AfterDeserialization() 200 { 201 // rebuild not serialized dictionary 202 foreach(var item in lefts) 203 { 204 rights.Add(item.Value, item.Key); 205 } 206 } 207 208 private readonly Dictionary<TLeft, TRight> lefts = new Dictionary<TLeft, TRight>(); 209 210 [Constructor] 211 private readonly Dictionary<TRight, TLeft> rights = new Dictionary<TRight, TLeft>(); 212 private readonly object lockObject = new object(); 213 } 214 } 215