PageRenderTime 197ms CodeModel.GetById 7ms RepoModel.GetById 0ms app.codeStats 0ms

/IronPython_1_0/Src/IronPython/Runtime/WeakHash.cs

#
C# | 294 lines | 215 code | 58 blank | 21 comment | 31 complexity | eb2cc1abd912db0030e6de7c1fe8d41e MD5 | raw file
Possible License(s): GPL-2.0, MPL-2.0-no-copyleft-exception, CPL-1.0, CC-BY-SA-3.0, BSD-3-Clause, ISC, AGPL-3.0, LGPL-2.1, Apache-2.0
  1. /* **********************************************************************************
  2. *
  3. * Copyright (c) Microsoft Corporation. All rights reserved.
  4. *
  5. * This source code is subject to terms and conditions of the Shared Source License
  6. * for IronPython. A copy of the license can be found in the License.html file
  7. * at the root of this distribution. If you can not locate the Shared Source License
  8. * for IronPython, please send an email to ironpy@microsoft.com.
  9. * By using this source code in any fashion, you are agreeing to be bound by
  10. * the terms of the Shared Source License for IronPython.
  11. *
  12. * You must not remove this notice, or any other, from this software.
  13. *
  14. * **********************************************************************************/
  15. using System;
  16. using System.Collections.Generic;
  17. using System.Text;
  18. using System.Runtime.InteropServices;
  19. using System.Runtime.CompilerServices;
  20. using IronPython.Runtime.Operations;
  21. namespace IronPython.Runtime {
  22. class WeakHash<TKey, TValue> : IDictionary<TKey, TValue> {
  23. // The one and only comparer instance.
  24. static readonly IEqualityComparer<object> comparer = new WeakComparer<object>();
  25. IDictionary<object, TValue> dict = new Dictionary<object, TValue>();
  26. int version, cleanupVersion, cleanupGC;
  27. public WeakHash() {
  28. }
  29. #region IDictionary<TKey,TValue> Members
  30. public void Add(TKey key, TValue value) {
  31. CheckCleanup();
  32. dict.Add(new WeakObject<TKey>(key), value);
  33. }
  34. public bool ContainsKey(TKey key) {
  35. return dict.ContainsKey(key);
  36. }
  37. public ICollection<TKey> Keys {
  38. get { throw new NotImplementedException(); }
  39. }
  40. public bool Remove(TKey key) {
  41. return dict.Remove(key);
  42. }
  43. public bool TryGetValue(TKey key, out TValue value) {
  44. return dict.TryGetValue(key, out value);
  45. }
  46. public ICollection<TValue> Values {
  47. get { throw new Exception("The method or operation is not implemented."); }
  48. }
  49. public TValue this[TKey key] {
  50. get {
  51. return dict[key];
  52. }
  53. set {
  54. dict[new WeakObject<TKey>(key)] = value;
  55. }
  56. }
  57. void CheckCleanup() {
  58. version++;
  59. long change = version - cleanupVersion;
  60. // Cleanup the table if it is a while since we have done it last time.
  61. // Take the size of the table into account.
  62. if (change > 1234 + dict.Count / 2) {
  63. // It makes sense to do the cleanup only if a GC has happened in the meantime.
  64. // WeakReferences can become zero only during the GC.
  65. int currentGC = GC.CollectionCount(0);
  66. if (currentGC != cleanupGC) {
  67. Cleanup();
  68. cleanupVersion = version;
  69. cleanupGC = currentGC;
  70. } else {
  71. cleanupVersion += 1234;
  72. }
  73. }
  74. }
  75. void Cleanup() {
  76. int liveCount = 0;
  77. int emptyCount = 0;
  78. foreach (WeakObject<TKey> w in dict.Keys) {
  79. if (w.Target != null)
  80. liveCount++;
  81. else
  82. emptyCount++;
  83. }
  84. // Rehash the table if there is a significant number of empty slots
  85. if (emptyCount > liveCount / 4) {
  86. Dictionary<object, TValue> newtable = new Dictionary<object, TValue>(liveCount + liveCount / 4, comparer);
  87. foreach (WeakObject<TKey> w in dict.Keys) {
  88. object target = w.Target;
  89. if (target != null)
  90. newtable[w] = dict[w];
  91. GC.KeepAlive(target);
  92. }
  93. dict = newtable;
  94. }
  95. }
  96. #endregion
  97. #region ICollection<KeyValuePair<TKey,TValue>> Members
  98. public void Add(KeyValuePair<TKey, TValue> item) {
  99. throw new Exception("The method or operation is not implemented.");
  100. }
  101. public void Clear() {
  102. throw new Exception("The method or operation is not implemented.");
  103. }
  104. public bool Contains(KeyValuePair<TKey, TValue> item) {
  105. throw new Exception("The method or operation is not implemented.");
  106. }
  107. public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex) {
  108. throw new Exception("The method or operation is not implemented.");
  109. }
  110. public int Count {
  111. get { throw new Exception("The method or operation is not implemented."); }
  112. }
  113. public bool IsReadOnly {
  114. get { throw new Exception("The method or operation is not implemented."); }
  115. }
  116. public bool Remove(KeyValuePair<TKey, TValue> item) {
  117. throw new Exception("The method or operation is not implemented.");
  118. }
  119. #endregion
  120. #region IEnumerable<KeyValuePair<TKey,TValue>> Members
  121. public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator() {
  122. throw new Exception("The method or operation is not implemented.");
  123. }
  124. #endregion
  125. #region IEnumerable Members
  126. System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() {
  127. throw new Exception("The method or operation is not implemented.");
  128. }
  129. #endregion
  130. }
  131. internal class WeakObject<T> {
  132. WeakReference weakReference;
  133. int hashCode;
  134. public WeakObject(T obj) {
  135. weakReference = new WeakReference(obj, true);
  136. hashCode = RuntimeHelpers.GetHashCode(obj);
  137. }
  138. public T Target {
  139. get {
  140. return (T)weakReference.Target;
  141. }
  142. }
  143. public override int GetHashCode() {
  144. return hashCode;
  145. }
  146. public override bool Equals(object obj) {
  147. return Target.Equals(obj);
  148. }
  149. }
  150. // WeakComparer treats WeakObject as transparent envelope
  151. sealed class WeakComparer<T> : IEqualityComparer<T> {
  152. bool IEqualityComparer<T>.Equals(T x, T y) {
  153. WeakObject<T> wx = x as WeakObject<T>;
  154. if (wx != null)
  155. x = wx.Target;
  156. WeakObject<T> wy = y as WeakObject<T>;
  157. if (wy != null)
  158. y = wy.Target;
  159. return Object.Equals(x, y);
  160. }
  161. int IEqualityComparer<T>.GetHashCode(T obj) {
  162. WeakObject<T> wobj = obj as WeakObject<T>;
  163. if (wobj != null)
  164. return wobj.GetHashCode();
  165. return RuntimeHelpers.GetHashCode(obj);
  166. }
  167. }
  168. sealed class HybridMapping<T> {
  169. Dictionary<int, object> dict = new Dictionary<int, object>();
  170. readonly Object synchObject = new Object();
  171. readonly int SIZE = 4096;
  172. int current = 0;
  173. public int WeakAdd(T value) {
  174. lock (synchObject) {
  175. int saved = current;
  176. while (dict.ContainsKey(current)) {
  177. current = (current + 1) % SIZE;
  178. if (current == saved)
  179. throw Ops.SystemError("HybridMapping is full");
  180. }
  181. dict.Add(current, new WeakObject<T>(value));
  182. return current;
  183. }
  184. }
  185. public int StrongAdd(T value) {
  186. lock (synchObject) {
  187. int saved = current;
  188. while (dict.ContainsKey(current)) {
  189. current = (current + 1) % SIZE;
  190. if (current == saved)
  191. throw Ops.SystemError("HybridMapping is full");
  192. }
  193. dict.Add(current, value);
  194. return current;
  195. }
  196. }
  197. public T GetObjectFromId(int id) {
  198. object ret;
  199. if (dict.TryGetValue(id, out ret)) {
  200. if (ret is WeakObject<T>) {
  201. return ((WeakObject<T>)ret).Target;
  202. }
  203. if (ret is T) {
  204. return (T)ret;
  205. }
  206. throw Ops.SystemError("Unexpected dictionary content: type {0}", ret.GetType());
  207. } else
  208. return default(T);
  209. }
  210. public int GetIdFromObject(T value) {
  211. lock (synchObject) {
  212. foreach (KeyValuePair<int, object> kv in dict) {
  213. if (kv.Value is WeakObject<T>) {
  214. object target = ((WeakObject<T>)kv.Value).Target;
  215. if (target != null && target.Equals(value))
  216. return kv.Key;
  217. } else if (kv.Value is T) {
  218. object target = (T)(kv.Value);
  219. if (target.Equals(value))
  220. return kv.Key;
  221. }
  222. }
  223. }
  224. return -1;
  225. }
  226. public void RemoveOnId(int id) {
  227. try {
  228. dict.Remove(id);
  229. } catch { }
  230. }
  231. public void RemoveOnObject(T value) {
  232. int id = GetIdFromObject(value);
  233. RemoveOnId(id);
  234. }
  235. }
  236. }