/// <summary> /// Returns a data-producer that will ignore the /// elements from the start of a sequence while a condition /// (involving the elements's index in the sequence) /// is satsified; when the condition fails for an element, /// that element and all subsequent elements are yielded. /// </summary> /// <param name="source">The source data-producer</param> /// <param name="predicate">The condition to skip elements</param> public static IDataProducer <TSource> SkipWhile <TSource>(this IDataProducer <TSource> source, DotNet20.Func <TSource, int, bool> predicate) { source.ThrowIfNull("source"); predicate.ThrowIfNull("predicate"); DataProducer <TSource> ret = new DataProducer <TSource>(); Action completion = () => ret.End(); bool skipping = true; int index = 0; source.DataProduced += value => { if (skipping) { skipping = predicate(value, index++); } // Note - not an else clause! if (!skipping) { ret.Produce(value); } }; source.EndOfData += completion; return(ret); }
/// <summary> /// Returns a data-producer that will yield a specified number of /// contiguous elements from the start of a sequence - i.e. /// "the first <x> elements". /// </summary> /// <param name="source">The source data-producer</param> /// <param name="count">The maximum number of elements to return</param> public static IDataProducer <TSource> Take <TSource>(this IDataProducer <TSource> source, int count) { source.ThrowIfNull("source"); DataProducer <TSource> ret = new DataProducer <TSource>(); Action completion = () => ret.End(); Action <TSource> production = null; production = value => { if (count > 0) { ret.Produce(value); count--; } if (count <= 0) { source.EndOfData -= completion; source.DataProduced -= production; ret.End(); } }; source.DataProduced += production; source.EndOfData += completion; return(ret); }
/// <summary> /// Returns a data-producer that will yield /// elements a sequence as long as a condition /// (involving the element's index in the sequence) /// is satsified; when the condition fails for an element, /// that element and all subsequent elements are ignored. /// </summary> /// <param name="source">The source data-producer</param> /// <param name="predicate">The condition to yield elements</param> public static IDataProducer <TSource> TakeWhile <TSource>(this IDataProducer <TSource> source, DotNet20.Func <TSource, int, bool> predicate) { source.ThrowIfNull("source"); predicate.ThrowIfNull("predicate"); DataProducer <TSource> ret = new DataProducer <TSource>(); Action completion = () => ret.End(); Action <TSource> production = null; int index = 0; production = value => { if (!predicate(value, index++)) { ret.End(); source.DataProduced -= production; source.EndOfData -= completion; } else { ret.Produce(value); } }; source.DataProduced += production; source.EndOfData += completion; return(ret); }
/// <summary> /// Returns a future that indicates whether any suitable values are /// yielded by the data-producer. The future will return false /// for an empty sequence or one with no matching values, or true for a sequence with matching values. /// </summary> /// <param name="source">The data-producer to be monitored.</param> /// <param name="predicate">The condition that must be satisfied.</param> public static IFuture <bool> Any <TSource>(this IDataProducer <TSource> source, DotNet20.Func <TSource, bool> predicate) { source.ThrowIfNull("source"); predicate.ThrowIfNull("predicate"); Future <bool> ret = new Future <bool>(); Action <TSource> production = null; Action completion = () => ret.Value = false; production = value => { if (predicate(value)) { ret.Value = true; source.DataProduced -= production; source.EndOfData -= completion; } }; source.DataProduced += production; source.EndOfData += completion; return(ret); }
/// <summary> /// Returns a future to the element at the given position in the sequence, /// or the default-value if the specified index is never reached /// </summary> /// <param name="source">The data-producer</param> /// <param name="index">The index of the desired trem in the sequence</param> /// <exception cref="ArgumentOutOfRangeException">If the specified index is negative</exception> public static IFuture <TSource> ElementAtOrDefault <TSource>(this IDataProducer <TSource> source, int index) { source.ThrowIfNull("source"); if (index < 0) { throw new ArgumentOutOfRangeException("index"); } Future <TSource> ret = new Future <TSource>(); Action completion = () => ret.Value = default(TSource); Action <TSource> production = null; production = value => { if (index == 0) { ret.Value = value; source.DataProduced -= production; source.EndOfData -= completion; } else { index--; } }; source.DataProduced += production; source.EndOfData += completion; return(ret); }
/// <summary> /// Returns a future that indicates whether any values are /// yielded by the data-producer. The future will return false /// for an empty sequence, or true for a sequence with values. /// </summary> /// <param name="source">The data-producer to be monitored.</param> public static IFuture <bool> Any <TSource>(this IDataProducer <TSource> source) { source.ThrowIfNull("source"); Future <bool> ret = new Future <bool>(); Action <TSource> production = null; Action completion = () => ret.Value = false; production = value => { ret.Value = true; source.DataProduced -= production; source.EndOfData -= completion; }; source.DataProduced += production; source.EndOfData += completion; return(ret); }
/// <summary> /// Returns a future to the first value from a sequence that matches the given condition, or the default /// for that type if no matching value is produced. /// </summary> /// <param name="source">The source data-producer.</param> /// <param name="predicate">The condition to be satisfied.</param> public static IFuture <TSource> FirstOrDefault <TSource>(this IDataProducer <TSource> source, DotNet20.Func <TSource, bool> predicate) { source.ThrowIfNull("source"); predicate.ThrowIfNull("predicate"); Future <TSource> ret = new Future <TSource>(); Action completion = () => ret.Value = default(TSource); Action <TSource> production = null; production = t => { if (predicate(t)) { ret.Value = t; source.EndOfData -= completion; source.DataProduced -= production; } }; source.DataProduced += production; source.EndOfData += completion; return(ret); }
/// <summary> /// Returns the first element in a sequence that satisfies a specified condition, as a future value. /// </summary> /// <typeparam name="TSource">The type of the elements of source.</typeparam> /// <param name="source">The sequence to an element from.</param> /// <param name="predicate">A function to test each element for a condition.</param> /// <returns>The first element in the specified sequence that passes the test in /// the specified predicate function, as a future value. /// The actual value can only be retrieved after the source has indicated the end /// of its data. /// </returns> public static IFuture <TSource> First <TSource>(this IDataProducer <TSource> source, DotNet20.Func <TSource, bool> predicate) { source.ThrowIfNull("source"); predicate.ThrowIfNull("predicate"); Future <TSource> ret = new Future <TSource>(); Action completion = () => { throw new InvalidOperationException("Sequence is empty"); }; Action <TSource> production = null; production = t => { if (predicate(t)) { ret.Value = t; source.EndOfData -= completion; source.DataProduced -= production; } }; source.DataProduced += production; source.EndOfData += completion; return(ret); }