1 // 2 // Copyright (c) 2010-2022 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 System.Collections.Generic; 10 using System.Linq; 11 12 namespace Antmicro.Renode.Utilities.Collections 13 { 14 public class FastReadConcurrentTwoWayDictionary<TLeft, TRight>: IDisposable 15 { FastReadConcurrentTwoWayDictionary()16 public FastReadConcurrentTwoWayDictionary() 17 { 18 locker = new object(); 19 20 lefts = new Dictionary<TLeft, TRight>(); 21 rights = new Dictionary<TRight, TLeft>(); 22 23 Lefts = new TLeft[0]; 24 Rights = new TRight[0]; 25 } 26 Dispose()27 public void Dispose() 28 { 29 Clear(); 30 ItemAdded = null; 31 ItemRemoved = null; 32 } 33 Clear()34 public void Clear() 35 { 36 lock(locker) 37 { 38 var copyOfRights = rights; 39 40 rights = new Dictionary<TRight, TLeft>(); 41 lefts = new Dictionary<TLeft, TRight>(); 42 43 Lefts = new TLeft[0]; 44 Rights = new TRight[0]; 45 46 foreach(var item in copyOfRights) 47 { 48 OnItemRemoved(item.Value, item.Key); 49 } 50 } 51 } 52 Remove(TLeft left)53 public void Remove(TLeft left) 54 { 55 TRight fake; 56 TryRemove(left, out fake); 57 } 58 TryRemove(TLeft left, out TRight right)59 public bool TryRemove(TLeft left, out TRight right) 60 { 61 lock(locker) 62 { 63 var newRights = new Dictionary<TRight, TLeft>(rights); 64 var newLefts = new Dictionary<TLeft, TRight>(lefts); 65 66 if(!newLefts.TryGetValue(left, out right)) 67 { 68 return false; 69 } 70 71 newRights.Remove(right); 72 newLefts.Remove(left); 73 74 lefts = newLefts; 75 rights = newRights; 76 77 Lefts = lefts.Keys.ToArray(); 78 Rights = rights.Keys.ToArray(); 79 80 OnItemRemoved(left, right); 81 return true; 82 } 83 } 84 Remove(TRight right)85 public void Remove(TRight right) 86 { 87 lock(locker) 88 { 89 var newRights = new Dictionary<TRight, TLeft>(rights); 90 var newLefts = new Dictionary<TLeft, TRight>(lefts); 91 92 var leftToRemove = newRights[right]; 93 newRights.Remove(right); 94 newLefts.Remove(leftToRemove); 95 96 lefts = newLefts; 97 rights = newRights; 98 99 Lefts = lefts.Keys.ToArray(); 100 Rights = rights.Keys.ToArray(); 101 102 OnItemRemoved(leftToRemove, right); 103 } 104 } 105 Add(TLeft left, TRight right)106 public void Add(TLeft left, TRight right) 107 { 108 Add(right, left); 109 } 110 Add(TRight right, TLeft left)111 public void Add(TRight right, TLeft left) 112 { 113 lock(locker) 114 { 115 var newRights = new Dictionary<TRight, TLeft>(rights); 116 var newLefts = new Dictionary<TLeft, TRight>(lefts); 117 118 newRights.Add(right, left); 119 newLefts.Add(left, right); 120 121 lefts = newLefts; 122 rights = newRights; 123 124 Lefts = lefts.Keys.ToArray(); 125 Rights = rights.Keys.ToArray(); 126 127 var ia = ItemAdded; 128 if(ia != null) 129 { 130 ia(left, right); 131 } 132 } 133 } 134 ExistsEither(TRight right, TLeft left)135 public bool ExistsEither(TRight right, TLeft left) 136 { 137 return ExistsEither(left, right); 138 } 139 ExistsEither(TLeft left, TRight right)140 public bool ExistsEither(TLeft left, TRight right) 141 { 142 Dictionary<TLeft, TRight> copyOfLefts; 143 Dictionary<TRight, TLeft> copyOfRights; 144 145 lock(locker) 146 { 147 copyOfLefts = lefts; 148 copyOfRights = rights; 149 } 150 151 return copyOfLefts.ContainsKey(left) || copyOfRights.ContainsKey(right); 152 } 153 Exists(TLeft left)154 public bool Exists(TLeft left) 155 { 156 var copy = lefts; 157 return copy.ContainsKey(left); 158 } 159 TryGetValue(TLeft left, out TRight right)160 public bool TryGetValue(TLeft left, out TRight right) 161 { 162 right = default(TRight); 163 if(left == null) 164 { 165 return false; 166 } 167 var copy = lefts; 168 return copy.TryGetValue(left, out right); 169 } 170 TryGetValue(TRight right, out TLeft left)171 public bool TryGetValue(TRight right, out TLeft left) 172 { 173 left = default(TLeft); 174 if(right == null) 175 { 176 return false; 177 } 178 var copy = rights; 179 return copy.TryGetValue(right, out left); 180 } 181 182 public event Action<TLeft, TRight> ItemAdded; 183 184 public event Action<TLeft, TRight> ItemRemoved; 185 186 public TLeft[] Lefts { get; private set; } 187 188 public TRight[] Rights { get; private set; } 189 190 public TLeft this[TRight index] 191 { 192 get 193 { 194 var copy = rights; 195 return copy[index]; 196 } 197 } 198 199 public TRight this[TLeft index] 200 { 201 get 202 { 203 var copy = lefts; 204 return copy[index]; 205 } 206 } 207 208 public int Count 209 { 210 get { return lefts.Count; } 211 } 212 OnItemRemoved(TLeft left, TRight right)213 private void OnItemRemoved(TLeft left, TRight right) 214 { 215 var itemRemoved = ItemRemoved; 216 if(itemRemoved != null) 217 { 218 itemRemoved(left, right); 219 } 220 } 221 222 private readonly object locker; 223 private Dictionary<TLeft, TRight> lefts; 224 private Dictionary<TRight, TLeft> rights; 225 } 226 } 227 228