Implement MachineKey.Protect and MachineKey.Unprotect
[mono.git] / mcs / class / System.ComponentModel.Composition / src / ComponentModel / Microsoft / Internal / Collections / ConditionalWeakTable.cs
1 // -----------------------------------------------------------------------\r
2 // Copyright (c) Microsoft Corporation.  All rights reserved.\r
3 // -----------------------------------------------------------------------\r
4 #if !CLR40\r
5 using System;\r
6 using System.Collections;\r
7 using System.Collections.Generic;\r
8 using System.Linq;\r
9 using Microsoft.Internal;\r
10 using Microsoft.Internal.Collections;\r
11 \r
12 namespace Microsoft.Internal.Collections\r
13 {\r
14     // This is a broken implementation of ConditionalWeakTable that allows us\r
15     // to compile and work on versions of .Net eariler then 4.0. This class is\r
16     // broken when there are circular dependencies between keys and values, which\r
17     // can only be fixed by using some specific CLR 4.0 features.\r
18     // For code samples of the broken behavior see ConditionalWeakTableTests.cs.\r
19     internal class ConditionalWeakTable<TKey, TValue> \r
20         where TKey : class\r
21         where TValue : class\r
22     {\r
23         private readonly Dictionary<object, TValue> _table;\r
24         private int _capacity = 4;\r
25 \r
26         public ConditionalWeakTable()\r
27         {\r
28             this._table = new Dictionary<object, TValue>();\r
29         }\r
30 \r
31         public void Add(TKey key, TValue value)\r
32         {\r
33             CleanupDeadReferences();\r
34             this._table.Add(CreateWeakKey(key), value);\r
35         }\r
36 \r
37         public bool Remove(TKey key)\r
38         {\r
39             return this._table.Remove(key);\r
40         }\r
41 \r
42         public bool TryGetValue(TKey key, out TValue value)\r
43         {\r
44             return this._table.TryGetValue(key, out value);\r
45         }\r
46 \r
47         private void CleanupDeadReferences()\r
48         {\r
49             if (this._table.Count < _capacity)\r
50             {\r
51                 return;\r
52             }\r
53 \r
54             object[] deadKeys = this._table.Keys\r
55                 .Where(weakRef => !((EquivalentWeakReference)weakRef).IsAlive).ToArray();\r
56 \r
57             foreach (var deadKey in deadKeys)\r
58             {\r
59                 this._table.Remove(deadKey);\r
60             }\r
61 \r
62             if (this._table.Count >= _capacity)\r
63             {\r
64                 _capacity *= 2;\r
65             }\r
66         }\r
67 \r
68         private static object CreateWeakKey(TKey key)\r
69         {\r
70             return new EquivalentWeakReference(key);\r
71         }\r
72 \r
73         private class EquivalentWeakReference\r
74         {\r
75             private readonly WeakReference _weakReference;\r
76             private readonly int _hashCode;\r
77 \r
78             public EquivalentWeakReference(object obj)\r
79             {\r
80                 this._hashCode = obj.GetHashCode();\r
81                 this._weakReference = new WeakReference(obj);\r
82             }\r
83 \r
84             public bool IsAlive\r
85             {\r
86                 get\r
87                 {\r
88                     return this._weakReference.IsAlive;\r
89                 }\r
90             }\r
91 \r
92             public override bool Equals(object obj)\r
93             {\r
94                 EquivalentWeakReference weakRef = obj as EquivalentWeakReference;\r
95 \r
96                 if (weakRef != null)\r
97                 {\r
98                     obj = weakRef._weakReference.Target;\r
99                 }\r
100 \r
101                 if (obj == null)\r
102                 {\r
103                     return base.Equals(weakRef);\r
104                 }\r
105                 \r
106                 return object.Equals(this._weakReference.Target, obj);\r
107             }\r
108 \r
109             public override int GetHashCode()\r
110             {\r
111                 return this._hashCode;\r
112             }\r
113         }\r
114     }\r
115 }\r
116 #endif