mscorlib(4.0.0.0) API with additions
ConditionalWeakTable.cs
1 using System.Collections;
4 using System.Security;
5 
7 {
11  [ComVisible(false)]
12  [__DynamicallyInvokable]
13  public sealed class ConditionalWeakTable<TKey, TValue> where TKey : class where TValue : class
14  {
18  [__DynamicallyInvokable]
19  public delegate TValue CreateValueCallback(TKey key);
20 
21  private struct Entry
22  {
23  public DependentHandle depHnd;
24 
25  public int hashCode;
26 
27  public int next;
28  }
29 
30  private int[] _buckets;
31 
32  private Entry[] _entries;
33 
34  private int _freeList;
35 
36  private const int _initialCapacity = 5;
37 
38  private readonly object _lock;
39 
40  private bool _invalid;
41 
42  internal ICollection<TKey> Keys
43  {
44  [SecuritySafeCritical]
45  get
46  {
47  List<TKey> list = new List<TKey>();
48  lock (_lock)
49  {
50  for (int i = 0; i < _buckets.Length; i++)
51  {
52  for (int num = _buckets[i]; num != -1; num = _entries[num].next)
53  {
54  TKey val = (TKey)_entries[num].depHnd.GetPrimary();
55  if (val != null)
56  {
57  list.Add(val);
58  }
59  }
60  }
61  return list;
62  }
63  }
64  }
65 
66  internal ICollection<TValue> Values
67  {
68  [SecuritySafeCritical]
69  get
70  {
71  List<TValue> list = new List<TValue>();
72  lock (_lock)
73  {
74  for (int i = 0; i < _buckets.Length; i++)
75  {
76  for (int num = _buckets[i]; num != -1; num = _entries[num].next)
77  {
78  object primary = null;
79  object secondary = null;
80  _entries[num].depHnd.GetPrimaryAndSecondary(out primary, out secondary);
81  if (primary != null)
82  {
83  list.Add((TValue)secondary);
84  }
85  }
86  }
87  return list;
88  }
89  }
90  }
91 
93  [SecuritySafeCritical]
94  [__DynamicallyInvokable]
96  {
97  _buckets = new int[0];
98  _entries = new Entry[0];
99  _freeList = -1;
100  _lock = new object();
101  Resize();
102  }
103 
111  [SecuritySafeCritical]
112  [__DynamicallyInvokable]
113  public bool TryGetValue(TKey key, out TValue value)
114  {
115  if (key == null)
116  {
117  ThrowHelper.ThrowArgumentNullException(ExceptionArgument.key);
118  }
119  lock (_lock)
120  {
121  VerifyIntegrity();
122  return TryGetValueWorker(key, out value);
123  }
124  }
125 
133  [SecuritySafeCritical]
134  [__DynamicallyInvokable]
135  public void Add(TKey key, TValue value)
136  {
137  if (key == null)
138  {
139  ThrowHelper.ThrowArgumentNullException(ExceptionArgument.key);
140  }
141  lock (_lock)
142  {
143  VerifyIntegrity();
144  _invalid = true;
145  int num = FindEntry(key);
146  if (num != -1)
147  {
148  _invalid = false;
149  ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_AddingDuplicate);
150  }
151  CreateEntry(key, value);
152  _invalid = false;
153  }
154  }
155 
162  [SecuritySafeCritical]
163  [__DynamicallyInvokable]
164  public bool Remove(TKey key)
165  {
166  if (key == null)
167  {
168  ThrowHelper.ThrowArgumentNullException(ExceptionArgument.key);
169  }
170  lock (_lock)
171  {
172  VerifyIntegrity();
173  _invalid = true;
174  int num = RuntimeHelpers.GetHashCode(key) & int.MaxValue;
175  int num2 = num % _buckets.Length;
176  int num3 = -1;
177  for (int num4 = _buckets[num2]; num4 != -1; num4 = _entries[num4].next)
178  {
179  if (_entries[num4].hashCode == num && _entries[num4].depHnd.GetPrimary() == key)
180  {
181  if (num3 == -1)
182  {
183  _buckets[num2] = _entries[num4].next;
184  }
185  else
186  {
187  _entries[num3].next = _entries[num4].next;
188  }
189  _entries[num4].depHnd.Free();
190  _entries[num4].next = _freeList;
191  _freeList = num4;
192  _invalid = false;
193  return true;
194  }
195  num3 = num4;
196  }
197  _invalid = false;
198  return false;
199  }
200  }
201 
208  [SecuritySafeCritical]
209  [__DynamicallyInvokable]
210  public TValue GetValue(TKey key, CreateValueCallback createValueCallback)
211  {
212  if (createValueCallback == null)
213  {
214  throw new ArgumentNullException("createValueCallback");
215  }
216  if (TryGetValue(key, out TValue value))
217  {
218  return value;
219  }
220  TValue val = createValueCallback(key);
221  lock (_lock)
222  {
223  VerifyIntegrity();
224  _invalid = true;
225  if (TryGetValueWorker(key, out value))
226  {
227  _invalid = false;
228  return value;
229  }
230  CreateEntry(key, val);
231  _invalid = false;
232  return val;
233  }
234  }
235 
243  [__DynamicallyInvokable]
244  public TValue GetOrCreateValue(TKey key)
245  {
246  return GetValue(key, (TKey k) => Activator.CreateInstance<TValue>());
247  }
248 
249  [SecuritySafeCritical]
250  [FriendAccessAllowed]
251  internal TKey FindEquivalentKeyUnsafe(TKey key, out TValue value)
252  {
253  lock (_lock)
254  {
255  for (int i = 0; i < _buckets.Length; i++)
256  {
257  for (int num = _buckets[i]; num != -1; num = _entries[num].next)
258  {
259  _entries[num].depHnd.GetPrimaryAndSecondary(out object primary, out object secondary);
260  if (object.Equals(primary, key))
261  {
262  value = (TValue)secondary;
263  return (TKey)primary;
264  }
265  }
266  }
267  }
268  value = null;
269  return null;
270  }
271 
272  [SecuritySafeCritical]
273  internal void Clear()
274  {
275  lock (_lock)
276  {
277  for (int i = 0; i < _buckets.Length; i++)
278  {
279  _buckets[i] = -1;
280  }
281  int j;
282  for (j = 0; j < _entries.Length; j++)
283  {
284  if (_entries[j].depHnd.IsAllocated)
285  {
286  _entries[j].depHnd.Free();
287  }
288  _entries[j].next = j - 1;
289  }
290  _freeList = j - 1;
291  }
292  }
293 
294  [SecurityCritical]
295  private bool TryGetValueWorker(TKey key, out TValue value)
296  {
297  int num = FindEntry(key);
298  if (num != -1)
299  {
300  object primary = null;
301  object secondary = null;
302  _entries[num].depHnd.GetPrimaryAndSecondary(out primary, out secondary);
303  if (primary != null)
304  {
305  value = (TValue)secondary;
306  return true;
307  }
308  }
309  value = null;
310  return false;
311  }
312 
313  [SecurityCritical]
314  private void CreateEntry(TKey key, TValue value)
315  {
316  if (_freeList == -1)
317  {
318  Resize();
319  }
320  int num = RuntimeHelpers.GetHashCode(key) & int.MaxValue;
321  int num2 = num % _buckets.Length;
322  int freeList = _freeList;
323  _freeList = _entries[freeList].next;
324  _entries[freeList].hashCode = num;
325  _entries[freeList].depHnd = new DependentHandle(key, value);
326  _entries[freeList].next = _buckets[num2];
327  _buckets[num2] = freeList;
328  }
329 
330  [SecurityCritical]
331  private void Resize()
332  {
333  int num = _buckets.Length;
334  bool flag = false;
335  int i;
336  for (i = 0; i < _entries.Length; i++)
337  {
338  if (_entries[i].depHnd.IsAllocated && _entries[i].depHnd.GetPrimary() == null)
339  {
340  flag = true;
341  break;
342  }
343  }
344  if (!flag)
345  {
346  num = HashHelpers.GetPrime((_buckets.Length == 0) ? 6 : (_buckets.Length * 2));
347  }
348  int num2 = -1;
349  int[] array = new int[num];
350  for (int j = 0; j < num; j++)
351  {
352  array[j] = -1;
353  }
354  Entry[] array2 = new Entry[num];
355  for (i = 0; i < _entries.Length; i++)
356  {
357  DependentHandle depHnd = _entries[i].depHnd;
358  if (depHnd.IsAllocated && depHnd.GetPrimary() != null)
359  {
360  int num3 = _entries[i].hashCode % num;
361  array2[i].depHnd = depHnd;
362  array2[i].hashCode = _entries[i].hashCode;
363  array2[i].next = array[num3];
364  array[num3] = i;
365  }
366  else
367  {
368  _entries[i].depHnd.Free();
369  array2[i].depHnd = default(DependentHandle);
370  array2[i].next = num2;
371  num2 = i;
372  }
373  }
374  for (; i != array2.Length; i++)
375  {
376  array2[i].depHnd = default(DependentHandle);
377  array2[i].next = num2;
378  num2 = i;
379  }
380  _buckets = array;
381  _entries = array2;
382  _freeList = num2;
383  }
384 
385  [SecurityCritical]
386  private int FindEntry(TKey key)
387  {
388  int num = RuntimeHelpers.GetHashCode(key) & int.MaxValue;
389  for (int num2 = _buckets[num % _buckets.Length]; num2 != -1; num2 = _entries[num2].next)
390  {
391  if (_entries[num2].hashCode == num && _entries[num2].depHnd.GetPrimary() == key)
392  {
393  return num2;
394  }
395  }
396  return -1;
397  }
398 
399  private void VerifyIntegrity()
400  {
401  if (_invalid)
402  {
403  throw new InvalidOperationException(Environment.GetResourceString("CollectionCorrupted"));
404  }
405  }
406 
408  [SecuritySafeCritical]
410  {
411  if (!Environment.HasShutdownStarted && _lock != null)
412  {
413  lock (_lock)
414  {
415  if (!_invalid)
416  {
417  Entry[] entries = _entries;
418  _invalid = true;
419  _entries = null;
420  _buckets = null;
421  int i = 0;
422  for (; i < entries.Length; i++)
423  {
424  entries[i].depHnd.Free();
425  }
426  }
427  }
428  }
429  }
430  }
431 }
The exception that is thrown when a null reference (Nothing in Visual Basic) is passed to a method th...
void Add(TKey key, TValue value)
Adds a key to the table.
TValue GetOrCreateValue(TKey key)
Atomically searches for a specified key in the table and returns the corresponding value....
static int GetHashCode(object o)
Serves as a hash function for a particular object, and is suitable for use in algorithms and data str...
Definition: __Canon.cs:3
ConditionalWeakTable()
Initializes a new instance of the T:System.Runtime.CompilerServices.ConditionalWeakTable`2 class.
Contains methods to create types of objects locally or remotely, or obtain references to existing rem...
Definition: Activator.cs:21
Enables compilers to dynamically attach object fields to managed objects.
delegate TValue CreateValueCallback(TKey key)
Represents a method that creates a non-default value to add as part of a key/value pair to a T:System...
static object CreateInstance(Type type, BindingFlags bindingAttr, Binder binder, object[] args, CultureInfo culture)
Creates an instance of the specified type using the constructor that best matches the specified param...
Definition: Activator.cs:57
Represents a strongly typed list of objects that can be accessed by index. Provides methods to search...
Definition: List.cs:14
TValue GetValue(TKey key, CreateValueCallback createValueCallback)
Atomically searches for a specified key in the table and returns the corresponding value....
bool TryGetValue(TKey key, out TValue value)
Gets the value of the specified key.
bool Remove(TKey key)
Removes a key and its value from the table.
Provides a set of static methods and properties that provide support for compilers....