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