wasSharp

Subversion Repositories:
Compare Path: Rev
With Path: Rev
?path1? @ 53  →  ?path2? @ 54
/Collections/Specialized/ObservableConcurrentHashSet.cs
@@ -0,0 +1,272 @@
///////////////////////////////////////////////////////////////////////////
// Copyright (C) Wizardry and Steamworks 2013 - License: GNU GPLv3 //
// Please see: http://www.gnu.org/licenses/gpl.html for legal details, //
// rights of fair usage, the disclaimer and warranty conditions. //
///////////////////////////////////////////////////////////////////////////
 
using System;
using System.Threading;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
 
namespace wasSharp.Collections.Specialized
{
///////////////////////////////////////////////////////////////////////////
// Copyright (C) 2014 Wizardry and Steamworks - License: GNU GPLv3 //
///////////////////////////////////////////////////////////////////////////
/// <summary>
/// An implementation of an observable HashSet.
/// </summary>
/// <typeparam name="T">the object type</typeparam>
public class ObservableConcurrentHashSet<T> : ICollection<T>, INotifyCollectionChanged, IEnumerable<T>
{
private readonly ReaderWriterLockSlim _lock = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion);
private readonly HashSet<T> store = new HashSet<T>();
 
public ObservableConcurrentHashSet(HashSet<T> set)
{
_lock.EnterWriteLock();
try
{
UnionWith(set);
}
finally
{
if (_lock.IsWriteLockHeld) _lock.ExitWriteLock();
}
}
 
public ObservableConcurrentHashSet()
{
}
 
public ObservableConcurrentHashSet(T item)
{
_lock.EnterWriteLock();
try
{
Add(item);
}
finally
{
if (_lock.IsWriteLockHeld) _lock.ExitWriteLock();
}
}
 
public ObservableConcurrentHashSet(ObservableConcurrentHashSet<T> other)
{
_lock.EnterWriteLock();
try
{
UnionWith(other);
}
finally
{
if (_lock.IsWriteLockHeld) _lock.ExitWriteLock();
}
}
 
public ObservableConcurrentHashSet(IEnumerable<T> list)
{
_lock.EnterWriteLock();
try
{
UnionWith(list);
}
finally
{
if (_lock.IsWriteLockHeld) _lock.ExitWriteLock();
}
}
 
public bool IsVirgin { get; private set; } = true;
 
public IEnumerator<T> GetEnumerator()
{
_lock.EnterReadLock();
try
{
using (var enumerator = store.GetEnumerator())
{
while (enumerator.MoveNext())
yield return enumerator.Current;
}
}
finally
{
if (_lock.IsReadLockHeld) _lock.ExitReadLock();
}
}
 
IEnumerator IEnumerable.GetEnumerator()
{
_lock.EnterReadLock();
try
{
using (var enumerator = store.GetEnumerator())
{
while (enumerator.MoveNext())
yield return enumerator.Current;
}
}
finally
{
if (_lock.IsReadLockHeld) _lock.ExitReadLock();
}
}
 
public void Add(T item)
{
_lock.EnterWriteLock();
try
{
store.Add(item);
}
finally
{
if (_lock.IsWriteLockHeld) _lock.ExitWriteLock();
}
IsVirgin = false;
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item));
}
 
public void Clear()
{
_lock.EnterWriteLock();
try
{
store.Clear();
}
finally
{
if (_lock.IsWriteLockHeld) _lock.ExitWriteLock();
}
if (!IsVirgin)
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
IsVirgin = false;
}
 
public bool Contains(T item)
{
_lock.EnterReadLock();
try
{
return store.Contains(item);
}
finally
{
if (_lock.IsReadLockHeld) _lock.ExitReadLock();
}
}
 
public void CopyTo(T[] array, int arrayIndex)
{
_lock.EnterReadLock();
try
{
store.CopyTo(array, arrayIndex);
}
finally
{
if (_lock.IsReadLockHeld) _lock.ExitReadLock();
}
}
 
public bool Remove(T item)
{
_lock.EnterWriteLock();
bool removed;
try
{
removed = store.Remove(item);
}
finally
{
if (_lock.IsWriteLockHeld) _lock.ExitWriteLock();
}
IsVirgin = false;
if (removed)
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, item));
return removed;
}
 
public int Count => store.Count();
 
public bool IsReadOnly => false;
 
public event NotifyCollectionChangedEventHandler CollectionChanged;
 
public void UnionWith(IEnumerable<T> list)
{
var added = new List<T>(list.Except(store));
_lock.EnterWriteLock();
try
{
store.UnionWith(added);
}
finally
{
if (_lock.IsWriteLockHeld) _lock.ExitWriteLock();
}
if (!IsVirgin && added.Any())
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, added));
IsVirgin = false;
}
 
private void OnCollectionChanged(NotifyCollectionChangedEventArgs args)
{
CollectionChanged?.Invoke(this, args);
}
 
public void ExceptWith(IEnumerable<T> list)
{
var removed = new List<T>(list.Intersect(store));
_lock.EnterWriteLock();
try
{
store.ExceptWith(removed);
}
finally
{
if (_lock.IsWriteLockHeld) _lock.ExitWriteLock();
}
if (!IsVirgin && removed.Any())
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove,
removed));
IsVirgin = false;
}
 
public void RemoveWhere(Func<T, bool> func)
{
var removed = new List<T>(store.Where(func));
_lock.EnterWriteLock();
try
{
store.ExceptWith(removed);
}
finally
{
if (_lock.IsWriteLockHeld) _lock.ExitWriteLock();
}
if (!IsVirgin && removed.Any())
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove,
removed));
IsVirgin = false;
}
 
public IEnumerable<T> AsEnumerable()
{
_lock.EnterWriteLock();
try
{
return store.AsEnumerable();
}
finally
{
if (_lock.IsWriteLockHeld) _lock.ExitWriteLock();
}
}
}
}