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