mirror of
https://github.com/danbulant/Cosmos
synced 2026-05-19 04:18:43 +00:00
477 lines
16 KiB
C#
477 lines
16 KiB
C#
/*
|
|
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;
|
|
|
|
#if !SILVERLIGHT
|
|
using System.Collections.Concurrent;
|
|
#endif
|
|
|
|
namespace Orvid.Concurrent.Collections
|
|
{
|
|
internal abstract class InternalWeakDictionaryWeakValueBase<IK, IV, EK, EV, SK> : ConcurrentDictionary<IK, IV>, IMaintainable, IDictionary<EK, EV>, ICollection<KeyValuePair<EK, EV>>, IEnumerable<KeyValuePair<EK, EV>>
|
|
where IK : ITrashable
|
|
//For IV we do not use the WeakValueRef struct directly in order to support unittesting.
|
|
where IV : IWeakValueRef<EV>, IEquatable<IV>
|
|
where EV : class
|
|
where SK : struct
|
|
{
|
|
protected InternalWeakDictionaryWeakValueBase(int concurrencyLevel, int capacity, IEqualityComparer<IK> keyComparer)
|
|
#if SILVERLIGHT
|
|
: base(keyComparer)
|
|
#else
|
|
: base(concurrencyLevel, capacity, keyComparer)
|
|
#endif
|
|
{ }
|
|
|
|
protected InternalWeakDictionaryWeakValueBase(IEqualityComparer<IK> 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);
|
|
protected abstract IV FromExternalValueToInternalValue(EV externalValue);
|
|
|
|
bool FromInternalValueToExternalValue(IV internalValue, out EV externalValue)
|
|
{ return internalValue.GetValue(out externalValue); }
|
|
|
|
#region IMaintainable Members
|
|
|
|
void IMaintainable.DoMaintenance()
|
|
{
|
|
foreach (var kvp in (IEnumerable<KeyValuePair<IK, IV>>)this)
|
|
if (kvp.Key.IsGarbage || kvp.Value.IsGarbage)
|
|
((ICollection<KeyValuePair<IK, IV>>)this).Remove(kvp);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region IDictionary<Tuple<TWeakKey1,TStrongKey>,TValue> Members
|
|
|
|
void IDictionary<EK, EV>.Add(EK key, EV value)
|
|
{
|
|
var newItm = FromExternalValueToInternalValue(value);
|
|
|
|
var storedItm =
|
|
base.AddOrUpdate(
|
|
FromExternalKeyToStorageKey(key),
|
|
newItm,
|
|
(sKey, oldItm) =>
|
|
{
|
|
if (!sKey.IsGarbage && !oldItm.IsGarbage)
|
|
return oldItm;
|
|
else
|
|
{
|
|
//boyscout
|
|
RemoveIKVP(sKey, oldItm);
|
|
return newItm;
|
|
}
|
|
}
|
|
)
|
|
;
|
|
|
|
if (!object.ReferenceEquals(newItm.Reference, storedItm.Reference))
|
|
throw new ArgumentException();
|
|
}
|
|
|
|
bool IDictionary<EK, EV>.ContainsKey(EK key)
|
|
{
|
|
EV dummy;
|
|
return ((IDictionary<EK, EV>)this).TryGetValue(key, out dummy);
|
|
}
|
|
|
|
ICollection<EK> IDictionary<EK, EV>.Keys
|
|
{ get { return new TransformedCollection<EK> { _source = ((IEnumerable<KeyValuePair<EK, EV>>)this).Select(kvp => kvp.Key) }; } }
|
|
|
|
bool IDictionary<EK, EV>.Remove(EK key)
|
|
{
|
|
IV itm;
|
|
bool res = this.TryRemove(FromExternalKeyToSearchKey(key), out itm);
|
|
return res && !itm.IsGarbage;
|
|
}
|
|
|
|
bool IDictionary<EK, EV>.TryGetValue(EK key, out EV value)
|
|
{
|
|
IV internalValue;
|
|
IK searchKey = FromExternalKeyToSearchKey(key);
|
|
if (((IDictionary<IK, IV>)this).TryGetValue(searchKey, out internalValue))
|
|
{
|
|
if (FromInternalValueToExternalValue(internalValue, out value))
|
|
return true;
|
|
|
|
//boyscout
|
|
RemoveIKVP(searchKey, internalValue);
|
|
}
|
|
|
|
value = default(EV);
|
|
return false;
|
|
}
|
|
|
|
ICollection<EV> IDictionary<EK, EV>.Values
|
|
{ get { return new TransformedCollection<EV> { _source = ((IEnumerable<KeyValuePair<EK, EV>>)this).Select(kvp => kvp.Value) }; } }
|
|
|
|
EV IDictionary<EK, EV>.this[EK key]
|
|
{
|
|
get
|
|
{
|
|
EV externalValue;
|
|
if (!((IDictionary<EK, EV>)this).TryGetValue(key, out externalValue))
|
|
throw new KeyNotFoundException();
|
|
return externalValue;
|
|
}
|
|
set
|
|
{
|
|
((IDictionary<IK, IV>)this)[FromExternalKeyToStorageKey(key)]
|
|
= FromExternalValueToInternalValue(value);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ICollection<KeyValuePair<Tuple<TWeakKey1,TStrongKey>,TValue>> Members
|
|
|
|
void ICollection<KeyValuePair<EK, EV>>.Add(KeyValuePair<EK, EV> item)
|
|
{ ((IDictionary<EK, EV>)this).Add(item.Key, item.Value); }
|
|
|
|
void ICollection<KeyValuePair<EK, EV>>.Clear()
|
|
{ Clear(); }
|
|
|
|
bool ICollection<KeyValuePair<EK, EV>>.Contains(KeyValuePair<EK, EV> item)
|
|
{
|
|
EV value;
|
|
|
|
if (((IDictionary<EK, EV>)this).TryGetValue(item.Key, out value))
|
|
return EqualityComparer<EV>.Default.Equals(value, item.Value);
|
|
|
|
return false;
|
|
}
|
|
|
|
void ICollection<KeyValuePair<EK, EV>>.CopyTo(KeyValuePair<EK, EV>[] 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<EK, EV>[end];
|
|
|
|
using (var it = ((IEnumerable<KeyValuePair<EK, EV>>)this).GetEnumerator())
|
|
while (it.MoveNext())
|
|
{
|
|
if (i == end)
|
|
throw new ArgumentException();
|
|
|
|
buffer[i++] = it.Current;
|
|
}
|
|
|
|
buffer.CopyTo(array, arrayIndex);
|
|
}
|
|
|
|
int ICollection<KeyValuePair<EK, EV>>.Count
|
|
{
|
|
get
|
|
{
|
|
int ct = 0;
|
|
|
|
using (var it = ((IEnumerable<KeyValuePair<EK, EV>>)this).GetEnumerator())
|
|
while (it.MoveNext())
|
|
++ct;
|
|
|
|
return ct;
|
|
}
|
|
}
|
|
|
|
bool ICollection<KeyValuePair<EK, EV>>.IsReadOnly
|
|
{ get { return false; } }
|
|
|
|
bool ICollection<KeyValuePair<EK, EV>>.Remove(KeyValuePair<EK, EV> item)
|
|
{
|
|
return
|
|
RemoveIKVP(FromExternalKeyToSearchKey(item.Key),FromExternalValueToInternalValue(item.Value))
|
|
;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region IEnumerable<KeyValuePair<EK, EV>> Members
|
|
|
|
public new IEnumerator<KeyValuePair<EK, EV>> GetEnumerator()
|
|
{
|
|
foreach (var kvp in (IEnumerable<KeyValuePair<IK, IV>>)this)
|
|
{
|
|
EK externalKey;
|
|
EV externalValue;
|
|
|
|
if (
|
|
FromInternalKeyToExternalKey(kvp.Key, out externalKey)
|
|
&& FromInternalValueToExternalValue(kvp.Value, out externalValue)
|
|
)
|
|
yield return new KeyValuePair<EK, EV>(externalKey, externalValue);
|
|
else
|
|
//boyscout
|
|
((ICollection<KeyValuePair<IK, IV>>)this).Remove(kvp);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
public bool ContainsKey(SK key)
|
|
{
|
|
IV itm;
|
|
return ((IDictionary<IK, IV>)this).TryGetValue(FromStackKeyToSearchKey(key), out itm) && !itm.IsGarbage;
|
|
}
|
|
|
|
public bool TryGetValue(SK key, out EV value)
|
|
{
|
|
IV itm;
|
|
IK internalKey = FromStackKeyToSearchKey(key);
|
|
|
|
if (((IDictionary<IK, IV>)this).TryGetValue(FromStackKeyToSearchKey(key), out itm))
|
|
{
|
|
if (FromInternalValueToExternalValue(itm, out value))
|
|
return true;
|
|
|
|
//boyscout
|
|
RemoveIKVP(internalKey, itm);
|
|
}
|
|
|
|
value = default(EV);
|
|
return false;
|
|
}
|
|
|
|
public EV GetItem(SK key)
|
|
{
|
|
EV externalValue;
|
|
if (!TryGetValue(key, out externalValue))
|
|
throw new KeyNotFoundException();
|
|
return externalValue;
|
|
}
|
|
|
|
public void SetItem(SK key, EV value)
|
|
{
|
|
((IDictionary<IK, IV>)this)[FromStackKeyToStorageKey(key)]
|
|
= FromExternalValueToInternalValue(value);
|
|
}
|
|
|
|
public new bool IsEmpty
|
|
{ get { return !((ICollection<KeyValuePair<EK, EV>>)this).GetEnumerator().MoveNext(); } }
|
|
|
|
public EV AddOrUpdate(SK key, Func<SK, EV> addValueFactory, Func<SK, EV, EV> updateValueFactory)
|
|
{
|
|
while (true)
|
|
{
|
|
//variables to hold references to newly created values so they will remain alive
|
|
EV hold1;
|
|
EV hold2;
|
|
|
|
if (
|
|
FromInternalValueToExternalValue(
|
|
base.AddOrUpdate(
|
|
FromStackKeyToStorageKey(key),
|
|
sKey => FromExternalValueToInternalValue(hold1 = addValueFactory(key)),
|
|
(sKey, oldItm) =>
|
|
{
|
|
EV oldValue;
|
|
SK oldKey;
|
|
EV newValue;
|
|
|
|
if (
|
|
FromInternalKeyToStackKey(sKey, out oldKey)
|
|
&& FromInternalValueToExternalValue(oldItm, out oldValue)
|
|
)
|
|
newValue = updateValueFactory(oldKey, oldValue);
|
|
else
|
|
{
|
|
//boyscout
|
|
RemoveIKVP(sKey, oldItm);
|
|
newValue = addValueFactory(key);
|
|
}
|
|
|
|
return FromExternalValueToInternalValue(hold2 = newValue);
|
|
}
|
|
),
|
|
out hold1
|
|
)
|
|
)
|
|
return hold1;
|
|
}
|
|
}
|
|
|
|
public EV AddOrUpdate(SK key, EV addValue, Func<SK, EV, EV> updateValueFactory)
|
|
{
|
|
while (true)
|
|
{
|
|
//this inside loop to prevent optimizer from optimizing away our reference to addValue.
|
|
var newItm = FromExternalValueToInternalValue(addValue);
|
|
var internalKey = FromStackKeyToStorageKey(key);
|
|
|
|
if (base.TryAdd(internalKey, newItm))
|
|
return addValue;
|
|
|
|
EV hold = default(EV);
|
|
|
|
if(
|
|
FromInternalValueToExternalValue(
|
|
base.AddOrUpdate(
|
|
FromStackKeyToStorageKey(key),
|
|
newItm,
|
|
(sKey, oldItm) =>
|
|
{
|
|
EV oldValue;
|
|
SK oldKey;
|
|
|
|
if (
|
|
FromInternalKeyToStackKey(sKey, out oldKey)
|
|
&& FromInternalValueToExternalValue(oldItm, out oldValue)
|
|
)
|
|
return FromExternalValueToInternalValue(hold = updateValueFactory(oldKey, oldValue));
|
|
else
|
|
{
|
|
//boyscout
|
|
RemoveIKVP(sKey, oldItm);
|
|
return newItm;
|
|
}
|
|
}
|
|
),
|
|
out hold
|
|
)
|
|
)
|
|
return hold;
|
|
}
|
|
}
|
|
|
|
public EV GetOrAdd(SK key, EV value)
|
|
{
|
|
while (true)
|
|
{
|
|
//this inside loop to prevent optimizer from optimizing away our reference to value.
|
|
var newItm = FromExternalValueToInternalValue(value);
|
|
var internalKey = FromStackKeyToStorageKey(key);
|
|
|
|
EV hold;
|
|
|
|
IV item = base.GetOrAdd(internalKey, newItm);
|
|
|
|
if (FromInternalValueToExternalValue(item, out hold))
|
|
return hold;
|
|
|
|
//boyscout
|
|
RemoveIKVP(internalKey, item);
|
|
}
|
|
}
|
|
|
|
private bool RemoveIKVP(IK internalKey, IV item)
|
|
{
|
|
return ((ICollection<KeyValuePair<IK, IV>>)this).Remove(new KeyValuePair<IK, IV>(internalKey, item));
|
|
}
|
|
|
|
public EV GetOrAdd(SK key, Func<SK, EV> valueFactory)
|
|
{
|
|
EV hold;
|
|
|
|
return this.TryGetValue(key, out hold) ? hold : GetOrAdd(key, valueFactory(key));
|
|
}
|
|
|
|
public new KeyValuePair<EK, EV>[] ToArray()
|
|
{ return ((IEnumerable<KeyValuePair<EK, EV>>)this).ToArray(); }
|
|
|
|
public bool TryAdd(SK key, EV value)
|
|
{
|
|
var newItm = FromExternalValueToInternalValue(value);
|
|
var internalKey = FromStackKeyToStorageKey(key);
|
|
|
|
if (base.TryAdd(internalKey, newItm))
|
|
return true;
|
|
|
|
var storedItm =
|
|
base.AddOrUpdate(
|
|
internalKey,
|
|
newItm,
|
|
(k, itm) =>
|
|
{
|
|
if (k.IsGarbage || itm.IsGarbage)
|
|
{
|
|
//boyscout
|
|
RemoveIKVP(k, itm);
|
|
return newItm;
|
|
}
|
|
else
|
|
return itm;
|
|
}
|
|
)
|
|
;
|
|
|
|
return object.ReferenceEquals(storedItm.Reference, newItm.Reference);
|
|
}
|
|
|
|
public bool TryRemove(SK key, out EV value)
|
|
{
|
|
IV hold;
|
|
|
|
if (base.TryRemove(FromStackKeyToSearchKey(key), out hold))
|
|
return FromInternalValueToExternalValue(hold, out value);
|
|
|
|
value = default(EV);
|
|
return false;
|
|
}
|
|
|
|
public bool TryUpdate(SK key, EV newValue, EV comparisonValue)
|
|
{
|
|
return
|
|
base.TryUpdate(
|
|
FromStackKeyToSearchKey(key),
|
|
FromExternalValueToInternalValue(newValue),
|
|
FromExternalValueToInternalValue(comparisonValue)
|
|
)
|
|
;
|
|
}
|
|
|
|
public List<KeyValuePair<EK, EV>> GetContents()
|
|
{ return ((IEnumerable<KeyValuePair<EK, EV>>)this).ToList(); }
|
|
|
|
public void InsertContents(IEnumerable<KeyValuePair<EK, EV>> collection)
|
|
{
|
|
if (null == collection)
|
|
throw new ArgumentNullException("collection");
|
|
|
|
foreach (var kvp in collection)
|
|
((IDictionary<EK, EV>)this).Add(kvp);
|
|
}
|
|
}
|
|
|
|
internal abstract class InternalWeakDictionaryWeakValueBase<IK, EK, EV, SK> : InternalWeakDictionaryWeakValueBase<IK, WeakValueRef<EV>, EK, EV, SK>
|
|
where IK : ITrashable
|
|
where EV : class
|
|
where SK : struct
|
|
{
|
|
protected InternalWeakDictionaryWeakValueBase(int concurrencyLevel, int capacity, IEqualityComparer<IK> keyComparer)
|
|
#if SILVERLIGHT
|
|
: base(keyComparer)
|
|
#else
|
|
: base(concurrencyLevel, capacity, keyComparer)
|
|
#endif
|
|
{ }
|
|
|
|
protected InternalWeakDictionaryWeakValueBase(IEqualityComparer<IK> keyComparer)
|
|
: base(keyComparer)
|
|
{ }
|
|
|
|
protected override WeakValueRef<EV> FromExternalValueToInternalValue(EV externalValue)
|
|
{ return WeakValueRef<EV>.Create( externalValue ); }
|
|
}
|
|
}
|