File: WeakHashtable.cs

package info (click to toggle)
mono 6.12.0.199%2Bdfsg-6
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 1,296,836 kB
  • sloc: cs: 11,181,803; xml: 2,850,076; ansic: 699,709; cpp: 123,344; perl: 59,361; javascript: 30,841; asm: 21,853; makefile: 20,405; sh: 15,009; python: 4,839; pascal: 925; sql: 859; sed: 16; php: 1
file content (227 lines) | stat: -rw-r--r-- 7,172 bytes parent folder | download | duplicates (7)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
//------------------------------------------------------------------------------
// <copyright file="WeakHashtable.cs" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>                                                                
//------------------------------------------------------------------------------

namespace System.ComponentModel {

    using System;
    using System.Collections;
    using System.Security.Permissions;

    /// <devdoc>
    ///     This is a hashtable that stores object keys as weak references.  
    ///     It monitors memory usage and will periodically scavenge the
    ///     hash table to clean out dead references.
    /// </devdoc>
    [HostProtection(SharedState = true)]
    internal sealed class WeakHashtable : Hashtable
    {
        private static IEqualityComparer _comparer = new WeakKeyComparer();

        private long     _lastGlobalMem;
        private int      _lastHashCount;

        internal WeakHashtable() : base(_comparer)
        {
        }

        /// <devdoc>
        ///     Override of clear that performs a scavenge.
        /// </devdoc>
        public override void Clear()
        {
            base.Clear();
        }

        /// <devdoc>
        ///     Override of remove that performs a scavenge.
        /// </devdoc>
        public override void Remove(object key)
        {
            base.Remove(key);
        }

        /// <devdoc>
        ///     Override of Item that wraps a weak reference around the
        ///     key and performs a scavenge.
        /// </devdoc>
        public void SetWeak(object key, object value)
        {
            ScavengeKeys();
            this[new EqualityWeakReference(key)] = value;
        }

        /// <devdoc>
        ///     This method checks to see if it is necessary to
        ///     scavenge keys, and if it is it performs a scan
        ///     of all keys to see which ones are no longer valid.
        ///     To determine if we need to scavenge keys we need to
        ///     try to track the current GC memory.  Our rule of
        ///     thumb is that if GC memory is decreasing and our
        ///     key count is constant we need to scavenge.  We
        ///     will need to see if this is too often for extreme
        ///     use cases like the CompactFramework (they add
        ///     custom type data for every object at design time).
        /// </devdoc>
        private void ScavengeKeys()
        {
            int hashCount = Count;

            if (hashCount == 0)
            {
                return;
            }

            if (_lastHashCount == 0)
            {
                _lastHashCount = hashCount;
                return;
            }

            long globalMem = GC.GetTotalMemory(false);

            if (_lastGlobalMem == 0)
            {
                _lastGlobalMem = globalMem;
                return;
            }

            float memDelta = (float)(globalMem - _lastGlobalMem) / (float)_lastGlobalMem;
            float hashDelta = (float)(hashCount - _lastHashCount) / (float)_lastHashCount;

            if (memDelta < 0 && hashDelta >= 0)
            {
                // Perform a scavenge through our keys, looking
                // for dead references.
                //
                ArrayList cleanupList = null;
                foreach(object o in Keys)
                {
                    WeakReference wr = o as WeakReference;
                    if (wr != null && !wr.IsAlive)
                    {
                        if (cleanupList == null)
                        {
                            cleanupList = new ArrayList();
                        }

                        cleanupList.Add(wr);
                    }
                }

                if (cleanupList != null)
                {
                    foreach(object o in cleanupList)
                    {
                        Remove(o);
                    }
                }
            }
        
            _lastGlobalMem = globalMem;
            _lastHashCount = hashCount;
        }

        private class WeakKeyComparer : IEqualityComparer
        {
            bool IEqualityComparer.Equals(Object x, Object y)
            {
                if (x == null)
                {
                    return y == null;
                }
                if (y != null && x.GetHashCode() == y.GetHashCode())
                {
                    WeakReference wX = x as WeakReference;
                    WeakReference wY = y as WeakReference;

                    if (wX != null)
                    {
                        if (!wX.IsAlive)
                        {
                            return false;
                        }
                        x = wX.Target;
                    }

                    if (wY != null)
                    {
                        if (!wY.IsAlive)
                        {
                            return false;
                        }
                        y = wY.Target;
                    }

                    return object.ReferenceEquals(x, y);
                }

                return false;
            }

            int IEqualityComparer.GetHashCode (Object obj)
            {
                return obj.GetHashCode();
            }
        }

        /// <devdoc>
        ///     A subclass of WeakReference that overrides GetHashCode and
        ///     Equals so that the weak reference returns the same equality
        ///     semantics as the object it wraps.  This will always return
        ///     the object's hash code and will return True for a Equals
        ///     comparison of the object it is wrapping.  If the object
        ///     it is wrapping has finalized, Equals always returns false.
        /// </devdoc>
        private sealed class EqualityWeakReference : WeakReference
        {
            private int _hashCode;
            internal EqualityWeakReference(object o) : base(o)
            {
                _hashCode = o.GetHashCode();
            }

            public override bool Equals(object o)
            {
                if (o == null)
                {
                    return false;
                }

                if (o.GetHashCode() != _hashCode)
                {
                    return false;
                }

                if (o == this || (IsAlive && object.ReferenceEquals(o, Target)))
                {
                    return true;
                }

                return false;
            }

            public override int GetHashCode()
            {
                return _hashCode;
            }
        }


        /* The folowing code has been removed to prevent FXCOP violation
           It is left here incase it needs to be resurected
        /// <devdoc>
        ///     Override of add that wraps a weak reference around the
        ///     key and performs a scavenge.
        /// </devdoc>
        public void AddWeak(object key, object value)
        {
            ScavengeKeys();
            base.Add(new EqualityWeakReference(key), value);
        }
        */
    }
}