You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
347 lines
9.2 KiB
347 lines
9.2 KiB
// Needed for Workaround |
|
#if !NET_4_6 |
|
using System; |
|
using System.Collections.Generic; |
|
using System.Threading; |
|
using LinqInternal.Threading; |
|
using LinqInternal.Threading.Needles; |
|
|
|
namespace LinqInternal.Collections.ThreadSafe |
|
{ |
|
[System.Diagnostics.DebuggerNonUserCode] |
|
[System.Diagnostics.DebuggerDisplay("Count={Count}")] |
|
internal class WeakCollection<T, TNeedle> : ICollection<T> |
|
where T : class |
|
where TNeedle : WeakNeedle<T> |
|
{ |
|
private readonly IEqualityComparer<T> _comparer; |
|
private readonly SafeDictionary<int, TNeedle> _wrapped; |
|
private StructNeedle<WeakNeedle<EventHandler>> _eventHandler; |
|
private int _maxIndex; |
|
|
|
public WeakCollection() |
|
: this(null, true) |
|
{ |
|
// Empty |
|
} |
|
|
|
public WeakCollection(IEqualityComparer<T> comparer) |
|
: this(comparer, true) |
|
{ |
|
// Empty |
|
} |
|
|
|
public WeakCollection(bool autoRemoveDeadItems) |
|
: this(null, autoRemoveDeadItems) |
|
{ |
|
// Empty |
|
} |
|
|
|
public WeakCollection(IEqualityComparer<T> comparer, bool autoRemoveDeadItems) |
|
{ |
|
_maxIndex = -1; |
|
_comparer = comparer ?? EqualityComparer<T>.Default; |
|
_wrapped = new SafeDictionary<int, TNeedle>(); |
|
if (autoRemoveDeadItems) |
|
{ |
|
RegisterForAutoRemoveDeadItemsExtracted(); |
|
} |
|
else |
|
{ |
|
GC.SuppressFinalize(this); |
|
} |
|
} |
|
|
|
public WeakCollection(IEqualityComparer<T> comparer, int initialProbing) |
|
: this(comparer, true, initialProbing) |
|
{ |
|
// Empty |
|
} |
|
|
|
public WeakCollection(bool autoRemoveDeadItems, int initialProbing) |
|
: this(null, autoRemoveDeadItems, initialProbing) |
|
{ |
|
// Empty |
|
} |
|
|
|
public WeakCollection(IEqualityComparer<T> comparer, bool autoRemoveDeadItems, int initialProbing) |
|
{ |
|
_maxIndex = -1; |
|
#if FAT |
|
_comparer = comparer ?? EqualityComparer<T>.Default; |
|
#else |
|
_comparer = comparer ?? EqualityComparer<T>.Default; |
|
#endif |
|
_wrapped = new SafeDictionary<int, TNeedle>(initialProbing); |
|
if (autoRemoveDeadItems) |
|
{ |
|
RegisterForAutoRemoveDeadItemsExtracted(); |
|
} |
|
else |
|
{ |
|
GC.SuppressFinalize(this); |
|
} |
|
} |
|
|
|
public WeakCollection(int initialProbing) |
|
: this(null, true, initialProbing) |
|
{ |
|
// Empty |
|
} |
|
|
|
~WeakCollection() |
|
{ |
|
UnRegisterForAutoRemoveDeadItemsExtracted(); |
|
} |
|
|
|
public bool AutoRemoveDeadItems |
|
{ |
|
get { return _eventHandler.IsAlive; } |
|
|
|
set |
|
{ |
|
if (value) |
|
{ |
|
RegisterForAutoRemoveDeadItems(); |
|
} |
|
else |
|
{ |
|
UnRegisterForAutoRemoveDeadItems(); |
|
} |
|
} |
|
} |
|
|
|
public int Count |
|
{ |
|
get { return _wrapped.Count; } |
|
} |
|
|
|
bool ICollection<T>.IsReadOnly |
|
{ |
|
get { return false; } |
|
} |
|
|
|
public void Add(T item) |
|
{ |
|
var needle = NeedleHelper.CreateNeedle<T, TNeedle>(item); |
|
_wrapped.Set(Interlocked.Increment(ref _maxIndex), needle); |
|
} |
|
|
|
public void Clear() |
|
{ |
|
var displaced = _wrapped.ClearEnumerable(); |
|
foreach (var item in displaced) |
|
{ |
|
item.Value.Dispose(); |
|
} |
|
} |
|
|
|
public bool Contains(T item) |
|
{ |
|
foreach (var input in this) |
|
{ |
|
if (_comparer.Equals(input, item)) |
|
{ |
|
return true; |
|
} |
|
} |
|
return false; |
|
} |
|
|
|
public bool Contains(Predicate<T> itemCheck) |
|
{ |
|
foreach (var input in this) |
|
{ |
|
if (itemCheck(input)) |
|
{ |
|
return true; |
|
} |
|
} |
|
return false; |
|
} |
|
|
|
public void CopyTo(T[] array, int arrayIndex) |
|
{ |
|
Extensions.CopyTo(this, array, arrayIndex); |
|
} |
|
|
|
public bool Equals(T x, T y) |
|
{ |
|
return _comparer.Equals(x, y); |
|
} |
|
|
|
public IEnumerator<T> GetEnumerator() |
|
{ |
|
foreach (var pair in _wrapped) |
|
{ |
|
T result; |
|
if (pair.Value.TryGetValue(out result)) |
|
{ |
|
yield return result; |
|
} |
|
} |
|
} |
|
|
|
public bool Remove(T item) |
|
{ |
|
Predicate<TNeedle> check = input => |
|
{ |
|
T value; |
|
if (input.TryGetValue(out value)) |
|
{ |
|
return _comparer.Equals(item, value); |
|
} |
|
return false; |
|
}; |
|
foreach (var removed in _wrapped.RemoveWhereValueEnumerable(check)) |
|
{ |
|
removed.Dispose(); |
|
return true; |
|
} |
|
return false; |
|
} |
|
|
|
public int RemoveDeadItems() |
|
{ |
|
return _wrapped.RemoveWhere(input => !input.Value.IsAlive); |
|
} |
|
|
|
public int RemoveWhere(Predicate<T> itemCheck) |
|
{ |
|
Predicate<TNeedle> check = input => |
|
{ |
|
T value; |
|
if (input.TryGetValue(out value)) |
|
{ |
|
return itemCheck(value); |
|
} |
|
return false; |
|
}; |
|
return _wrapped.RemoveWhereValue(check); |
|
} |
|
|
|
public IEnumerable<T> RemoveWhereEnumerable(Predicate<T> itemCheck) |
|
{ |
|
Predicate<TNeedle> check = input => |
|
{ |
|
T value; |
|
if (input.TryGetValue(out value)) |
|
{ |
|
return itemCheck(value); |
|
} |
|
return false; |
|
}; |
|
foreach (var removed in _wrapped.RemoveWhereValueEnumerable(check)) |
|
{ |
|
T value; |
|
if (removed.TryGetValue(out value)) |
|
{ |
|
yield return value; |
|
} |
|
removed.Dispose(); |
|
} |
|
} |
|
|
|
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() |
|
{ |
|
return GetEnumerator(); |
|
} |
|
|
|
protected void Add(TNeedle needle) |
|
{ |
|
_wrapped.Set(Interlocked.Increment(ref _maxIndex), needle); |
|
} |
|
|
|
protected bool Contains(Predicate<TNeedle> needleCheck) |
|
{ |
|
foreach (var pair in _wrapped) |
|
{ |
|
if (needleCheck(pair.Value)) |
|
{ |
|
return true; |
|
} |
|
} |
|
return false; |
|
} |
|
|
|
protected IEnumerable<TNeedle> GetNeedleEnumerable() |
|
{ |
|
foreach (var pair in _wrapped) |
|
{ |
|
yield return pair.Value; |
|
} |
|
} |
|
|
|
protected IEnumerable<T> RemoveWhereEnumerable(Predicate<TNeedle> needleCheck) |
|
{ |
|
foreach (var removed in _wrapped.RemoveWhereValueEnumerable(needleCheck)) |
|
{ |
|
T value; |
|
if (removed.TryGetValue(out value)) |
|
{ |
|
yield return value; |
|
} |
|
removed.Dispose(); |
|
} |
|
} |
|
|
|
private void GarbageCollected(object sender, EventArgs e) |
|
{ |
|
RemoveDeadItems(); |
|
} |
|
|
|
private void RegisterForAutoRemoveDeadItems() |
|
{ |
|
if (RegisterForAutoRemoveDeadItemsExtracted()) |
|
{ |
|
GC.ReRegisterForFinalize(this); |
|
} |
|
} |
|
|
|
private bool RegisterForAutoRemoveDeadItemsExtracted() |
|
{ |
|
var result = false; |
|
EventHandler eventHandler; |
|
if (ReferenceEquals(_eventHandler.Value, null)) |
|
{ |
|
eventHandler = GarbageCollected; |
|
_eventHandler = new WeakNeedle<EventHandler>(eventHandler); |
|
result = true; |
|
} |
|
else |
|
{ |
|
eventHandler = _eventHandler.Value.Value; |
|
if (!_eventHandler.IsAlive) |
|
{ |
|
eventHandler = GarbageCollected; |
|
_eventHandler.Value = eventHandler; |
|
result = true; |
|
} |
|
} |
|
GCMonitor.Collected += eventHandler; |
|
return result; |
|
} |
|
|
|
private void UnRegisterForAutoRemoveDeadItems() |
|
{ |
|
if (UnRegisterForAutoRemoveDeadItemsExtracted()) |
|
{ |
|
GC.SuppressFinalize(this); |
|
} |
|
} |
|
|
|
private bool UnRegisterForAutoRemoveDeadItemsExtracted() |
|
{ |
|
EventHandler eventHandler; |
|
if (_eventHandler.Value.Retrieve(out eventHandler)) |
|
{ |
|
GCMonitor.Collected -= eventHandler; |
|
_eventHandler.Value = null; |
|
return true; |
|
} |
|
_eventHandler.Value = null; |
|
return false; |
|
} |
|
} |
|
} |
|
#endif |