Lucene.Net  3.0.3
Lucene.Net is a port of the Lucene search engine library, written in C# and targeted at .NET runtime users.
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Properties Pages
WeakDictionary.cs
Go to the documentation of this file.
1 /*
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements. See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership. The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License. You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied. See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20 */
21 
22 using System;
23 using System.Collections;
24 using System.Collections.Generic;
25 using System.Linq;
26 
27 namespace Lucene.Net.Support
28 {
29  public sealed class WeakDictionary<TKey, TValue> : IDictionary<TKey, TValue>
30  {
31  private HashMap<WeakKey<TKey>, TValue> _hm;
32  private int _gcCollections = 0;
33 
34  public WeakDictionary(int initialCapacity) : this(initialCapacity, Enumerable.Empty<KeyValuePair<TKey, TValue>>())
35  { }
36 
37  public WeakDictionary() : this(32, Enumerable.Empty<KeyValuePair<TKey, TValue>>())
38  { }
39 
40  public WeakDictionary(IEnumerable<KeyValuePair<TKey, TValue>> otherDictionary) : this(32, otherDictionary)
41  { }
42 
43  private WeakDictionary(int initialCapacity, IEnumerable<KeyValuePair<TKey, TValue>> otherDict)
44  {
45  _hm = new HashMap<WeakKey<TKey>, TValue>(initialCapacity);
46  foreach (var kvp in otherDict)
47  {
48  _hm.Add(new WeakKey<TKey>(kvp.Key), kvp.Value);
49  }
50  }
51 
52  private void Clean()
53  {
54  if (_hm.Count == 0) return;
55  var newHm = new HashMap<WeakKey<TKey>, TValue>();
56  foreach (var entry in _hm.Where(x => x.Key != null && x.Key.IsAlive))
57  {
58  newHm.Add(entry.Key, entry.Value);
59  }
60  _hm = newHm;
61  }
62 
63  private void CleanIfNeeded()
64  {
65  int currentColCount = GC.CollectionCount(0);
66  if (currentColCount > _gcCollections)
67  {
68  Clean();
69  _gcCollections = currentColCount;
70  }
71  }
72 
73  public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
74  {
75  foreach (var kvp in _hm.Where(x => x.Key.IsAlive))
76  {
77  yield return new KeyValuePair<TKey, TValue>(kvp.Key.Target, kvp.Value);
78  }
79  }
80 
81  IEnumerator IEnumerable.GetEnumerator()
82  {
83  return GetEnumerator();
84  }
85 
86  void ICollection<KeyValuePair<TKey, TValue>>.Add(KeyValuePair<TKey, TValue> item)
87  {
88  CleanIfNeeded();
89  ((ICollection<KeyValuePair<WeakKey<TKey>, TValue>>) _hm).Add(
90  new KeyValuePair<WeakKey<TKey>, TValue>(new WeakKey<TKey>(item.Key), item.Value));
91  }
92 
93  public void Clear()
94  {
95  _hm.Clear();
96  }
97 
98  bool ICollection<KeyValuePair<TKey, TValue>>.Contains(KeyValuePair<TKey, TValue> item)
99  {
100  return ((ICollection<KeyValuePair<WeakKey<TKey>, TValue>>)_hm).Contains(
101  new KeyValuePair<WeakKey<TKey>, TValue>(new WeakKey<TKey>(item.Key), item.Value));
102  }
103 
104  bool ICollection<KeyValuePair<TKey, TValue>>.Remove(KeyValuePair<TKey, TValue> item)
105  {
106  return ((ICollection<KeyValuePair<WeakKey<TKey>, TValue>>)_hm).Remove(
107  new KeyValuePair<WeakKey<TKey>, TValue>(new WeakKey<TKey>(item.Key), item.Value));
108  }
109 
110  public int Count
111  {
112  get
113  {
114  CleanIfNeeded();
115  return _hm.Count;
116  }
117  }
118 
119  public bool IsReadOnly
120  {
121  get { return false; }
122  }
123 
124  public bool ContainsKey(TKey key)
125  {
126  return _hm.ContainsKey(new WeakKey<TKey>(key));
127  }
128 
129  public void Add(TKey key, TValue value)
130  {
131  CleanIfNeeded();
132  _hm.Add(new WeakKey<TKey>(key), value);
133  }
134 
135  public bool Remove(TKey key)
136  {
137  return _hm.Remove(new WeakKey<TKey>(key));
138  }
139 
140  public bool TryGetValue(TKey key, out TValue value)
141  {
142  return _hm.TryGetValue(new WeakKey<TKey>(key), out value);
143  }
144 
145  public TValue this[TKey key]
146  {
147  get { return _hm[new WeakKey<TKey>(key)]; }
148  set
149  {
150  CleanIfNeeded();
151  _hm[new WeakKey<TKey>(key)] = value;
152  }
153  }
154 
155  public ICollection<TKey> Keys
156  {
157  get
158  {
159  CleanIfNeeded();
160  return new KeyCollection(_hm);
161  }
162  }
163 
164  public ICollection<TValue> Values
165  {
166  get
167  {
168  CleanIfNeeded();
169  return _hm.Values;
170  }
171  }
172 
173  void ICollection<KeyValuePair<TKey, TValue>>.CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
174  {
175  throw new NotSupportedException();
176  }
177 
178  #region KeyCollection
179  class KeyCollection : ICollection<TKey>
180  {
181  private readonly HashMap<WeakKey<TKey>, TValue> _internalDict;
182 
183  public KeyCollection(HashMap<WeakKey<TKey>, TValue> dict)
184  {
185  _internalDict = dict;
186  }
187 
188  public IEnumerator<TKey> GetEnumerator()
189  {
190  foreach (var key in _internalDict.Keys)
191  {
192  yield return key.Target;
193  }
194  }
195 
196  IEnumerator IEnumerable.GetEnumerator()
197  {
198  return GetEnumerator();
199  }
200 
201  public void CopyTo(TKey[] array, int arrayIndex)
202  {
203  throw new NotImplementedException("Implement this as needed");
204  }
205 
206  public int Count
207  {
208  get { return _internalDict.Count + 1; }
209  }
210 
211  public bool IsReadOnly
212  {
213  get { return true; }
214  }
215 
216  #region Explicit Interface Definitions
217  bool ICollection<TKey>.Contains(TKey item)
218  {
219  throw new NotSupportedException();
220  }
221 
222  void ICollection<TKey>.Add(TKey item)
223  {
224  throw new NotSupportedException();
225  }
226 
227  void ICollection<TKey>.Clear()
228  {
229  throw new NotSupportedException();
230  }
231 
232  bool ICollection<TKey>.Remove(TKey item)
233  {
234  throw new NotSupportedException();
235  }
236  #endregion
237  }
238  #endregion
239 
240 
241  /// <summary>
242  /// A weak reference wrapper for the hashtable keys. Whenever a key\value pair
243  /// is added to the hashtable, the key is wrapped using a WeakKey. WeakKey saves the
244  /// value of the original object hashcode for fast comparison.
245  /// </summary>
246  class WeakKey<T>
247  {
248  WeakReference reference;
249  int hashCode;
250 
251  public WeakKey(T key)
252  {
253  if (key == null)
254  throw new ArgumentNullException("key");
255 
256  hashCode = key.GetHashCode();
257  reference = new WeakReference(key);
258  }
259 
260  public override int GetHashCode()
261  {
262  return hashCode;
263  }
264 
265  public override bool Equals(object obj)
266  {
267  if (!reference.IsAlive || obj == null) return false;
268 
269  if (object.ReferenceEquals(this, obj))
270  {
271  return true;
272  }
273 
274  if (obj is WeakKey<T>)
275  {
276  var other = (WeakKey<T>)obj;
277 
278  var referenceTarget = reference.Target; // Careful: can be null in the mean time...
279  return referenceTarget != null && referenceTarget.Equals(other.Target);
280  }
281 
282  return false;
283  }
284 
285  public T Target
286  {
287  get { return (T)reference.Target; }
288  }
289 
290  public bool IsAlive
291  {
292  get { return reference.IsAlive; }
293  }
294  }
295  }
296 }