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.Linq;
11 using Antmicro.Migrant.Hooks;
12 using Antmicro.Migrant;
13 
14 namespace Antmicro.Renode.Utilities.Collections
15 {
16     public class WeakMultiTable<TLeft, TRight>
17     {
WeakMultiTable()18         public WeakMultiTable()
19         {
20             sync = new object();
21             Init();
22         }
23 
Add(TLeft left, TRight right)24         public void Add(TLeft left, TRight right)
25         {
26             lock(sync)
27             {
28                 lefts.Add(new WeakReference(left));
29                 rights.Add(new WeakReference(right));
30             }
31         }
32 
GetAllForLeft(TLeft left)33         public IEnumerable<TRight> GetAllForLeft(TLeft left)
34         {
35             lock(sync)
36             {
37                 try
38                 {
39                     Snapshot();
40                     var neededIndices = new HashSet<int>(snapshotLefts.Select((l, index) => new { l, index }).Where(x => x.l.Equals(left)).Select(x => x.index));
41                     return snapshotRights.Where((r, index) => neededIndices.Contains(index)).Distinct().ToList();
42                 }
43                 finally
44                 {
45                     FreeSnapshot();
46                 }
47             }
48         }
49 
GetAllForRight(TRight right)50         public IEnumerable<TLeft> GetAllForRight(TRight right)
51         {
52             lock(sync)
53             {
54                 try
55                 {
56                     Snapshot();
57                     var neededIndices = new HashSet<int>(snapshotRights.Select((r, index) => new { r, index }).Where(x => x.r.Equals(right)).Select(x => x.index));
58                     return snapshotLefts.Where((l, index) => neededIndices.Contains(index)).Distinct().ToList();
59                 }
60                 finally
61                 {
62                     FreeSnapshot();
63                 }
64             }
65         }
66 
RemovePair(TLeft left, TRight right)67         public void RemovePair(TLeft left, TRight right)
68         {
69             lock(sync)
70             {
71                 try
72                 {
73                     Snapshot();
74                     for(var i = 0; i < snapshotLefts.Count; i++)
75                     {
76                         if(left.Equals(snapshotLefts[i]) && right.Equals(snapshotRights[i]))
77                         {
78                             snapshotLefts.RemoveAt(i);
79                             snapshotRights.RemoveAt(i);
80                             i--;
81                             continue;
82                         }
83                     }
84                     FromSnapshot();
85                 }
86                 finally
87                 {
88                     FreeSnapshot();
89                 }
90             }
91         }
92 
Init()93         private void Init()
94         {
95             lefts = new List<WeakReference>();
96             rights = new List<WeakReference>();
97         }
98 
Snapshot()99         private void Snapshot()
100         {
101             snapshotLefts = new List<TLeft>();
102             snapshotRights = new List<TRight>();
103             lock(sync)
104             {
105                 for(var i = 0; i < lefts.Count; i++)
106                 {
107                     var left = (TLeft)lefts[i].Target;
108                     var right = (TRight)rights[i].Target;
109                     if(left == null || right == null)
110                     {
111                         lefts.RemoveAt(i);
112                         rights.RemoveAt(i);
113                         i--;
114                         continue;
115                     }
116                     snapshotLefts.Add(left);
117                     snapshotRights.Add(right);
118                 }
119             }
120         }
121 
FromSnapshot()122         private void FromSnapshot()
123         {
124             lefts = snapshotLefts.Select(x => new WeakReference(x)).ToList();
125             rights = snapshotRights.Select(x => new WeakReference(x)).ToList();
126         }
127 
FreeSnapshot()128         private void FreeSnapshot()
129         {
130             snapshotLefts = null;
131             snapshotRights = null;
132         }
133 
134         [PreSerialization]
BeforeSerialization()135         private void BeforeSerialization()
136         {
137             Snapshot();
138         }
139 
140         [PostSerialization]
AfterSerialization()141         private void AfterSerialization()
142         {
143             FreeSnapshot();
144         }
145 
146         [PostDeserialization]
AfterDeserialization()147         private void AfterDeserialization()
148         {
149             FromSnapshot();
150             FreeSnapshot();
151         }
152 
153         private readonly object sync;
154         private List<TLeft> snapshotLefts;
155         private List<TRight> snapshotRights;
156 
157         [Transient]
158         private List<WeakReference> lefts;
159 
160         [Transient]
161         private List<WeakReference> rights;
162     }
163 }
164 
165