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 
9 using System;
10 
11 namespace Antmicro.Renode.Utilities
12 {
13     public class WeakWrapper<T> where T : class
14     {
15         // this method can be used to create *fake* WeakWrapper that holds no real WeakReference
16         // it is intended for use with methods like *Compare*, *ContainsKey* etc. yet without the overhead of creating the WeakReference
CreateForComparison(T obj)17         public static WeakWrapper<T> CreateForComparison(T obj)
18         {
19             return new WeakWrapper<T>(obj, true);
20         }
21 
WeakWrapper(T obj)22         public WeakWrapper(T obj) : this(obj, false)
23         {
24         }
25 
ConvertToRealWeakWrapper()26         public void ConvertToRealWeakWrapper()
27         {
28             var objReferenceCopy = objReference;
29             if(objReferenceCopy == null)
30             {
31                 throw new InvalidOperationException("Cannot convert real weak wrapper.");
32             }
33 
34             objWeakReference = new WeakReference<T>(objReferenceCopy);
35             objReference = null;
36         }
37 
Equals(object obj)38         public override bool Equals(object obj)
39         {
40             var objAsWeakWrapper = obj as WeakWrapper<T>;
41             if(objAsWeakWrapper != null)
42             {
43                 T myTarget, objTarget;
44                 bool hasTarget;
45                 return ((hasTarget = TryGetTarget(out myTarget)) == objAsWeakWrapper.TryGetTarget(out objTarget)) && hasTarget && myTarget.Equals(objTarget);
46             }
47 
48             return false;
49         }
50 
GetHashCode()51         public override int GetHashCode()
52         {
53             return objHashCode;
54         }
55 
TryGetTarget(out T target)56         public bool TryGetTarget(out T target)
57         {
58             if(objReference != null)
59             {
60                 target = objReference;
61                 return true;
62             }
63             return objWeakReference.TryGetTarget(out target);
64         }
65 
WeakWrapper(T obj, bool doNotCreateWeakReference)66         private WeakWrapper(T obj, bool doNotCreateWeakReference)
67         {
68             // we can calculate the hashcode here, because according
69             // to "The Path of C#" `GetHashCode` method result should not
70             // be calculated from mutable fields, so it should not change
71             // during object's lifetime
72             objHashCode = obj.GetHashCode();
73             if(doNotCreateWeakReference)
74             {
75                 objReference = obj;
76             }
77             else
78             {
79                 objWeakReference = new WeakReference<T>(obj);
80             }
81         }
82 
83         private T objReference;
84         private WeakReference<T> objWeakReference;
85         private readonly int objHashCode;
86     }
87 }
88