wasSharp – Rev 38

Subversion Repositories:
Rev:
///////////////////////////////////////////////////////////////////////////
//  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);
    }
}