/* Copyright 2008 The 'A Concurrent Hashtable' development team (http://www.codeplex.com/CH/People/ProjectPeople.aspx) This library is licensed under the GNU Library General Public License (LGPL). You should have received a copy of the license along with the source code. If not, an online copy of the license can be found at http://www.codeplex.com/CH/license. */ using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Collections.Concurrent; namespace Orvid.Concurrent.Collections { internal abstract class InternalWeakDictionaryStrongValueBase : System.Collections.Concurrent.ConcurrentDictionary, IMaintainable, IDictionary, ICollection>, IEnumerable> where IK : ITrashable where SK : struct { protected InternalWeakDictionaryStrongValueBase(int concurrencyLevel, int capacity, IEqualityComparer keyComparer) : base(concurrencyLevel, capacity, keyComparer) { } protected InternalWeakDictionaryStrongValueBase(IEqualityComparer keyComparer) : base(keyComparer) { } protected abstract IK FromExternalKeyToSearchKey(EK externalKey); protected abstract IK FromExternalKeyToStorageKey(EK externalKey); protected abstract IK FromStackKeyToSearchKey(SK externalKey); protected abstract IK FromStackKeyToStorageKey(SK externalKey); protected abstract bool FromInternalKeyToExternalKey(IK internalKey, out EK externalKey); protected abstract bool FromInternalKeyToStackKey(IK internalKey, out SK externalKey); #region IMaintainable Members void IMaintainable.DoMaintenance() { foreach (var kvp in (IEnumerable>)this) if (kvp.Key.IsGarbage) { EV value; base.TryRemove(kvp.Key, out value); } } #endregion #region IDictionary,TValue> Members void IDictionary.Add(EK key, EV value) { ((IDictionary)this).Add(FromExternalKeyToStorageKey(key), value); } bool IDictionary.ContainsKey(EK key) { return ((IDictionary)this).ContainsKey(FromExternalKeyToSearchKey(key)); } ICollection IDictionary.Keys { get { return new TransformedCollection { _source = ((IEnumerable>)this).Select(kvp => kvp.Key) }; } } bool IDictionary.Remove(EK key) { return ((IDictionary)this).Remove(FromExternalKeyToSearchKey(key)); } bool IDictionary.TryGetValue(EK key, out EV value) { return base.TryGetValue(FromExternalKeyToSearchKey(key), out value); } ICollection IDictionary.Values { get { return new TransformedCollection { _source = ((IEnumerable>)this).Select(kvp => kvp.Value) }; } } EV IDictionary.this[EK key] { get { return ((IDictionary)this)[FromExternalKeyToSearchKey(key)]; } set { ((IDictionary)this)[FromExternalKeyToStorageKey(key)] = value; } } #endregion #region ICollection,TValue>> Members void ICollection>.Add(KeyValuePair item) { ((IDictionary)this).Add(item.Key, item.Value); } void ICollection>.Clear() { base.Clear(); } bool ICollection>.Contains(KeyValuePair item) { return ((IDictionary)this).Contains(new KeyValuePair(FromExternalKeyToSearchKey(item.Key), item.Value)); } //HIERO: void ICollection>.CopyTo(KeyValuePair[] array, int arrayIndex) { if (array == null) throw new ArgumentNullException("array"); if (arrayIndex < 0 || arrayIndex > array.Length) throw new IndexOutOfRangeException(); int i = 0; int end = array.Length - arrayIndex; var buffer = new KeyValuePair[end]; using (var it = ((IEnumerable>)this).GetEnumerator()) while (it.MoveNext()) { if (i == end) throw new ArgumentException(); buffer[i++] = it.Current; } buffer.CopyTo(array, arrayIndex); } int ICollection>.Count { get { int ct = 0; using (var it = ((IEnumerable>)this).GetEnumerator()) while (it.MoveNext()) ++ct; return ct; } } bool ICollection>.IsReadOnly { get { return false; } } bool ICollection>.Remove(KeyValuePair item) { return RemoveIKVP(FromExternalKeyToSearchKey(item.Key), item.Value) ; } #endregion #region IEnumerable> Members public new IEnumerator> GetEnumerator() { foreach (var kvp in (IEnumerable>)this) { EK externalKey; if ( FromInternalKeyToExternalKey(kvp.Key, out externalKey) ) yield return new KeyValuePair(externalKey, kvp.Value); else //boyscout ((ICollection>)this).Remove(kvp); } } #endregion public bool ContainsKey(SK key) { return ((IDictionary)this).ContainsKey(FromStackKeyToSearchKey(key)); } public bool TryGetValue(SK key, out EV value) { return ((IDictionary)this).TryGetValue(FromStackKeyToSearchKey(key), out value); } public EV GetItem(SK key) { return ((IDictionary)this)[FromStackKeyToStorageKey(key)]; } public void SetItem(SK key, EV value) { ((IDictionary)this)[FromStackKeyToStorageKey(key)] = value; } public new bool IsEmpty { get { return !((ICollection>)this).GetEnumerator().MoveNext(); } } public EV AddOrUpdate(SK key, Func addValueFactory, Func updateValueFactory) { return base.AddOrUpdate( FromStackKeyToStorageKey(key), sKey => addValueFactory(key), (sKey, oldValue) => { SK oldKey; if (FromInternalKeyToStackKey(sKey, out oldKey)) return updateValueFactory(oldKey, oldValue); else { //boyscout RemoveIKVP(sKey, oldValue); return addValueFactory(key); } } ) ; } private bool RemoveIKVP(IK sKey, EV oldValue) { return ((ICollection>)this).Remove(new KeyValuePair(sKey, oldValue)); } public EV AddOrUpdate(SK key, EV addValue, Func updateValueFactory) { return AddOrUpdate( FromStackKeyToStorageKey(key), addValue, (sKey, oldValue) => { SK oldKey; if (FromInternalKeyToStackKey(sKey, out oldKey)) return updateValueFactory(oldKey, oldValue); else { //boyscout RemoveIKVP(sKey, oldValue); return addValue; } } ) ; } public EV GetOrAdd(SK key, EV value) { return base.GetOrAdd(FromStackKeyToStorageKey(key), value); } public EV GetOrAdd(SK key, Func valueFactory) { EV hold; return this.TryGetValue(key, out hold) ? hold : GetOrAdd(key, valueFactory(key)); } public new KeyValuePair[] ToArray() { return ((IEnumerable>)this).ToArray(); } public bool TryAdd(SK key, EV value) { return base.TryAdd(FromStackKeyToStorageKey(key), value); } public bool TryRemove(SK key, out EV value) { return base.TryRemove(FromStackKeyToSearchKey(key), out value); } public bool TryUpdate(SK key, EV newValue, EV comparisonValue) { return base.TryUpdate(FromStackKeyToSearchKey(key), newValue, comparisonValue); } public List> GetContents() { return ((IEnumerable>)this).ToList(); } public void InsertContents(IEnumerable> collection) { if (null == collection) throw new ArgumentNullException("collection"); foreach (var kvp in collection) ((IDictionary)this).Add(kvp); } } }