/// <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)); }
/// <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))); }
/// <summary> /// Applies an accumulator function over the values yielded from /// a data-producer. 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="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="seed">The initial value for the accumulator</param> /// <param name="source">The data-source for the values</param> public static IFuture <TAccumulate> Aggregate <TSource, TAccumulate> (this IDataProducer <TSource> source, TAccumulate seed, DotNet20.Func <TAccumulate, TSource, TAccumulate> func) { return(source.Aggregate(seed, func, x => x)); }
/// <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); }
internal ReverseLineReader(DotNet20.Func <Stream> streamSource, Encoding encoding, int bufferSize) { this.streamSource = streamSource; this.encoding = encoding; this.bufferSize = bufferSize; if (encoding.IsSingleByte) { // For a single byte encoding, every byte is the start (and end) of a character characterStartDetector = (pos, data) => true; } else if (encoding is UnicodeEncoding) { // For UTF-16, even-numbered positions are the start of a character characterStartDetector = (pos, data) => (pos & 1) == 0; } else if (encoding is UTF8Encoding) { // For UTF-8, bytes with the top bit clear or the second bit set are the start of a character // See http://www.cl.cam.ac.uk/~mgk25/unicode.html characterStartDetector = (pos, data) => (data & 0x80) == 0 || (data & 0x40) != 0; } else { throw new ArgumentException("Only single byte, UTF-8 and Unicode encodings are permitted"); } }
/// <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); }
/// <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); }
/// <summary> /// Sorts the elements in the entire System.Collections.Generic.List{T} using /// a projection. /// </summary> /// <param name="source">Data source</param> /// <param name="selector">The projection to use to obtain values for comparison</param> /// <param name="comparer">The comparer to use to compare projected values (on null to use the default comparer)</param> /// <param name="descending">Should the list be sorted ascending or descending?</param> public static void Sort <T, TValue>(this List <T> source, DotNet20.Func <T, TValue> selector, IComparer <TValue> comparer, bool descending) { if (source == null) { throw new ArgumentNullException("source"); } if (comparer == null) { comparer = Comparer <TValue> .Default; } IComparer <T> itemComparer = new ProjectionComparer <T, TValue>(selector, comparer); if (descending) { itemComparer = itemComparer.Reverse(); } source.Sort(itemComparer); }
/// <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); }
/// <summary> /// Orders the values from a data-source by a transform on each term, ascending /// </summary> /// <param name="source">The original data-producer</param> /// <param name="selector">Returns the value (for each term) by which to order the sequence</param> /// <returns>A data-producer that yeilds the sequence ordered /// by the selected value</returns> /// <remarks>This will force all data to be buffered</remarks> public static IOrderedDataProducer <TSource> OrderBy <TSource, TKey>(this IDataProducer <TSource> source, DotNet20.Func <TSource, TKey> selector) { return(OrderBy(source, selector, Comparer <TKey> .Default, false)); }
/// <summary> /// Further orders the values from an ordered data-source by a transform on each term, descending /// (the sort operation is only applied once for the combined ordering) /// </summary> /// <param name="source">The original data-producer and ordering</param> /// <param name="selector">Returns the value (for each term) by which to order the sequence</param> /// <returns>A data-producer that yeilds the sequence ordered /// by the selected value</returns> /// <remarks>This will force all data to be buffered</remarks> public static IOrderedDataProducer <TSource> ThenByDescending <TSource, TKey>(this IOrderedDataProducer <TSource> source, DotNet20.Func <TSource, TKey> selector) { return(ThenBy(source, selector, Comparer <TKey> .Default, true)); }
/// <summary> /// Further orders the values from an ordered data-source by a transform on each term, ascending /// (the sort operation is only applied once for the combined ordering) /// </summary> /// <param name="source">The original data-producer and ordering</param> /// <param name="selector">Returns the value (for each term) by which to order the sequence</param> /// <param name="comparer">Comparer to compare the selected values</param> /// <returns>A data-producer that yeilds the sequence ordered /// by the selected value</returns> /// <remarks>This will force all data to be buffered</remarks> public static IOrderedDataProducer <TSource> ThenBy <TSource, TKey>(this IOrderedDataProducer <TSource> source, DotNet20.Func <TSource, TKey> selector, IComparer <TKey> comparer) { return(ThenBy(source, selector, comparer, false)); }
/// <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 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))); }
private static IOrderedDataProducer <TSource> ThenBy <TSource, TKey>(IOrderedDataProducer <TSource> source, DotNet20.Func <TSource, TKey> selector, IComparer <TKey> comparer, bool descending) { comparer.ThrowIfNull("comparer"); IComparer <TSource> itemComparer = new ProjectionComparer <TSource, TKey>(selector, comparer); if (descending) { itemComparer = itemComparer.Reverse(); } itemComparer = new LinkedComparer <TSource>(source.Comparer, itemComparer); return(new OrderedDataProducer <TSource>(source, itemComparer)); }
/// <summary> /// Returns an iterator which begins at the end of this range, /// applying the given step delegate on each iteration until the /// start is reached or passed. The start and end points are included /// or excluded according to this range. /// </summary> /// <param name="step">Delegate to apply to the "current value" on each iteration</param> public RangeIterator <T> FromEnd(DotNet20.Func <T, T> step) { return(new RangeIterator <T>(this, step, false)); }
/// <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> /// Creates a LineReader from a stream source. The delegate is only /// called when the enumerator is fetched. /// </summary> /// <param name="streamSource">Data source</param> /// <param name="encoding">Encoding to use to decode the stream into text</param> public ReverseLineReader(DotNet20.Func <Stream> streamSource, Encoding encoding) : this(streamSource, encoding, DefaultBufferSize) { }
/// <summary> /// Creates a LineReader from a stream source. The delegate is only /// called when the enumerator is fetched. UTF-8 is used to decode /// the stream into text. /// </summary> /// <param name="streamSource">Data source</param> public ReverseLineReader(DotNet20.Func <Stream> streamSource) : this(streamSource, Encoding.UTF8) { }
/// <summary> /// Creates an instance of ProjectionEqualityComparer using the specified projection. /// The ignored parameter is solely present to aid type inference. /// </summary> /// <typeparam name="TSource">Type parameter for the elements to be compared</typeparam> /// <typeparam name="TKey">Type parameter for the keys to be compared, after being projected from the elements</typeparam> /// <param name="ignored">Value is ignored - type may be used by type inference</param> /// <param name="projection">Projection to use when determining the key of an element</param> /// <returns>A comparer which will compare elements by projecting each element to its key, and comparing keys</returns> public static ProjectionEqualityComparer <TSource, TKey> Create <TSource, TKey> (TSource ignored, DotNet20.Func <TSource, TKey> projection) { return(new ProjectionEqualityComparer <TSource, TKey>(projection)); }
/// <summary> /// Orders the values from a data-source by a transform on each term, descending /// </summary> /// <param name="source">The original data-producer</param> /// <param name="selector">Returns the value (for each term) by which to order the sequence</param> /// <param name="comparer">Comparer to compare the selected values</param> /// <returns>A data-producer that yeilds the sequence ordered /// by the selected value</returns> /// <remarks>This will force all data to be buffered</remarks> public static IOrderedDataProducer <TSource> OrderByDescending <TSource, TKey>(this IDataProducer <TSource> source, DotNet20.Func <TSource, TKey> selector, IComparer <TKey> comparer) { return(OrderBy(source, selector, comparer, true)); }
/// <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 <long> LongCount <TSource>(this IDataProducer <TSource> source, DotNet20.Func <TSource, bool> predicate) { source.ThrowIfNull("source"); predicate.ThrowIfNull("predicate"); Future <long> ret = new Future <long>(); int count = 0; source.DataProduced += t => { if (predicate(t)) { count++; } }; source.EndOfData += () => ret.Value = count; return(ret); }
private static IOrderedDataProducer <TSource> OrderBy <TSource, TKey>(IDataProducer <TSource> source, DotNet20.Func <TSource, TKey> selector, IComparer <TKey> comparer, bool descending) { source.ThrowIfNull("source"); comparer.ThrowIfNull("comparer"); IComparer <TSource> itemComparer = new ProjectionComparer <TSource, TKey>(selector, comparer); if (descending) { itemComparer = itemComparer.Reverse(); } // first, discard any existing "order by"s by going back to the producer IOrderedDataProducer <TSource> orderedProducer; bool first = true; while ((orderedProducer = source as IOrderedDataProducer <TSource>) != null) { if (first) { // keep the top-most comparer to enforce a balanced sort itemComparer = new LinkedComparer <TSource>(itemComparer, orderedProducer.Comparer); first = false; } source = orderedProducer.BaseProducer; } return(new OrderedDataProducer <TSource>(source, itemComparer)); }
/// <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 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> /// Creates an ascending iterator over the given range with the given step function /// </summary> public RangeIterator(Range <T> range, DotNet20.Func <T, T> step) : this(range, step, true) { }
/// <summary> /// Sorts the elements in the entire System.Collections.Generic.List{T} using /// a projection. /// </summary> /// <param name="source">Data source</param> /// <param name="selector">The projection to use to obtain values for comparison</param> public static void Sort <T, TValue>(this List <T> source, DotNet20.Func <T, TValue> selector) { Sort <T, TValue>(source, selector, null, false); }
/// <summary> /// Returns an iterator which begins at the start of this range, /// applying the given step delegate on each iteration until the /// end is reached or passed. The start and end points are included /// or excluded according to this range. /// </summary> /// <param name="step">Delegate to apply to the "current value" on each iteration</param> public RangeIterator <T> FromStart(DotNet20.Func <T, T> step) { return(new RangeIterator <T>(this, step)); }