|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using System.Threading;
|
|
|
|
|
|
|
|
|
|
namespace ZeroLevel.Services.Collections
|
|
|
|
|
{
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Collection return new seq every iteration
|
|
|
|
|
/// Sample. Original: [1,2,3]. Iteration #1: [1, 2, 3]. Iteration #2: [2, 3, 1]. Iteration #3: [3, 1, 2]. Iteration #4: [1, 2, 3]
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <typeparam name="T"></typeparam>
|
|
|
|
|
public sealed class RoundRobinCollection<T> :
|
|
|
|
|
IDisposable
|
|
|
|
|
{
|
|
|
|
|
private readonly List<T> _collection =
|
|
|
|
|
new List<T>();
|
|
|
|
|
|
|
|
|
|
private int _index = -1;
|
|
|
|
|
|
|
|
|
|
private readonly ReaderWriterLockSlim _lock =
|
|
|
|
|
new ReaderWriterLockSlim();
|
|
|
|
|
|
|
|
|
|
public int Count { get { return _collection.Count; } }
|
|
|
|
|
|
|
|
|
|
public RoundRobinCollection() { }
|
|
|
|
|
public RoundRobinCollection(IEnumerable<T> items)
|
|
|
|
|
{
|
|
|
|
|
if (items != null && items.Any())
|
|
|
|
|
{
|
|
|
|
|
_collection.AddRange(items);
|
|
|
|
|
_index = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void Add(T item)
|
|
|
|
|
{
|
|
|
|
|
_lock.EnterWriteLock();
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
if (!_collection.Contains(item))
|
|
|
|
|
{
|
|
|
|
|
_collection.Add(item);
|
|
|
|
|
if (_index == -1) _index = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
finally
|
|
|
|
|
{
|
|
|
|
|
_lock.ExitWriteLock();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void Remove(T item)
|
|
|
|
|
{
|
|
|
|
|
_lock.EnterWriteLock();
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
_collection.Remove(item);
|
|
|
|
|
if (_index >= _collection.Count)
|
|
|
|
|
{
|
|
|
|
|
if (_collection.Count == 0) _index = -1;
|
|
|
|
|
else _index = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
finally
|
|
|
|
|
{
|
|
|
|
|
_lock.ExitWriteLock();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public bool Contains(T item)
|
|
|
|
|
{
|
|
|
|
|
_lock.EnterReadLock();
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
return _collection.Contains(item);
|
|
|
|
|
}
|
|
|
|
|
finally
|
|
|
|
|
{
|
|
|
|
|
_lock.ExitReadLock();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public bool MoveNext()
|
|
|
|
|
{
|
|
|
|
|
_lock.EnterReadLock();
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
if (_collection.Count > 0)
|
|
|
|
|
{
|
|
|
|
|
_index = Interlocked.Increment(ref _index) % _collection.Count;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
finally
|
|
|
|
|
{
|
|
|
|
|
_lock.ExitReadLock();
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public IEnumerable<T> MoveNextSeq()
|
|
|
|
|
{
|
|
|
|
|
_lock.EnterReadLock();
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
if (_collection.Count > 0)
|
|
|
|
|
{
|
|
|
|
|
_index = Interlocked.Increment(ref _index) % _collection.Count;
|
|
|
|
|
int p = 0;
|
|
|
|
|
for (int i = _index; i < _collection.Count; i++, p++)
|
|
|
|
|
{
|
|
|
|
|
yield return _collection[i];
|
|
|
|
|
}
|
|
|
|
|
for (int i = 0; i < _index; i++, p++)
|
|
|
|
|
{
|
|
|
|
|
yield return _collection[i];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
finally
|
|
|
|
|
{
|
|
|
|
|
_lock.ExitReadLock();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public bool MoveNextAndHandle(Action<T> handler)
|
|
|
|
|
{
|
|
|
|
|
_lock.EnterReadLock();
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
if (_collection.Count > 0)
|
|
|
|
|
{
|
|
|
|
|
_index = Interlocked.Increment(ref _index) % _collection.Count;
|
|
|
|
|
handler.Invoke(Current);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
finally
|
|
|
|
|
{
|
|
|
|
|
_lock.ExitReadLock();
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public T Current
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
|
|
|
|
return (_index == -1 ? default(T) : _collection[_index])!;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public IEnumerable<T> Source { get { return _collection; } }
|
|
|
|
|
|
|
|
|
|
public IEnumerable<T> GetCurrentSeq()
|
|
|
|
|
{
|
|
|
|
|
_lock.EnterReadLock();
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
int p = 0;
|
|
|
|
|
for (int i = _index; i < _collection.Count; i++, p++)
|
|
|
|
|
{
|
|
|
|
|
yield return _collection[i];
|
|
|
|
|
}
|
|
|
|
|
for (int i = 0; i < _index; i++, p++)
|
|
|
|
|
{
|
|
|
|
|
yield return _collection[i];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
finally
|
|
|
|
|
{
|
|
|
|
|
_lock.ExitReadLock();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public IEnumerable<T> Find(Func<T, bool> selector)
|
|
|
|
|
{
|
|
|
|
|
_lock.EnterReadLock();
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
var arr = new List<T>(_collection.Count);
|
|
|
|
|
for (int i = _index; i < _collection.Count; i++)
|
|
|
|
|
{
|
|
|
|
|
if (selector(_collection[i]))
|
|
|
|
|
{
|
|
|
|
|
arr.Add(_collection[i]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return arr;
|
|
|
|
|
}
|
|
|
|
|
finally
|
|
|
|
|
{
|
|
|
|
|
_lock.ExitReadLock();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void Clear()
|
|
|
|
|
{
|
|
|
|
|
_collection.Clear();
|
|
|
|
|
_index = -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void Dispose()
|
|
|
|
|
{
|
|
|
|
|
_collection.Clear();
|
|
|
|
|
_lock.Dispose();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|