You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
785 lines
24 KiB
785 lines
24 KiB
5 years ago
|
// Needed for NET40
|
||
|
#if !NET_4_6
|
||
|
using System;
|
||
|
using System.Collections.Generic;
|
||
|
using System.Linq;
|
||
|
using System.Threading;
|
||
|
using LinqInternal.Collections.ThreadSafe;
|
||
|
using LinqInternal.Core;
|
||
|
using LinqInternal.Threading;
|
||
|
|
||
|
namespace LinqInternal.Collections
|
||
|
{
|
||
|
[Serializable]
|
||
|
internal sealed class Progressor<T> : IObservable<T>
|
||
|
{
|
||
|
private ProxyObservable<T> _proxy;
|
||
|
private TryTake<T> _tryTake;
|
||
|
private bool _done;
|
||
|
|
||
|
public Progressor(Progressor<T> wrapped)
|
||
|
{
|
||
|
if (wrapped == null)
|
||
|
{
|
||
|
throw new ArgumentNullException("wrapped");
|
||
|
}
|
||
|
|
||
|
var control = 0;
|
||
|
|
||
|
Predicate<T> newFilter = item => Volatile.Read(ref control) == 0;
|
||
|
var buffer = new SafeQueue<T>();
|
||
|
wrapped.SubscribeAction
|
||
|
(
|
||
|
item =>
|
||
|
{
|
||
|
if (newFilter(item))
|
||
|
{
|
||
|
buffer.Add(item);
|
||
|
}
|
||
|
}
|
||
|
);
|
||
|
_proxy = new ProxyObservable<T>();
|
||
|
|
||
|
_tryTake = (out T value) =>
|
||
|
{
|
||
|
Interlocked.Increment(ref control);
|
||
|
try
|
||
|
{
|
||
|
if (buffer.TryTake(out value) || wrapped.TryTake(out value))
|
||
|
{
|
||
|
_proxy.OnNext(value);
|
||
|
return true;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
_done = wrapped._done;
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
finally
|
||
|
{
|
||
|
Interlocked.Decrement(ref control);
|
||
|
}
|
||
|
};
|
||
|
}
|
||
|
|
||
|
public Progressor(IEnumerable<T> preface, Progressor<T> wrapped)
|
||
|
{
|
||
|
if (wrapped == null)
|
||
|
{
|
||
|
throw new ArgumentNullException("wrapped");
|
||
|
}
|
||
|
if (preface == null)
|
||
|
{
|
||
|
throw new ArgumentNullException("preface");
|
||
|
}
|
||
|
var enumerator = preface.GetEnumerator();
|
||
|
if (enumerator == null)
|
||
|
{
|
||
|
throw new ArgumentException("preface.GetEnumerator()");
|
||
|
}
|
||
|
|
||
|
var control = 0;
|
||
|
var guard = 0;
|
||
|
|
||
|
Predicate<T> newFilter = item => Volatile.Read(ref control) == 0;
|
||
|
var buffer = new SafeQueue<T>();
|
||
|
wrapped.SubscribeAction
|
||
|
(
|
||
|
item =>
|
||
|
{
|
||
|
if (newFilter(item))
|
||
|
{
|
||
|
buffer.Add(item);
|
||
|
}
|
||
|
}
|
||
|
);
|
||
|
_proxy = new ProxyObservable<T>();
|
||
|
|
||
|
TryTake<T> tryTakeReplacement = (out T value) =>
|
||
|
{
|
||
|
Interlocked.Increment(ref control);
|
||
|
try
|
||
|
{
|
||
|
if (buffer.TryTake(out value) || wrapped.TryTake(out value))
|
||
|
{
|
||
|
_proxy.OnNext(value);
|
||
|
return true;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
_done = wrapped._done;
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
finally
|
||
|
{
|
||
|
Interlocked.Decrement(ref control);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
_tryTake = (out T value) =>
|
||
|
{
|
||
|
value = default(T);
|
||
|
if (Volatile.Read(ref guard) == 0)
|
||
|
{
|
||
|
bool result;
|
||
|
// We need a lock, there is no way around it. IEnumerator is just awful. Use another overload if possible.
|
||
|
lock (enumerator)
|
||
|
{
|
||
|
result = enumerator.MoveNext();
|
||
|
if (result)
|
||
|
{
|
||
|
value = enumerator.Current;
|
||
|
}
|
||
|
}
|
||
|
if (result)
|
||
|
{
|
||
|
_proxy.OnNext(value);
|
||
|
return true;
|
||
|
}
|
||
|
enumerator.Dispose();
|
||
|
Interlocked.CompareExchange(ref guard, 1, 0);
|
||
|
}
|
||
|
if (Interlocked.CompareExchange(ref guard, 2, 1) == 1)
|
||
|
{
|
||
|
_tryTake = tryTakeReplacement;
|
||
|
Volatile.Write(ref guard, 3);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ThreadingHelper.SpinWaitUntil(ref guard, 3);
|
||
|
}
|
||
|
var tryTake = _tryTake;
|
||
|
return tryTake(out value);
|
||
|
};
|
||
|
}
|
||
|
|
||
|
public Progressor(T[] wrapped)
|
||
|
{
|
||
|
if (wrapped == null)
|
||
|
{
|
||
|
throw new ArgumentNullException("wrapped");
|
||
|
}
|
||
|
|
||
|
var guard = 0;
|
||
|
var index = -1;
|
||
|
|
||
|
_proxy = new ProxyObservable<T>();
|
||
|
|
||
|
TryTake<T> tryTakeReplacement = (out T value) =>
|
||
|
{
|
||
|
value = default(T);
|
||
|
return false;
|
||
|
};
|
||
|
|
||
|
_tryTake = (out T value) =>
|
||
|
{
|
||
|
value = default(T);
|
||
|
if (Volatile.Read(ref guard) == 0)
|
||
|
{
|
||
|
var currentIndex = Interlocked.Increment(ref index);
|
||
|
if (currentIndex < wrapped.Length)
|
||
|
{
|
||
|
value = wrapped[currentIndex];
|
||
|
_proxy.OnNext(value);
|
||
|
return true;
|
||
|
}
|
||
|
Interlocked.CompareExchange(ref guard, 1, 0);
|
||
|
}
|
||
|
if (Interlocked.CompareExchange(ref guard, 2, 1) == 1)
|
||
|
{
|
||
|
_tryTake = tryTakeReplacement;
|
||
|
}
|
||
|
return false;
|
||
|
};
|
||
|
}
|
||
|
|
||
|
public Progressor(T[] preface, Progressor<T> wrapped)
|
||
|
{
|
||
|
if (wrapped == null)
|
||
|
{
|
||
|
throw new ArgumentNullException("wrapped");
|
||
|
}
|
||
|
if (preface == null)
|
||
|
{
|
||
|
throw new ArgumentNullException("preface");
|
||
|
}
|
||
|
|
||
|
var control = 0;
|
||
|
var guard = 0;
|
||
|
var index = -1;
|
||
|
|
||
|
Predicate<T> newFilter = item => Volatile.Read(ref control) == 0;
|
||
|
var buffer = new SafeQueue<T>();
|
||
|
wrapped.SubscribeAction
|
||
|
(
|
||
|
item =>
|
||
|
{
|
||
|
if (newFilter(item))
|
||
|
{
|
||
|
buffer.Add(item);
|
||
|
}
|
||
|
}
|
||
|
);
|
||
|
_proxy = new ProxyObservable<T>();
|
||
|
|
||
|
TryTake<T> tryTakeReplacement = (out T value) =>
|
||
|
{
|
||
|
Interlocked.Increment(ref control);
|
||
|
try
|
||
|
{
|
||
|
if (buffer.TryTake(out value) || wrapped.TryTake(out value))
|
||
|
{
|
||
|
_proxy.OnNext(value);
|
||
|
return true;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
_done = wrapped._done;
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
finally
|
||
|
{
|
||
|
Interlocked.Decrement(ref control);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
_tryTake = (out T value) =>
|
||
|
{
|
||
|
if (Volatile.Read(ref guard) == 0)
|
||
|
{
|
||
|
var currentIndex = Interlocked.Increment(ref index);
|
||
|
if (currentIndex < preface.Length)
|
||
|
{
|
||
|
value = preface[currentIndex];
|
||
|
_proxy.OnNext(value);
|
||
|
return true;
|
||
|
}
|
||
|
Interlocked.CompareExchange(ref guard, 1, 0);
|
||
|
}
|
||
|
if (Interlocked.CompareExchange(ref guard, 2, 1) == 1)
|
||
|
{
|
||
|
_tryTake = tryTakeReplacement;
|
||
|
Volatile.Write(ref guard, 3);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ThreadingHelper.SpinWaitUntil(ref guard, 3);
|
||
|
}
|
||
|
var tryTake = _tryTake;
|
||
|
return tryTake(out value);
|
||
|
};
|
||
|
}
|
||
|
|
||
|
public Progressor(IEnumerable<T> wrapped)
|
||
|
{
|
||
|
if (wrapped == null)
|
||
|
{
|
||
|
throw new ArgumentNullException("wrapped");
|
||
|
}
|
||
|
var enumerator = wrapped.GetEnumerator();
|
||
|
if (enumerator == null)
|
||
|
{
|
||
|
throw new ArgumentException("wrapped.GetEnumerator()");
|
||
|
}
|
||
|
|
||
|
var guard = 0;
|
||
|
|
||
|
_proxy = new ProxyObservable<T>();
|
||
|
|
||
|
TryTake<T> tryTakeReplacement = (out T value) =>
|
||
|
{
|
||
|
value = default(T);
|
||
|
return false;
|
||
|
};
|
||
|
|
||
|
_tryTake = (out T value) =>
|
||
|
{
|
||
|
value = default(T);
|
||
|
if (Volatile.Read(ref guard) == 0)
|
||
|
{
|
||
|
bool result;
|
||
|
// We need a lock, there is no way around it. IEnumerator is just awful. Use another overload if possible.
|
||
|
lock (enumerator)
|
||
|
{
|
||
|
result = enumerator.MoveNext();
|
||
|
if (result)
|
||
|
{
|
||
|
value = enumerator.Current;
|
||
|
}
|
||
|
}
|
||
|
if (result)
|
||
|
{
|
||
|
_proxy.OnNext(value);
|
||
|
return true;
|
||
|
}
|
||
|
enumerator.Dispose();
|
||
|
Interlocked.CompareExchange(ref guard, 1, 0);
|
||
|
}
|
||
|
if (Interlocked.CompareExchange(ref guard, 2, 1) == 1)
|
||
|
{
|
||
|
_tryTake = tryTakeReplacement;
|
||
|
}
|
||
|
return false;
|
||
|
};
|
||
|
}
|
||
|
|
||
|
public Progressor(TryTake<T> tryTake, bool doneOnFalse)
|
||
|
{
|
||
|
if (tryTake == null)
|
||
|
{
|
||
|
throw new ArgumentNullException("tryTake");
|
||
|
}
|
||
|
var tryTakeCopy = tryTake;
|
||
|
_proxy = new ProxyObservable<T>();
|
||
|
_tryTake = (out T value) =>
|
||
|
{
|
||
|
// This is not an overridable method, and it is not being called on the constructor.
|
||
|
if (tryTakeCopy(out value))
|
||
|
{
|
||
|
_proxy.OnNext(value);
|
||
|
return true;
|
||
|
}
|
||
|
_done = doneOnFalse;
|
||
|
return false;
|
||
|
};
|
||
|
}
|
||
|
|
||
|
public Progressor(TryTake<T> tryTake, Func<bool> isDone)
|
||
|
{
|
||
|
if (tryTake == null)
|
||
|
{
|
||
|
throw new ArgumentNullException("tryTake");
|
||
|
}
|
||
|
if (isDone == null)
|
||
|
{
|
||
|
throw new ArgumentNullException("isDone");
|
||
|
}
|
||
|
var tryTakeCopy = tryTake;
|
||
|
_proxy = new ProxyObservable<T>();
|
||
|
_tryTake = (out T value) =>
|
||
|
{
|
||
|
// This is not an overridable method, and it is not being called on the constructor.
|
||
|
if (tryTakeCopy(out value))
|
||
|
{
|
||
|
_proxy.OnNext(value);
|
||
|
return true;
|
||
|
}
|
||
|
_done = new ValueFuncClosure<bool>(isDone).InvokeReturn();
|
||
|
return false;
|
||
|
};
|
||
|
}
|
||
|
|
||
|
public Progressor(IObservable<T> wrapped)
|
||
|
{
|
||
|
var buffer = new SafeQueue<T>();
|
||
|
wrapped.Subscribe
|
||
|
(
|
||
|
new CustomObserver<T>
|
||
|
(
|
||
|
() => _done = true,
|
||
|
exception => _done = true,
|
||
|
buffer.Add
|
||
|
)
|
||
|
);
|
||
|
_proxy = new ProxyObservable<T>();
|
||
|
|
||
|
_tryTake = (out T value) =>
|
||
|
{
|
||
|
if (buffer.TryTake(out value))
|
||
|
{
|
||
|
_proxy.OnNext(value);
|
||
|
return true;
|
||
|
}
|
||
|
value = default(T);
|
||
|
return false;
|
||
|
};
|
||
|
}
|
||
|
|
||
|
private Progressor(TryTake<T> tryTake, ProxyObservable<T> proxy)
|
||
|
{
|
||
|
_proxy = proxy;
|
||
|
_tryTake = tryTake;
|
||
|
}
|
||
|
|
||
|
public bool IsClosed
|
||
|
{
|
||
|
get { return _tryTake == null; }
|
||
|
}
|
||
|
|
||
|
public static Progressor<T> CreateConverted<TInput>(Progressor<TInput> wrapped, Func<TInput, T> converter)
|
||
|
{
|
||
|
if (wrapped == null)
|
||
|
{
|
||
|
throw new ArgumentNullException("wrapped");
|
||
|
}
|
||
|
if (converter == null)
|
||
|
{
|
||
|
throw new ArgumentNullException("converter");
|
||
|
}
|
||
|
|
||
|
var control = 0;
|
||
|
|
||
|
Predicate<TInput> newFilter = item => Volatile.Read(ref control) == 0;
|
||
|
var buffer = new SafeQueue<T>();
|
||
|
var proxy = new ProxyObservable<T>();
|
||
|
|
||
|
var result = new Progressor<T>(
|
||
|
(out T value) =>
|
||
|
{
|
||
|
Interlocked.Increment(ref control);
|
||
|
try
|
||
|
{
|
||
|
TInput item;
|
||
|
if (buffer.TryTake(out value))
|
||
|
{
|
||
|
proxy.OnNext(value);
|
||
|
return true;
|
||
|
}
|
||
|
else if (wrapped.TryTake(out item))
|
||
|
{
|
||
|
value = converter(item);
|
||
|
proxy.OnNext(value);
|
||
|
return true;
|
||
|
}
|
||
|
value = default(T);
|
||
|
return false;
|
||
|
}
|
||
|
finally
|
||
|
{
|
||
|
Interlocked.Decrement(ref control);
|
||
|
}
|
||
|
},
|
||
|
proxy
|
||
|
);
|
||
|
wrapped.Subscribe
|
||
|
(
|
||
|
new CustomObserver<TInput>
|
||
|
(
|
||
|
() => result._done = true,
|
||
|
exception => result._done = true,
|
||
|
item =>
|
||
|
{
|
||
|
if (newFilter(item))
|
||
|
{
|
||
|
buffer.Add(converter(item));
|
||
|
}
|
||
|
}
|
||
|
)
|
||
|
);
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
public static Progressor<T> CreatedFiltered(Progressor<T> wrapped, Predicate<T> filter)
|
||
|
{
|
||
|
if (wrapped == null)
|
||
|
{
|
||
|
throw new ArgumentNullException("wrapped");
|
||
|
}
|
||
|
if (filter == null)
|
||
|
{
|
||
|
throw new ArgumentNullException("filter");
|
||
|
}
|
||
|
|
||
|
var control = 0;
|
||
|
|
||
|
Predicate<T> newFilter = item => Volatile.Read(ref control) == 0 && filter(item);
|
||
|
var buffer = new SafeQueue<T>();
|
||
|
var proxy = new ProxyObservable<T>();
|
||
|
|
||
|
var result = new Progressor<T>(
|
||
|
(out T value) =>
|
||
|
{
|
||
|
Volatile.Write(ref control, 1);
|
||
|
try
|
||
|
{
|
||
|
again:
|
||
|
if (buffer.TryTake(out value))
|
||
|
{
|
||
|
proxy.OnNext(value);
|
||
|
return true;
|
||
|
}
|
||
|
else if (wrapped.TryTake(out value))
|
||
|
{
|
||
|
if (filter(value))
|
||
|
{
|
||
|
proxy.OnNext(value);
|
||
|
return true;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
goto again;
|
||
|
}
|
||
|
}
|
||
|
value = default(T);
|
||
|
return false;
|
||
|
}
|
||
|
finally
|
||
|
{
|
||
|
Interlocked.Decrement(ref control);
|
||
|
}
|
||
|
},
|
||
|
proxy
|
||
|
);
|
||
|
wrapped.Subscribe
|
||
|
(
|
||
|
new CustomObserver<T>
|
||
|
(
|
||
|
() => result._done = true,
|
||
|
exception => result._done = true,
|
||
|
item =>
|
||
|
{
|
||
|
if (newFilter(item))
|
||
|
{
|
||
|
buffer.Add(item);
|
||
|
}
|
||
|
}
|
||
|
)
|
||
|
);
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
public static Progressor<T> CreatedFilteredConverted<TInput>(Progressor<TInput> wrapped, Predicate<TInput> filter, Func<TInput, T> converter)
|
||
|
{
|
||
|
if (wrapped == null)
|
||
|
{
|
||
|
throw new ArgumentNullException("wrapped");
|
||
|
}
|
||
|
if (filter == null)
|
||
|
{
|
||
|
throw new ArgumentNullException("filter");
|
||
|
}
|
||
|
if (converter == null)
|
||
|
{
|
||
|
throw new ArgumentNullException("converter");
|
||
|
}
|
||
|
|
||
|
var control = 0;
|
||
|
|
||
|
Predicate<TInput> newFilter = item => Volatile.Read(ref control) == 0 && filter(item);
|
||
|
var buffer = new SafeQueue<T>();
|
||
|
var proxy = new ProxyObservable<T>();
|
||
|
|
||
|
var result = new Progressor<T>(
|
||
|
(out T value) =>
|
||
|
{
|
||
|
Interlocked.Increment(ref control);
|
||
|
try
|
||
|
{
|
||
|
TInput item;
|
||
|
again:
|
||
|
if (buffer.TryTake(out value))
|
||
|
{
|
||
|
proxy.OnNext(value);
|
||
|
return true;
|
||
|
}
|
||
|
else if (wrapped.TryTake(out item))
|
||
|
{
|
||
|
if (filter(item))
|
||
|
{
|
||
|
value = converter(item);
|
||
|
proxy.OnNext(value);
|
||
|
return true;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
goto again;
|
||
|
}
|
||
|
}
|
||
|
value = default(T);
|
||
|
return false;
|
||
|
}
|
||
|
finally
|
||
|
{
|
||
|
Interlocked.Decrement(ref control);
|
||
|
}
|
||
|
},
|
||
|
proxy
|
||
|
);
|
||
|
wrapped.Subscribe
|
||
|
(
|
||
|
new CustomObserver<TInput>
|
||
|
(
|
||
|
() => result._done = true,
|
||
|
exception => result._done = true,
|
||
|
item =>
|
||
|
{
|
||
|
if (newFilter(item))
|
||
|
{
|
||
|
buffer.Add(converter(item));
|
||
|
}
|
||
|
}
|
||
|
)
|
||
|
);
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
public static Progressor<T> CreateDistinct(Progressor<T> wrapped)
|
||
|
{
|
||
|
if (wrapped == null)
|
||
|
{
|
||
|
throw new ArgumentNullException("wrapped");
|
||
|
}
|
||
|
|
||
|
var control = 0;
|
||
|
|
||
|
var buffer = new SafeDictionary<T, bool>();
|
||
|
Predicate<T> newFilter = item => Volatile.Read(ref control) == 0;
|
||
|
var proxy = new ProxyObservable<T>();
|
||
|
|
||
|
var result = new Progressor<T>(
|
||
|
(out T value) =>
|
||
|
{
|
||
|
Interlocked.Increment(ref control);
|
||
|
try
|
||
|
{
|
||
|
again:
|
||
|
foreach (var item in buffer.Where(item => !item.Value))
|
||
|
{
|
||
|
value = item.Key;
|
||
|
buffer.Set(value, true);
|
||
|
proxy.OnNext(value);
|
||
|
return true;
|
||
|
}
|
||
|
if (wrapped.TryTake(out value))
|
||
|
{
|
||
|
bool seen;
|
||
|
if (!buffer.TryGetValue(value, out seen) || !seen)
|
||
|
{
|
||
|
buffer.Set(value, true);
|
||
|
proxy.OnNext(value);
|
||
|
return true;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
goto again;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
finally
|
||
|
{
|
||
|
Interlocked.Decrement(ref control);
|
||
|
}
|
||
|
},
|
||
|
proxy
|
||
|
);
|
||
|
wrapped.Subscribe
|
||
|
(
|
||
|
new CustomObserver<T>
|
||
|
(
|
||
|
() => result._done = true,
|
||
|
exception => result._done = true,
|
||
|
item =>
|
||
|
{
|
||
|
if (newFilter(item))
|
||
|
{
|
||
|
buffer.TryAdd(item, false);
|
||
|
}
|
||
|
}
|
||
|
)
|
||
|
);
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
public IEnumerable<T> AsEnumerable()
|
||
|
{
|
||
|
// After enumerating - the consumer of this method must check if the Progressor is closed.
|
||
|
while (true)
|
||
|
{
|
||
|
T item;
|
||
|
var tryTake = _tryTake;
|
||
|
if (tryTake(out item))
|
||
|
{
|
||
|
yield return item;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public void Close()
|
||
|
{
|
||
|
_tryTake = null;
|
||
|
_proxy.OnCompleted();
|
||
|
_proxy = null;
|
||
|
}
|
||
|
|
||
|
public IDisposable Subscribe(IObserver<T> observer)
|
||
|
{
|
||
|
if (_proxy != null)
|
||
|
{
|
||
|
return _proxy.Subscribe(observer);
|
||
|
}
|
||
|
return Disposable.Create(ActionHelper.GetNoopAction());
|
||
|
}
|
||
|
|
||
|
public bool TryTake(out T item)
|
||
|
{
|
||
|
if (_tryTake != null)
|
||
|
{
|
||
|
if (_tryTake.Invoke(out item))
|
||
|
{
|
||
|
return true;
|
||
|
}
|
||
|
if (_done)
|
||
|
{
|
||
|
Close();
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
item = default(T);
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
public IEnumerable<T> While(Predicate<T> condition)
|
||
|
{
|
||
|
if (condition == null)
|
||
|
{
|
||
|
throw new ArgumentNullException("condition");
|
||
|
}
|
||
|
while (true)
|
||
|
{
|
||
|
T item;
|
||
|
var tryTake = _tryTake;
|
||
|
if (tryTake(out item) && condition(item))
|
||
|
{
|
||
|
yield return item;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public IEnumerable<T> While(Func<bool> condition)
|
||
|
{
|
||
|
if (condition == null)
|
||
|
{
|
||
|
throw new ArgumentNullException("condition");
|
||
|
}
|
||
|
while (true)
|
||
|
{
|
||
|
T item;
|
||
|
var tryTake = _tryTake;
|
||
|
if (tryTake(out item) && condition())
|
||
|
{
|
||
|
yield return item;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
#endif
|