/////////////////////////////////////////////////////////////////////////// // 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. // /////////////////////////////////////////////////////////////////////////// // Based on work by Ben Mosher using System; using System.Collections; using System.Collections.Generic; using System.Threading; namespace wasSharp.Collections.Specialized { public static class ConcurrentHashSetExtensions { public static ConcurrentHashSet ToConcurrentHashSet(this IEnumerable enumerable) { return new ConcurrentHashSet(enumerable); } } public class ConcurrentHashSet : IDisposable, ISet { private readonly ReaderWriterLockSlim _lock = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion); private readonly HashSet _hashSet; public ConcurrentHashSet() { _lock.EnterWriteLock(); try { _hashSet = new HashSet(); } finally { if (_lock.IsWriteLockHeld) _lock.ExitWriteLock(); } } public ConcurrentHashSet(IEqualityComparer stringComparer) { _lock.EnterWriteLock(); try { _hashSet = new HashSet(stringComparer); } finally { if (_lock.IsWriteLockHeld) _lock.ExitWriteLock(); } } public ConcurrentHashSet(IEnumerable enumerable) { _lock.EnterWriteLock(); try { _hashSet = new HashSet(); foreach (var i in enumerable) { _hashSet.Add(i); } } finally { if (_lock.IsWriteLockHeld) _lock.ExitWriteLock(); } } #region Implementation of ICollection public bool Add(T item) { _lock.EnterWriteLock(); try { return _hashSet.Add(item); } finally { if (_lock.IsWriteLockHeld) _lock.ExitWriteLock(); } } public void Clear() { _lock.EnterWriteLock(); try { _hashSet.Clear(); } finally { if (_lock.IsWriteLockHeld) _lock.ExitWriteLock(); } } public bool Contains(T item) { _lock.EnterReadLock(); try { return _hashSet.Contains(item); } finally { if (_lock.IsReadLockHeld) _lock.ExitReadLock(); } } public bool Remove(T item) { _lock.EnterWriteLock(); try { return _hashSet.Remove(item); } finally { if (_lock.IsWriteLockHeld) _lock.ExitWriteLock(); } } public int RemoveWhere(Predicate match) { _lock.EnterWriteLock(); try { return _hashSet.RemoveWhere(match); } finally { if (_lock.IsWriteLockHeld) _lock.ExitWriteLock(); } } public int Count { get { _lock.EnterReadLock(); try { return _hashSet.Count; } finally { if (_lock.IsReadLockHeld) _lock.ExitReadLock(); } } } void ICollection.Add(T item) { _lock.EnterWriteLock(); try { _hashSet.Add(item); } finally { if (_lock.IsWriteLockHeld) _lock.ExitWriteLock(); } } public void CopyTo(T[] array, int arrayIndex) { _lock.EnterReadLock(); try { _hashSet.CopyTo(array, arrayIndex); } finally { if (_lock.IsReadLockHeld) _lock.ExitReadLock(); } } public IEnumerator GetEnumerator() { _lock.EnterReadLock(); try { using (var enumerator = _hashSet.GetEnumerator()) { while (enumerator.MoveNext()) yield return enumerator.Current; } } finally { if (_lock.IsReadLockHeld) _lock.ExitReadLock(); } } IEnumerator IEnumerable.GetEnumerator() { _lock.EnterReadLock(); try { using (var enumerator = _hashSet.GetEnumerator()) { while (enumerator.MoveNext()) yield return enumerator.Current; } } finally { if (_lock.IsReadLockHeld) _lock.ExitReadLock(); } } public bool IsReadOnly => ((ICollection)_hashSet).IsReadOnly; #endregion Implementation of ICollection #region Dispose public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { if (!disposing) return; _lock?.Dispose(); _hashSet.Clear(); } ~ConcurrentHashSet() { Dispose(false); } #endregion Dispose #region Implementation of ISet public void ExceptWith(IEnumerable other) { _lock.EnterWriteLock(); try { _hashSet.ExceptWith(other); } finally { if (_lock.IsWriteLockHeld) _lock.ExitWriteLock(); } } public void IntersectWith(IEnumerable other) { _lock.EnterWriteLock(); try { _hashSet.IntersectWith(other); } finally { if (_lock.IsWriteLockHeld) _lock.ExitWriteLock(); } } public bool IsProperSubsetOf(IEnumerable other) { _lock.EnterReadLock(); try { return _hashSet.IsProperSubsetOf(other); } finally { if (_lock.IsReadLockHeld) _lock.ExitReadLock(); } } public bool IsProperSupersetOf(IEnumerable other) { _lock.EnterReadLock(); try { return _hashSet.IsProperSupersetOf(other); } finally { if (_lock.IsReadLockHeld) _lock.ExitReadLock(); } } public bool IsSubsetOf(IEnumerable other) { _lock.EnterReadLock(); try { return _hashSet.IsSubsetOf(other); } finally { if (_lock.IsReadLockHeld) _lock.ExitReadLock(); } } public bool IsSupersetOf(IEnumerable other) { _lock.EnterReadLock(); try { return _hashSet.IsSupersetOf(other); } finally { if (_lock.IsReadLockHeld) _lock.ExitReadLock(); } } public bool Overlaps(IEnumerable other) { _lock.EnterReadLock(); try { return _hashSet.Overlaps(other); } finally { if (_lock.IsReadLockHeld) _lock.ExitReadLock(); } } public bool SetEquals(IEnumerable other) { _lock.EnterReadLock(); try { return _hashSet.SetEquals(other); } finally { if (_lock.IsReadLockHeld) _lock.ExitReadLock(); } } public void SymmetricExceptWith(IEnumerable other) { _lock.EnterWriteLock(); try { _hashSet.SymmetricExceptWith(other); } finally { if (_lock.IsWriteLockHeld) _lock.ExitWriteLock(); } } public void UnionWith(IEnumerable other) { _lock.EnterWriteLock(); try { _hashSet.UnionWith(other); } finally { if (_lock.IsWriteLockHeld) _lock.ExitWriteLock(); } } #endregion Implementation of ISet } }