Beispiel #1
0
        /// <summary>
        /// Applies an accumulator function over the values yielded from
        /// a data-producer. The first value in the seqnence
        /// is used as the initial accumulator value, and the specified function is used
        /// to select the result value. If the sequence is empty then
        /// the default value for TSource is returned.
        /// </summary>
        /// <typeparam name="TSource">The type of data yielded by the data-source</typeparam>
        /// <param name="func">Accumulator function to be applied to each term in the sequence</param>
        /// <param name="source">The data-source for the values</param>
        public static IFuture <TSource> Aggregate <TSource>
            (this IDataProducer <TSource> source,
            DotNet20.Func <TSource, TSource, TSource> func)
        {
            source.ThrowIfNull("source");
            func.ThrowIfNull("func");

            Future <TSource> ret   = new Future <TSource>();
            bool             first = true;

            TSource current = default(TSource);

            source.DataProduced += value =>
            {
                if (first)
                {
                    first   = false;
                    current = value;
                }
                else
                {
                    current = func(current, value);
                }
            };
            source.EndOfData += () => ret.Value = current;

            return(ret);
        }
Beispiel #2
0
        /// <summary>
        /// Returns an iterator which steps through the range, applying the specified
        /// step delegate on each iteration. The method determines whether to begin
        /// at the start or end of the range based on whether the step delegate appears to go
        /// "up" or "down". The step delegate is applied to the start point. If the result is
        /// more than the start point, the returned iterator begins at the start point; otherwise
        /// it begins at the end point.
        /// </summary>
        /// <param name="step">Delegate to apply to the "current value" on each iteration</param>
        public RangeIterator <T> Step(DotNet20.Func <T, T> step)
        {
            step.ThrowIfNull("step");
            bool ascending = (this.comparer.Compare(this.start, step(this.start)) < 0);

            return(ascending ? this.FromStart(step) : this.FromEnd(step));
        }
Beispiel #3
0
        /// <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);
        }
Beispiel #4
0
        /// <summary>
        /// Returns a future to a single value from a data-source that matches the
        /// specified condition, or the default value if no matching values
        /// are encountered. An exception
        /// is thrown if multiple matching values are encountered.
        /// </summary>
        /// <param name="source">The source data-producer.</param>
        /// <param name="predicate">The condition to be satisfied.</param>
        /// <exception cref="InvalidOperationException">Multiple matching terms are encountered.</exception>
        public static IFuture <TSource> SingleOrDefault <TSource>(this IDataProducer <TSource> source, DotNet20.Func <TSource, bool> predicate)
        {
            source.ThrowIfNull("source");
            predicate.ThrowIfNull("predicate");

            Future <TSource> ret = new Future <TSource>();

            TSource output   = default(TSource);
            bool    gotValue = false;

            source.DataProduced += value =>
            {
                if (predicate(value))
                {
                    if (gotValue)
                    {
                        throw new InvalidOperationException("More than one element in source data");
                    }
                    output   = value;
                    gotValue = true;
                }
            };

            source.EndOfData += () =>
            {
                ret.Value = output;
            };

            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 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);
        }
Beispiel #7
0
        /// <summary>
        /// Returns the last 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 last 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> Last <TSource>(this IDataProducer <TSource> source, DotNet20.Func <TSource, bool> predicate)
        {
            source.ThrowIfNull("source");
            predicate.ThrowIfNull("predicate");

            Future <TSource> ret = new Future <TSource>();

            bool    gotData = false;
            TSource prev    = default(TSource);

            source.DataProduced += value =>
            {
                if (predicate(value))
                {
                    prev    = value;
                    gotData = true;
                }
            };
            source.EndOfData += () =>
            {
                if (!gotData)
                {
                    throw new InvalidOperationException("Sequence is empty");
                }
                ret.Value = prev;
            };

            return(ret);
        }
        /// <summary>
        /// Filters a data-producer based on a predicate on each value
        /// </summary>
        /// <param name="source">The data-producer to be filtered</param>
        /// <param name="predicate">The condition to be satisfied</param>
        /// <returns>A filtered data-producer; only matching values will raise the DataProduced event</returns>
        public static IDataProducer <TSource> Where <TSource>(this IDataProducer <TSource> source,
                                                              DotNet20.Func <TSource, bool> predicate)
        {
            predicate.ThrowIfNull("predicate");

            return(source.Where((x, index) => predicate(x)));
        }
Beispiel #9
0
        /// <summary>
        /// Returns a future to the minumum of a sequence of values that are
        /// obtained by taking a transform of the input sequence, using the default comparer
        /// </summary>
        /// <remarks>Null values are removed from the minimum</remarks>
        public static IFuture <TResult> Min <TSource, TResult>
            (this IDataProducer <TSource> source, DotNet20.Func <TSource, TResult> selector)
        {
            source.ThrowIfNull("source");
            selector.ThrowIfNull("selector");

            return(source.Select(selector).Min());
        }
        /// <summary>
        /// Returns a projection on the data-producer, using a transformation
        /// (involving the elements's index in the sequence) to
        /// map each element into a new form.
        /// </summary>
        /// <typeparam name="TSource">The source type</typeparam>
        /// <typeparam name="TResult">The projected type</typeparam>
        /// <param name="source">The source data-producer</param>
        /// <param name="projection">The transformation to apply to each element.</param>
        public static IDataProducer <TResult> Select <TSource, TResult>(this IDataProducer <TSource> source, DotNet20.Func <TSource, int, TResult> projection)
        {
            source.ThrowIfNull("source");
            projection.ThrowIfNull("projection");

            DataProducer <TResult> ret = new DataProducer <TResult>();
            int index = 0;

            source.DataProduced += value => ret.Produce(projection(value, index++));
            source.EndOfData    += () => ret.End();
            return(ret);
        }
Beispiel #11
0
        /// <summary>
        /// Creates an iterator over the given range with the given step function,
        /// with the specified direction.
        /// </summary>
        public RangeIterator(Range <T> range, DotNet20.Func <T, T> step, bool ascending)
        {
            step.ThrowIfNull("step");

            if ((ascending && range.Comparer.Compare(range.Start, step(range.Start)) >= 0) ||
                (!ascending && range.Comparer.Compare(range.End, step(range.End)) <= 0))
            {
                throw new ArgumentException("step does nothing, or progresses the wrong way");
            }
            this.ascending = ascending;
            this.range     = range;
            this.step      = step;
        }
        /// <summary>
        /// Applies an accumulator function over the values yielded from
        /// a data-producer, performing a transformation on the final
        /// accululated value. The specified seed value
        /// is used as the initial accumulator value, and the specified function is used
        /// to select the result value
        /// </summary>
        /// <typeparam name="TSource">The type of data yielded by the data-source</typeparam>
        /// <typeparam name="TResult">The final result type (after the accumulator has been transformed)</typeparam>
        /// <typeparam name="TAccumulate">The type to be used for the accumulator</typeparam>
        /// <param name="func">Accumulator function to be applied to each term in the sequence</param>
        /// <param name="resultSelector">Transformation to apply to the final
        /// accumulated value to produce the result</param>
        /// <param name="seed">The initial value for the accumulator</param>
        /// <param name="source">The data-source for the values</param>
        public static IFuture <TResult> Aggregate <TSource, TAccumulate, TResult>
            (this IDataProducer <TSource> source,
            TAccumulate seed, DotNet20.Func <TAccumulate, TSource, TAccumulate> func, DotNet20.Func <TAccumulate, TResult> resultSelector)
        {
            source.ThrowIfNull("source");
            func.ThrowIfNull("func");
            resultSelector.ThrowIfNull("resultSelector");

            Future <TResult> result = new Future <TResult>();

            TAccumulate current = seed;

            source.DataProduced += value => current = func(current, value);
            source.EndOfData    += () => result.Value = resultSelector(current);

            return(result);
        }
Beispiel #13
0
        /// <summary>
        /// Returns the number of elements in the specified sequence satisfy a condition,
        /// as a future value.
        /// </summary>
        /// <typeparam name="TSource">The type of the elements of source.</typeparam>
        /// <param name="source">A sequence that contains elements to be tested and counted.</param>
        /// <param name="predicate">A function to test each element for a condition.</param>
        /// <returns>A number that represents how many elements in the sequence satisfy
        /// the condition in the predicate function, as a future value.
        /// The actual count can only be retrieved after the source has indicated the end
        /// of its data.
        /// </returns>
        public static IFuture <int> Count <TSource>(this IDataProducer <TSource> source, DotNet20.Func <TSource, bool> predicate)
        {
            source.ThrowIfNull("source");
            predicate.ThrowIfNull("predicate");
            Future <int> ret   = new Future <int>();
            int          count = 0;

            source.DataProduced += t =>
            {
                if (predicate(t))
                {
                    count++;
                }
            };
            source.EndOfData += () => ret.Value = count;

            return(ret);
        }
        /// <summary>
        /// Filters a data-producer based on a predicate on each value; the index
        /// in the sequence is used in the predicate
        /// </summary>
        /// <param name="source">The data-producer to be filtered</param>
        /// <param name="predicate">The condition to be satisfied</param>
        /// <returns>A filtered data-producer; only matching values will raise the DataProduced event</returns>
        public static IDataProducer <TSource> Where <TSource>(this IDataProducer <TSource> source, DotNet20.Func <TSource, int, bool> predicate)
        {
            source.ThrowIfNull("source");
            predicate.ThrowIfNull("predicate");

            DataProducer <TSource> ret = new DataProducer <TSource>();

            int index = 0;

            source.DataProduced += value =>
            {
                if (predicate(value, index++))
                {
                    ret.Produce(value);
                }
            };
            source.EndOfData += () => ret.End();
            return(ret);
        }
Beispiel #15
0
        /// <summary>
        /// Returns the last 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> LastOrDefault <TSource>(this IDataProducer <TSource> source, DotNet20.Func <TSource, bool> predicate)
        {
            source.ThrowIfNull("source");
            predicate.ThrowIfNull("predicate");

            Future <TSource> ret = new Future <TSource>();

            TSource prev = default(TSource);

            source.DataProduced += value =>
            {
                if (predicate(value))
                {
                    prev = value;
                }
            };
            source.EndOfData += () =>
            {
                ret.Value = prev;
            };

            return(ret);
        }
Beispiel #16
0
        /// <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);
        }
Beispiel #17
0
        /// <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);
        }
 /// <summary>
 /// Returns a projection on the data-producer, using a transformation to
 /// map each element into a new form.
 /// </summary>
 /// <typeparam name="TSource">The source type</typeparam>
 /// <typeparam name="TResult">The projected type</typeparam>
 /// <param name="source">The source data-producer</param>
 /// <param name="projection">The transformation to apply to each element.</param>
 public static IDataProducer <TResult> Select <TSource, TResult>(this IDataProducer <TSource> source, DotNet20.Func <TSource, TResult> projection)
 {
     projection.ThrowIfNull("projection");
     return(source.Select((t, index) => projection(t)));
 }
        /// <summary>
        /// Returns a data-producer that will ignore the
        /// elements from the start of a sequence while a condition
        /// 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, bool> predicate)
        {
            predicate.ThrowIfNull("predicate");

            return(source.SkipWhile((t, index) => predicate(t)));
        }
Beispiel #20
0
        /// <summary>
        /// Returns a future that indicates whether all values
        /// yielded by the data-producer satisfy a given condition.
        /// The future will return true for an empty sequence or
        /// where all values satisfy the condition, else false
        /// (if any value value fails to satisfy the condition).
        /// </summary>
        /// <param name="source">The data-producer to be monitored.</param>
        /// <param name="predicate">The condition that must be satisfied by all terms.</param>
        public static IFuture <bool> All <TSource>(this IDataProducer <TSource> source, DotNet20.Func <TSource, bool> predicate)
        {
            predicate.ThrowIfNull("predicate");

            return(FutureProxy <bool> .FromFuture(source.Any(value => !predicate(value)), value => !value));
        }