using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
namespace Umbraco.Core
{
///
/// A thread-safe representation of a .
/// Enumerating this collection is thread-safe and will only operate on a clone that is generated before returning the enumerator.
///
///
[Serializable]
public class ConcurrentHashSet : ICollection
{
private readonly HashSet _innerSet = new HashSet();
private readonly ReaderWriterLockSlim _instanceLocker = new ReaderWriterLockSlim(LockRecursionPolicy.NoRecursion);
///
/// Returns an enumerator that iterates through the collection.
///
///
/// A that can be used to iterate through the collection.
///
/// 1
public IEnumerator GetEnumerator()
{
return GetThreadSafeClone().GetEnumerator();
}
///
/// Returns an enumerator that iterates through a collection.
///
///
/// An object that can be used to iterate through the collection.
///
/// 2
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
///
/// Removes the first occurrence of a specific object from the .
///
///
/// true if was successfully removed from the ; otherwise, false. This method also returns false if is not found in the original .
///
/// The object to remove from the .The is read-only.
public bool Remove(T item)
{
using (new WriteLock(_instanceLocker))
{
return _innerSet.Remove(item);
}
}
///
/// Gets the number of elements contained in the .
///
///
/// The number of elements contained in the .
///
/// 2
public int Count
{
get { return GetThreadSafeClone().Count; }
}
///
/// Gets a value indicating whether the is read-only.
///
///
/// true if the is read-only; otherwise, false.
///
public bool IsReadOnly
{
get { return false; }
}
///
/// Adds an item to the .
///
/// The object to add to the .The is read-only.
public void Add(T item)
{
using (new WriteLock(_instanceLocker))
{
_innerSet.Add(item);
}
}
///
/// Attempts to add an item to the collection
///
///
///
public bool TryAdd(T item)
{
var clone = GetThreadSafeClone();
if (clone.Contains(item)) return false;
using (new WriteLock(_instanceLocker))
{
//double check
if (_innerSet.Contains(item)) return false;
_innerSet.Add(item);
return true;
}
}
///
/// Removes all items from the .
///
/// The is read-only.
public void Clear()
{
using (new WriteLock(_instanceLocker))
{
_innerSet.Clear();
}
}
///
/// Determines whether the contains a specific value.
///
///
/// true if is found in the ; otherwise, false.
///
/// The object to locate in the .
public bool Contains(T item)
{
return GetThreadSafeClone().Contains(item);
}
///
/// Copies the elements of the to an , starting at a specified index.
///
/// The one-dimensional that is the destination of the elements copied from the . The array must have zero-based indexing.The zero-based index in at which copying begins. is a null reference (Nothing in Visual Basic). is less than zero. is equal to or greater than the length of the -or- The number of elements in the source is greater than the available space from to the end of the destination .
public void CopyTo(T[] array, int index)
{
var clone = GetThreadSafeClone();
clone.CopyTo(array, index);
}
private HashSet GetThreadSafeClone()
{
HashSet clone = null;
using (new WriteLock(_instanceLocker))
{
clone = new HashSet(_innerSet, _innerSet.Comparer);
}
return clone;
}
///
/// Copies the elements of the to an , starting at a particular index.
///
/// The one-dimensional that is the destination of the elements copied from . The must have zero-based indexing. The zero-based index in at which copying begins. is null. is less than zero. is multidimensional.-or- The number of elements in the source is greater than the available space from to the end of the destination . The type of the source cannot be cast automatically to the type of the destination . 2
public void CopyTo(Array array, int index)
{
var clone = GetThreadSafeClone();
Array.Copy(clone.ToArray(), 0, array, index, clone.Count);
}
}
}