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