using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Loyc.Essentials;
namespace Loyc.Collections
{
/// <summary>A dictionary with weak keys.</summary>
/// <remarks>Source: datavault project. License: Apache License 2.0</remarks>
public sealed class WeakKeyDictionary<TKey, TValue> : BaseDictionary<TKey, TValue>
where TKey : class
{
private Dictionary<object, TValue> dictionary;
private WeakKeyComparer<TKey> comparer;
public WeakKeyDictionary()
: this(0, null) { }
public WeakKeyDictionary(int capacity)
: this(capacity, null) { }
public WeakKeyDictionary(IEqualityComparer<TKey> comparer)
: this(0, comparer) { }
public WeakKeyDictionary(int capacity, IEqualityComparer<TKey> comparer)
{
this.comparer = new WeakKeyComparer<TKey>(comparer);
this.dictionary = new Dictionary<object, TValue>(capacity, this.comparer);
}
// WARNING: The count returned here may include entries for which
// key value objects have already been garbage collected.
// Call RemoveCollectedEntries to weed out collected
// entries and update the count accordingly.
public override int Count
{
get { return this.dictionary.Count; }
}
public override void Add(TKey key, TValue value)
{
if (key == null) throw new ArgumentNullException("key");
WeakReference<TKey> weakKey = new WeakKeyReference<TKey>(key, this.comparer);
this.dictionary.Add(weakKey, value);
}
public override bool ContainsKey(TKey key)
{
return this.dictionary.ContainsKey(key);
}
public override bool Remove(TKey key)
{
return this.dictionary.Remove(key);
}
public override bool TryGetValue(TKey key, out TValue value)
{
return this.dictionary.TryGetValue(key, out value);
}
protected override void SetValue(TKey key, TValue value)
{
WeakReference<TKey> weakKey = new WeakKeyReference<TKey>(key, this.comparer);
this.dictionary[weakKey] = value;
}
public override void Clear()
{
this.dictionary.Clear();
}
public override IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
{
foreach (KeyValuePair<object, TValue> kvp in this.dictionary)
{
WeakReference<TKey> weakKey = (WeakReference<TKey>)(kvp.Key);
TKey key = weakKey.Target;
TValue value = kvp.Value;
if (weakKey.IsAlive)
{
yield return new KeyValuePair<TKey, TValue>(key, value);
}
}
}
// Removes the left-over weak references for entries in the dictionary
// whose key has already been reclaimed by the garbage
// collector. This will reduce the dictionary's Count by the number
// of dead key-value pairs that were eliminated.
public void RemoveCollectedEntries()
{
List<object> toRemove = null;
foreach (KeyValuePair<object, TValue> pair in this.dictionary)
{
WeakReference<TKey> weakKey = (WeakReference<TKey>)(pair.Key);
if (!weakKey.IsAlive)
{
if (toRemove == null)
toRemove = new List<object>();
toRemove.Add(weakKey);
}
}
if (toRemove != null)
{
foreach (object key in toRemove)
this.dictionary.Remove(key);
}
}
}
}