Skip to content

Commit

Permalink
Optimize weak collection/dictionary cleanup (#16)
Browse files Browse the repository at this point in the history
  • Loading branch information
tibel committed Apr 13, 2015
1 parent 1c853b9 commit 106ed22
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 38 deletions.
29 changes: 20 additions & 9 deletions src/Weakly/Collections/WeakCollection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,7 @@ private void CleanIfNeeded()
return;

_gcSentinel.Target = new object();

for (var i = _inner.Count - 1; i >= 0; i--)
{
if (!_inner[i].IsAlive)
_inner.RemoveAt(i);
}
Purge();
}

#region Constructors
Expand Down Expand Up @@ -59,13 +54,23 @@ public WeakCollection(int capacity)

#endregion

/// <summary>
/// Removes all dead entries.
/// </summary>
/// <returns>true if entries where removed; otherwise false.</returns>
public bool Purge()
{
return _inner.RemoveAll(l => !l.IsAlive) > 0;
}

/// <summary>
/// Returns an enumerator that iterates through the collection.
/// </summary>
/// <returns>A <see cref="T:System.Collections.Generic.IEnumerator`1" /> that can be used to iterate through the collection.</returns>
public IEnumerator<T> GetEnumerator()
{
CleanIfNeeded();

var enumerable = _inner.Select(item => (T) item.Target)
.Where(value => value != null);
return enumerable.GetEnumerator();
Expand Down Expand Up @@ -102,7 +107,7 @@ public void Clear()
public bool Contains(T item)
{
CleanIfNeeded();
return _inner.Any(w => ((T)w.Target) == item);
return _inner.FindIndex(w => ((T) w.Target) == item) >= 0;
}

/// <summary>
Expand All @@ -112,14 +117,20 @@ public bool Contains(T item)
/// <param name="arrayIndex">The zero-based index in array at which copying begins.</param>
public void CopyTo(T[] array, int arrayIndex)
{
CleanIfNeeded();

if (array == null)
throw new ArgumentNullException("array");
if (arrayIndex < 0 || arrayIndex >= array.Length)
throw new ArgumentOutOfRangeException("arrayIndex");
if ((arrayIndex + Count) > array.Length)
if ((arrayIndex + _inner.Count) > array.Length)
throw new ArgumentException("The number of elements in the source collection is greater than the available space from arrayIndex to the end of the destination array.");

this.ToArray().CopyTo(array, arrayIndex);
var items = _inner.Select(item => (T) item.Target)
.Where(value => value != null)
.ToArray();

items.CopyTo(array, arrayIndex);
}

/// <summary>
Expand Down
52 changes: 35 additions & 17 deletions src/Weakly/Collections/WeakValueDictionary.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,7 @@ private void CleanIfNeeded()
return;

_gcSentinel.Target = new object();

var keysToRemove = _inner.Where(pair => !pair.Value.IsAlive)
.Select(pair => pair.Key)
.ToList();

foreach (var key in keysToRemove)
{
_inner.Remove(key);
}
Purge();
}

#region Constructors
Expand Down Expand Up @@ -102,13 +94,32 @@ public WeakValueDictionary(int capacity, IEqualityComparer<TKey> comparer)

#endregion

/// <summary>
/// Removes all dead entries.
/// </summary>
/// <returns>true if entries where removed; otherwise false.</returns>
public bool Purge()
{
var keysToRemove = _inner.Where(pair => !pair.Value.IsAlive)
.Select(pair => pair.Key)
.ToArray();

foreach (var key in keysToRemove)
{
_inner.Remove(key);
}

return keysToRemove.Length > 0;
}

/// <summary>
/// Returns an enumerator that iterates through the <see cref="WeakValueDictionary&lt;TKey, TValue&gt;"/>.
/// </summary>
/// <returns>The enumerator.</returns>
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
{
CleanIfNeeded();

var enumerable = _inner.Select(pair => new KeyValuePair<TKey, TValue>(pair.Key, (TValue) pair.Value.Target))
.Where(pair => pair.Value != null);
return enumerable.GetEnumerator();
Expand Down Expand Up @@ -143,14 +154,20 @@ bool ICollection<KeyValuePair<TKey, TValue>>.Contains(KeyValuePair<TKey, TValue>

void ICollection<KeyValuePair<TKey, TValue>>.CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
{
CleanIfNeeded();

if (array == null)
throw new ArgumentNullException("array");
if (arrayIndex < 0 || arrayIndex >= array.Length)
throw new ArgumentOutOfRangeException("arrayIndex");
if ((arrayIndex + Count) > array.Length)
if ((arrayIndex + _inner.Count) > array.Length)
throw new ArgumentException("The number of elements in the source collection is greater than the available space from arrayIndex to the end of the destination array.");

this.ToArray().CopyTo(array, arrayIndex);
var items = _inner.Select(pair => new KeyValuePair<TKey, TValue>(pair.Key, (TValue) pair.Value.Target))
.Where(pair => pair.Value != null)
.ToArray();

items.CopyTo(array, arrayIndex);
}

bool ICollection<KeyValuePair<TKey, TValue>>.Remove(KeyValuePair<TKey, TValue> item)
Expand Down Expand Up @@ -238,15 +255,13 @@ public bool TryGetValue(TKey key, out TValue value)
return false;
}

var result = (TValue) wr.Target;
if (result == null)
value = (TValue) wr.Target;
if (value == null)
{
_inner.Remove(key);
value = null;
return false;
}

value = result;
return true;
}

Expand Down Expand Up @@ -332,10 +347,13 @@ public void CopyTo(TValue[] array, int arrayIndex)
throw new ArgumentNullException("array");
if (arrayIndex < 0 || arrayIndex >= array.Length)
throw new ArgumentOutOfRangeException("arrayIndex");
if ((arrayIndex + Count) > array.Length)
if ((arrayIndex + _inner.Count) > array.Length)
throw new ArgumentException("The number of elements in the source collection is greater than the available space from arrayIndex to the end of the destination array.");

this.ToArray().CopyTo(array, arrayIndex);
var items = _inner.Select(pair => pair.Value)
.ToArray();

items.CopyTo(array, arrayIndex);
}

bool ICollection<TValue>.Remove(TValue item)
Expand Down
13 changes: 1 addition & 12 deletions src/Weakly/Events/WeakEventList.cs
Original file line number Diff line number Diff line change
Expand Up @@ -94,18 +94,7 @@ public void RemoveHandler(Delegate handler)

public bool Purge()
{
var foundDirt = false;

for (var i = _list.Count - 1; i >= 0; --i)
{
if (_list[i].Target == null)
{
_list.RemoveAt(i);
foundDirt = true;
}
}

return foundDirt;
return _list.RemoveAll(l => l.Target == null) > 0;
}

public List<WeakEventListener> GetCopy()
Expand Down

0 comments on commit 106ed22

Please sign in to comment.