PageRenderTime 44ms CodeModel.GetById 18ms RepoModel.GetById 1ms app.codeStats 0ms

/Microsoft.Scripting.Core/Utils/WeakUniqueSet.cs

https://bitbucket.org/stefanrusek/xronos
C# | 189 lines | 127 code | 32 blank | 30 comment | 27 complexity | 4834dbe07bbff968050743d8784c8eae MD5 | raw file
  1. /* ****************************************************************************
  2. *
  3. * Copyright (c) Microsoft Corporation.
  4. *
  5. * This source code is subject to terms and conditions of the Microsoft Public License. A
  6. * copy of the license can be found in the License.html file at the root of this distribution. If
  7. * you cannot locate the Microsoft Public License, please send an email to
  8. * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
  9. * by the terms of the Microsoft Public License.
  10. *
  11. * You must not remove this notice, or any other, from this software.
  12. *
  13. *
  14. * ***************************************************************************/
  15. using System; using Microsoft;
  16. using System.Collections;
  17. using System.Collections.Generic;
  18. using System.Diagnostics;
  19. using System.Threading;
  20. #if CODEPLEX_40
  21. namespace System.Dynamic.Utils {
  22. #else
  23. namespace Microsoft.Scripting.Utils {
  24. #endif
  25. internal sealed class WeakUniqueSet<T> where T : class {
  26. private readonly Dictionary<int, WeakLinkedList> hashTable = new Dictionary<int, WeakLinkedList>();
  27. internal T GetUniqueFor(T obj) {
  28. CheckCleanup();
  29. int hash = obj.GetHashCode();
  30. WeakLinkedList list;
  31. // LOCK table to get/set the list
  32. lock (hashTable) {
  33. if (!hashTable.TryGetValue(hash, out list)) {
  34. hashTable[hash] = list = new WeakLinkedList();
  35. list.Add(obj);
  36. return obj;
  37. }
  38. }
  39. var objType = obj.GetType();
  40. // LOCK list to iterate
  41. lock (list) {
  42. foreach (var current in list) {
  43. Debug.Assert(current != null);
  44. if (current.GetType() == objType && current.Equals(obj)) {
  45. return current as T;
  46. }
  47. }
  48. list.Add(obj);
  49. }
  50. return obj;
  51. }
  52. #region TableCleanup
  53. int sinceLastChange;
  54. #if SILVERLIGHT // GC
  55. WeakReference cleanupGC = new WeakReference(new object());
  56. #else
  57. int cleanupGC = 0;
  58. #endif
  59. /// <summary>
  60. /// Check if any of the keys have gotten collected
  61. /// </summary>
  62. private void CheckCleanup() {
  63. sinceLastChange++;
  64. // Cleanup the table if it is a while since we have done it last time.
  65. // Take the size of the table into account.
  66. if (sinceLastChange > 1234 + hashTable.Count / 2) {
  67. if (Interlocked.Exchange(ref sinceLastChange, 0) < 1234) {
  68. return; // someone is already cleaning
  69. };
  70. bool HasCollectionSinceLastCleanup;
  71. #if SILVERLIGHT // GC.CollectionCount
  72. HasCollectionSinceLastCleanup = !cleanupGC.IsAlive;
  73. if (HasCollectionSinceLastCleanup) cleanupGC = new WeakReference(new object());
  74. #else
  75. int currentGC = GC.CollectionCount(2);
  76. HasCollectionSinceLastCleanup = currentGC != cleanupGC;
  77. if (HasCollectionSinceLastCleanup) cleanupGC = currentGC;
  78. #endif
  79. if (HasCollectionSinceLastCleanup) {
  80. CleanTable();
  81. }
  82. }
  83. }
  84. // remove empty lists.
  85. internal void CleanTable() {
  86. var keys = hashTable.Keys.ToReadOnly();
  87. // LOCK table to get lists.
  88. lock (hashTable) {
  89. foreach (int hash in keys) {
  90. WeakLinkedList list = hashTable[hash];
  91. int cnt;
  92. // LOCK list to iterate.
  93. lock (list) {
  94. cnt = list.Count();
  95. }
  96. if (cnt == 0) {
  97. hashTable.Remove(hash);
  98. }
  99. }
  100. }
  101. }
  102. #endregion
  103. }
  104. // self-compacting list of weak values
  105. internal class WeakLinkedList : IEnumerable {
  106. private class Node {
  107. internal Node next;
  108. internal readonly WeakReference value;
  109. internal Node(object item) {
  110. value = new WeakReference(item);
  111. }
  112. }
  113. private Node _head;
  114. internal void Add(object item) {
  115. Node newNode = new Node(item);
  116. newNode.next = _head;
  117. _head = newNode;
  118. }
  119. // O(n) operation. will drop dead nodes and report number of live ones.
  120. internal int Count() {
  121. int i = 0;
  122. foreach (var cur in this) {
  123. i++;
  124. }
  125. return i;
  126. }
  127. // enumerator for the list. Skips and drops dead nodes.
  128. IEnumerator IEnumerable.GetEnumerator() {
  129. Node cur1 = _head;
  130. object value = null;
  131. while (cur1 != null && (value = cur1.value.Target) == null) {
  132. cur1 = cur1.next;
  133. }
  134. // Invariant: cur1 ponts to null or the first live node and value has its Target.
  135. if (cur1 == null) {
  136. _head = cur1;
  137. yield break;
  138. }
  139. yield return value;
  140. Node cur2;
  141. do {
  142. // Invariant: cur1 ponts to last known live node,
  143. cur2 = cur1.next;
  144. while (cur2 != null && (value = cur2.value.Target) == null) {
  145. cur2 = cur2.next;
  146. }
  147. // Invariant: cur2 ponts to null or the next live node and value has its Target.
  148. if (cur2 == null) {
  149. cur1.next = cur2;
  150. yield break;
  151. }
  152. yield return value;
  153. cur1 = cur2;
  154. } while (cur1 != null);
  155. }
  156. }
  157. }