/Collections/Specialized/ConcurrentLazyList.cs |
@@ -0,0 +1,176 @@ |
/////////////////////////////////////////////////////////////////////////// |
// 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.Collections.Generic; |
using System.Linq; |
using System.Threading; |
|
// http://www.fallingcanbedeadly.com/posts/crazy-extention-methods-tolazylist/ |
|
namespace wasSharp.Collections.Specialized |
{ |
public class ConcurrentLazyList<T> : IList<T>, IDisposable |
{ |
public ConcurrentLazyList(IEnumerable<T> list) |
{ |
syncRoot.EnterReadLock(); |
_enumerator = list.GetEnumerator(); |
syncRoot.ExitReadLock(); |
_isFinished = false; |
_cached = new List<T>(); |
} |
|
public T this[int index] |
{ |
get |
{ |
if (index < 0) |
throw new ArgumentOutOfRangeException("index"); |
|
while (_cached.Count <= index && !_isFinished) |
{ |
syncRoot.EnterReadLock(); |
GetNext(); |
syncRoot.ExitReadLock(); |
} |
var cached = _cached[index]; |
return cached; |
} |
set |
{ |
throw new NotSupportedException(); |
} |
} |
|
public int Count |
{ |
get |
{ |
syncRoot.EnterWriteLock(); |
Finish(); |
syncRoot.ExitWriteLock(); |
return _cached.Count; |
} |
} |
|
public IEnumerator<T> GetEnumerator() |
{ |
int current = 0; |
|
while (current < _cached.Count || !_isFinished) |
{ |
if (current == _cached.Count) |
{ |
syncRoot.EnterReadLock(); |
GetNext(); |
syncRoot.ExitReadLock(); |
} |
if (current != _cached.Count) |
yield return _cached[current]; |
current++; |
} |
} |
|
public void Dispose() |
{ |
syncRoot.EnterWriteLock(); |
_enumerator.Dispose(); |
syncRoot.ExitWriteLock(); |
_isFinished = true; |
} |
|
public int IndexOf(T item) |
{ |
int result = _cached.IndexOf(item); |
while (result == -1 && !_isFinished) |
{ |
syncRoot.EnterReadLock(); |
GetNext(); |
syncRoot.ExitReadLock(); |
if (_cached.Last().Equals(item)) |
result = _cached.Count - 1; |
} |
|
return result; |
} |
|
public void Insert(int index, T item) |
{ |
throw new NotSupportedException(); |
} |
|
public void RemoveAt(int index) |
{ |
throw new NotSupportedException(); |
} |
|
public void Add(T item) |
{ |
throw new NotSupportedException(); |
} |
|
public void Clear() |
{ |
throw new NotSupportedException(); |
} |
|
public bool Contains(T item) |
{ |
syncRoot.EnterReadLock(); |
var contains = IndexOf(item) != -1; |
syncRoot.ExitReadLock(); |
return contains; |
} |
|
public void CopyTo(T[] array, int arrayIndex) |
{ |
syncRoot.EnterReadLock(); |
foreach (var item in this) |
array[arrayIndex++] = item; |
syncRoot.ExitReadLock(); |
} |
|
public bool IsReadOnly => true; |
|
public bool Remove(T item) |
{ |
throw new NotSupportedException(); |
} |
|
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() |
{ |
return GetEnumerator(); |
} |
|
private void GetNext() |
{ |
if (!_isFinished) |
{ |
if (_enumerator.MoveNext()) |
{ |
_cached.Add(_enumerator.Current); |
} |
else |
{ |
_isFinished = true; |
_enumerator.Dispose(); |
} |
} |
} |
|
private void Finish() |
{ |
while (!_isFinished) |
GetNext(); |
} |
|
private readonly List<T> _cached; |
private readonly IEnumerator<T> _enumerator; |
private bool _isFinished; |
private ReaderWriterLockSlim syncRoot = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion); |
} |
} |