Adding reference source for part of Workflow Foundation
[mono.git] / mcs / class / referencesource / System.Activities.Presentation / System.Activities.Presentation / System / Activities / Presentation / Model / WeakKeyDictionary.cs.back
diff --git a/mcs/class/referencesource/System.Activities.Presentation/System.Activities.Presentation/System/Activities/Presentation/Model/WeakKeyDictionary.cs.back b/mcs/class/referencesource/System.Activities.Presentation/System.Activities.Presentation/System/Activities/Presentation/Model/WeakKeyDictionary.cs.back
new file mode 100644 (file)
index 0000000..2eeb1bc
--- /dev/null
@@ -0,0 +1,424 @@
+//----------------------------------------------------------------
+// Copyright (c) Microsoft Corporation.  All rights reserved.
+//----------------------------------------------------------------
+namespace System.Activities.Presentation.Model
+{
+
+    using System;
+    using System.Collections;
+    using System.Collections.Generic;
+    using System.Diagnostics.CodeAnalysis;
+    using System.Text;
+    using System.Threading;
+    using System.Runtime.InteropServices;
+
+    internal class WeakKeyDictionary<K, V> : IDictionary<K, V> 
+    {
+        private Dictionary<WeakKey, V> _internalDictionary;
+        private object _[....] = new object();
+        private bool _finalized;
+
+        internal WeakKeyDictionary() 
+        {
+            _internalDictionary = new Dictionary<WeakKey, V>(new WeakComparer());
+        }
+
+        public WeakKeyDictionary(IEqualityComparer<K> comparer)  
+        {
+            _internalDictionary = new Dictionary<WeakKey, V>(new WeakComparer(comparer));
+        }
+
+        // FXCop: this is not empty; we need to mark this so we know if a key
+        // still has an active dictionary at its finalization.
+        [SuppressMessage("Microsoft.Performance", "CA1821:RemoveEmptyFinalizers")]
+        ~WeakKeyDictionary() 
+        {
+            _finalized = true;
+        }
+
+        public ICollection<K> Keys 
+        {
+            get 
+            {
+                List<K> list = new List<K>();
+                lock (_[....]) 
+                {
+                    foreach (WeakKey key in _internalDictionary.Keys) 
+                    {
+                        object k = key.Target;
+                        if (k != null)
+                        {
+                            list.Add((K)k);
+                        }
+                    }
+                }
+                return list;
+            }
+        }
+
+        public ICollection<V> Values 
+        {
+            get {
+                lock (_[....]) {
+                    // make a copy of the values, so the during GC, the returned collection does not change.
+                    return new List<V>(_internalDictionary.Values);
+                }
+            }
+        }
+
+        public int Count 
+        {
+            get 
+            {
+                // Ensure a fairly accurate count.
+                ScavangeLostKeys();
+                lock (_[....]) 
+                {
+                    return _internalDictionary.Count;
+                }
+            }
+        }
+
+        public bool IsReadOnly 
+        {
+            get {
+                return false;
+            }
+        }
+
+        [SuppressMessage("Microsoft.Usage", "CA1806:DoNotIgnoreMethodResults", Justification = "LostKeyFinder's purpose is to get garbage collected as soon as posible")]
+        public V this[K key] 
+        {
+            get {
+                lock (_[....]) {
+                    return _internalDictionary[new WeakKey(key)];
+                }
+            }
+            set 
+            {
+                WeakKey k = new WeakKey(key);
+                lock (_[....]) 
+                {
+                    _internalDictionary[k] = value;
+                }
+                // This looks a bit weird but the purpose of the lost key finder is to execute
+                // code in some future garbage collection phase so we immediately create some garbage.
+                new LostKeyFinder(this, k);
+            }
+        }
+
+        public bool TryGetValue(K key, out V value) 
+        {
+            WeakKey k = new WeakKey(key);
+            lock (_[....]) 
+            {
+                return _internalDictionary.TryGetValue(k, out value);
+            }
+        }
+
+        [SuppressMessage("Microsoft.Usage", "CA1806:DoNotIgnoreMethodResults", Justification = "LostKeyFinder's purpose is to get garbage collected as soon as posible")]
+        public void Add(K key, V value) 
+        {
+            WeakKey k = new WeakKey(key);
+            lock (_[....]) 
+            {
+                _internalDictionary.Add(k, value);
+            }
+            // This looks a bit weird but the purpose of the lost key finder is to execute
+            // code in some future garbage collection phase so we immediately create some garbage.
+            new LostKeyFinder(this, k);
+
+        }
+
+        public bool ContainsKey(K key) 
+        {
+            return _internalDictionary.ContainsKey(new WeakKey(key));
+        }
+
+        public bool Remove(K key) 
+        {
+            lock (_[....]) 
+            {
+                return _internalDictionary.Remove(new WeakKey(key));
+            }
+        }
+
+        public void Add(KeyValuePair<K, V> item) 
+        {
+            Add(item.Key, item.Value);
+        }
+
+        public void Clear() 
+        {
+            lock (_[....]) 
+            {
+                _internalDictionary.Clear();
+            }
+        }
+
+        public bool Contains(KeyValuePair<K, V> item) 
+        {
+            V value;
+            bool result;
+            lock (_[....]) 
+            {
+                result = _internalDictionary.TryGetValue(new WeakKey(item.Key), out value);
+            }
+            if (result)
+            {
+                return value.Equals(item.Value);
+            }
+            else
+            {
+                return false;
+            }
+        }
+
+        public void CopyTo(KeyValuePair<K, V>[] array, int arrayIndex) 
+        {
+            lock (_[....]) 
+            {
+                foreach (KeyValuePair<WeakKey, V> item in _internalDictionary) 
+                {
+                    KeyValuePair<K, V> kv = new KeyValuePair<K, V>((K)item.Key.Target, item.Value);
+                    array[arrayIndex] = kv;
+                    arrayIndex++;
+                }
+            }
+        }
+
+        public bool Remove(KeyValuePair<K, V> item) 
+        {
+            WeakKey key = new WeakKey(item.Key);
+            lock (_[....]) 
+            {
+                return _internalDictionary.Remove(key);
+            }
+        }
+
+
+
+
+
+        public IEnumerator<KeyValuePair<K, V>> GetEnumerator() 
+        {
+            List<WeakKey> lostKeys = null;
+            lock (_[....]) 
+            {
+                foreach (KeyValuePair<WeakKey, V> item in _internalDictionary) 
+                {
+                    object k = item.Key.Target;
+                    if (k != null)
+                    {
+                        yield return new KeyValuePair<K, V>((K)k, item.Value);
+                    }
+                    else 
+                    {
+                        if (lostKeys == null)
+                        {
+                            lostKeys = new List<WeakKey>();
+                        }
+                        lostKeys.Add(item.Key);
+                    }
+                }
+            }
+            // Recover any lost keys.
+            if (lostKeys != null)
+            {
+                lock (_[....]) 
+                {
+                    foreach (WeakKey key in lostKeys)
+                    {
+                        _internalDictionary.Remove(key);
+                    }
+                }
+            }
+        }
+
+
+
+
+        IEnumerator IEnumerable.GetEnumerator() 
+        {
+            return GetEnumerator();
+        }
+
+
+
+        private void ScavangeLostKeys() 
+        {
+            List<WeakKey> lostKeys = null;
+            lock (_[....]) 
+            {
+                foreach (WeakKey key in _internalDictionary.Keys)
+                {
+                    if (!key.IsAlive) 
+                    {
+                        if (lostKeys == null)
+                        {
+                            lostKeys = new List<WeakKey>();
+                        }
+                        lostKeys.Add(key);
+                    }
+                }
+            }
+            if (lostKeys != null)
+            {
+                lock (_[....]) 
+                {
+                    foreach (WeakKey key in lostKeys)
+                    {
+                        _internalDictionary.Remove(key);
+                    }
+                }
+            }
+        }
+
+        private class WeakKey : WeakReference 
+        {
+            private int _hashCode;
+            // private GCHandle _gcHandle;
+
+            public WeakKey(K key)
+                : base(key, true) 
+            {
+                _hashCode = key.GetHashCode();
+                // Keep the key alive until it is explicitly collected
+                // _gcHandle = GCHandle.Alloc(this);
+            }
+
+            internal void Release() 
+            {
+                // _gcHandle.Free();
+            }
+
+            public override int GetHashCode() 
+            {
+                return _hashCode;
+            }
+
+            public override bool Equals(object obj) 
+            {
+                if (obj == null)
+                {
+                    return false;
+                }
+                if (obj.GetHashCode() != _hashCode)
+                {
+                    return false;
+                }
+                if (obj != this && (!IsAlive || !obj.Equals(Target)))
+                {
+                    return false;
+                }
+                return true;
+            }
+        }
+
+        private class WeakComparer : IEqualityComparer<WeakKey> 
+        {
+
+            private IEqualityComparer<K> _comparer;
+            public WeakComparer() 
+            {
+            }
+
+            public WeakComparer(IEqualityComparer<K> comparer) 
+            {
+                _comparer = comparer;
+            }
+
+            public bool Equals(WeakKey x, WeakKey y) 
+            {
+                if (x.GetHashCode() != y.GetHashCode())
+                {
+                    return false;
+                }
+                if (object.ReferenceEquals(x, y))
+                {
+                    return true;
+                }
+                object ref1 = x.Target;
+                if (ref1 == null)
+                {
+                    return false;
+                }
+                object ref2 = y.Target;
+                if (ref2 == null)
+                {
+                    return false;
+                }
+
+                if (_comparer != null) 
+                {
+                    return _comparer.Equals((K)ref1, (K)ref2);
+                }
+                else 
+                {
+                    return ref1.Equals(ref2);
+                }
+            }
+
+            public int GetHashCode(WeakKey obj) 
+            {
+                return obj.GetHashCode();
+            }
+        }
+
+        private class LostKeyFinder 
+        {
+            WeakKeyDictionary<K, V> _dictionary;
+            WeakKey _key;
+
+            public LostKeyFinder(WeakKeyDictionary<K, V> dictionary, WeakKey key) 
+            {
+                _dictionary = dictionary;
+                _key = key;
+            }
+
+            ~LostKeyFinder() 
+            {
+                if (_dictionary._finalized || _key == null) 
+                {
+                    if (_key != null) 
+                    {
+                        _key.Release();
+                        _key = null;
+                    }
+                    return;
+                }
+                // if (!_key.IsAlive) {
+                if (_key.Target == null) 
+                {
+                    bool locked = false;
+                    try
+                    {
+                        locked = Monitor.TryEnter(_dictionary._[....]);
+                        _dictionary._internalDictionary.Remove(_key);
+                    }
+                    finally
+                    {
+                        if (locked)
+                        {
+                            Monitor.Exit(_dictionary._[....]);
+                        }
+                    }
+
+                    if (locked)
+                    {
+                        _key.Release();
+                        _key = null;
+                    }
+                    else
+                    {
+                        GC.ReRegisterForFinalize(this);
+                    }
+                }
+                else if (_dictionary._internalDictionary.ContainsKey(_key))
+                {
+                    GC.ReRegisterForFinalize(this);
+                }
+            }
+        }
+    }
+}