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 System.Collections.Generic; 10 using System.Collections; 11 using Antmicro.Migrant; 12 using System.Linq; 13 using Antmicro.Migrant.Hooks; 14 15 namespace Antmicro.Renode.Utilities.Collections 16 { 17 public class SerializableWeakDictionary<TKey, TValue> : IDictionary<TKey, TValue> 18 { SerializableWeakDictionary()19 public SerializableWeakDictionary() 20 { 21 sync = new object(); 22 Clear(); 23 } 24 Add(TKey key, TValue value)25 public void Add(TKey key, TValue value) 26 { 27 lock(sync) 28 { 29 List<TKey> currentKeys; 30 List<TValue> currentValues; 31 ObtainKeysAndValues(out currentKeys, out currentValues); 32 if(currentKeys.Contains(key)) 33 { 34 throw new InvalidOperationException(string.Format("Key '{0}' already exists.", key)); 35 } 36 keys.Add(new WeakReference(key)); 37 values.Add(new WeakReference(value)); 38 } 39 } 40 ContainsKey(TKey key)41 public bool ContainsKey(TKey key) 42 { 43 lock(sync) 44 { 45 return keys.Select(x => x.Target).Where(x => x != null).Any(x => x.Equals(key)); 46 } 47 } 48 Remove(TKey key)49 public bool Remove(TKey key) 50 { 51 lock(sync) 52 { 53 List<TKey> currentKeys; 54 List<TValue> currentValues; 55 ObtainKeysAndValues(out currentKeys, out currentValues); 56 var index = currentKeys.IndexOf(key); 57 if(index == -1) 58 { 59 return false; 60 } 61 keys.RemoveAt(index); 62 values.RemoveAt(index); 63 return true; 64 } 65 } 66 TryGetValue(TKey key, out TValue value)67 public bool TryGetValue(TKey key, out TValue value) 68 { 69 lock(sync) 70 { 71 List<TKey> currentKeys; 72 List<TValue> currentValues; 73 ObtainKeysAndValues(out currentKeys, out currentValues); 74 var index = currentKeys.IndexOf(key); 75 if(index == -1) 76 { 77 value = default(TValue); 78 return false; 79 } 80 value = currentValues[index]; 81 return true; 82 } 83 } 84 85 public TValue this[TKey key] 86 { 87 get 88 { 89 TValue value; 90 if(!TryGetValue(key, out value)) 91 { 92 throw new KeyNotFoundException(); 93 } 94 return value; 95 } 96 set 97 { 98 lock(sync) 99 { 100 List<TKey> currentKeys; 101 List<TValue> currentValues; 102 ObtainKeysAndValues(out currentKeys, out currentValues); 103 var index = currentKeys.IndexOf(key); 104 if(index == -1) 105 { 106 Add(key, value); 107 return; 108 } 109 values[index] = new WeakReference(value); 110 } 111 } 112 } 113 114 public ICollection<TKey> Keys 115 { 116 get 117 { 118 List<TKey> currentKeys; 119 List<TValue> currentValues; 120 ObtainKeysAndValues(out currentKeys, out currentValues); 121 return currentKeys; 122 } 123 } 124 125 public ICollection<TValue> Values 126 { 127 get 128 { 129 List<TKey> currentKeys; 130 List<TValue> currentValues; 131 ObtainKeysAndValues(out currentKeys, out currentValues); 132 return currentValues; 133 } 134 } 135 Add(KeyValuePair<TKey, TValue> item)136 public void Add(KeyValuePair<TKey, TValue> item) 137 { 138 Add(item.Key, item.Value); 139 } 140 Clear()141 public void Clear() 142 { 143 lock(sync) 144 { 145 keys = new List<WeakReference>(); 146 values = new List<WeakReference>(); 147 } 148 } 149 Contains(KeyValuePair<TKey, TValue> item)150 public bool Contains(KeyValuePair<TKey, TValue> item) 151 { 152 lock(sync) 153 { 154 List<TKey> currentKeys; 155 List<TValue> currentValues; 156 ObtainKeysAndValues(out currentKeys, out currentValues); 157 var index = currentKeys.IndexOf(item.Key); 158 if(index == -1) 159 { 160 return false; 161 } 162 return currentValues[index].Equals(item.Value); 163 } 164 } 165 CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)166 public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex) 167 { 168 throw new NotImplementedException(); 169 } 170 Remove(KeyValuePair<TKey, TValue> item)171 public bool Remove(KeyValuePair<TKey, TValue> item) 172 { 173 throw new NotImplementedException(); 174 } 175 176 public int Count 177 { 178 get 179 { 180 List<TKey> currentKeys; 181 List<TValue> currentValues; 182 ObtainKeysAndValues(out currentKeys, out currentValues); 183 return currentKeys.Count; 184 } 185 } 186 187 public bool IsReadOnly 188 { 189 get 190 { 191 return false; 192 } 193 } 194 195 GetEnumerator()196 public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator() 197 { 198 List<TKey> currentKeys; 199 List<TValue> currentValues; 200 ObtainKeysAndValues(out currentKeys, out currentValues); 201 for(var i = 0; i < currentKeys.Count; i++) 202 { 203 yield return new KeyValuePair<TKey, TValue>(currentKeys[i], currentValues[i]); 204 } 205 } 206 207 IEnumerable.GetEnumerator()208 IEnumerator IEnumerable.GetEnumerator() 209 { 210 return GetEnumerator(); 211 } 212 GetOrCreateValue(TKey key, TValue value)213 public TValue GetOrCreateValue(TKey key, TValue value) 214 { 215 lock(sync) 216 { 217 List<TKey> currentKeys; 218 List<TValue> currentValues; 219 ObtainKeysAndValues(out currentKeys, out currentValues); 220 var index = currentKeys.IndexOf(key); 221 if(index == -1) 222 { 223 Add(key, value); 224 return value; 225 } 226 return currentValues[index]; 227 } 228 } 229 ObtainKeysAndValues(out List<TKey> currentKeys, out List<TValue> currentValues)230 private void ObtainKeysAndValues(out List<TKey> currentKeys, out List<TValue> currentValues) 231 { 232 lock(sync) 233 { 234 currentKeys = new List<TKey>(); 235 currentValues = new List<TValue>(); 236 for(var i = 0; i < keys.Count; i++) 237 { 238 // if the key OR value is not available, the whole entry is not available 239 var key = keys[i].Target; 240 var value = values[i].Target; 241 if(key == null || value == null) 242 { 243 keys.RemoveAt(i); 244 values.RemoveAt(i); 245 i--; 246 continue; 247 } 248 currentKeys.Add((TKey)key); 249 currentValues.Add((TValue)value); 250 } 251 } 252 } 253 254 [PreSerialization] BeforeSerialization()255 private void BeforeSerialization() 256 { 257 ObtainKeysAndValues(out serializedKeys, out serializedValues); 258 } 259 260 [PostSerialization] AfterSerialization()261 private void AfterSerialization() 262 { 263 serializedKeys = null; 264 serializedValues = null; 265 } 266 267 [PostDeserialization] AfterDeserialization()268 private void AfterDeserialization() 269 { 270 keys = serializedKeys.Select(x => new WeakReference(x)).ToList(); 271 values = serializedValues.Select(x => new WeakReference(x)).ToList(); 272 AfterSerialization(); 273 } 274 275 private object sync; 276 277 [Transient] 278 private List<WeakReference> keys; 279 280 [Transient] 281 private List<WeakReference> values; 282 283 private List<TKey> serializedKeys; 284 private List<TValue> serializedValues; 285 } 286 } 287 288