Incidentally I forgot to mention that I’d also want to add:

extension SequenceType {
    /// Returns a `BufferedSequence` that wraps `self`.
    /// - SeeAlso: `BufferedSequence<Base>`.
    public var buffered: BufferedSequence<Self> { get }
}

extension BufferedSequence {
    /// Identical to `self`.
    public var buffered: BufferedSequence<Base> { get }
}

extension GeneratorType {
    /// Returns a `BufferedGenerator` that wraps `self`.
    /// - Parameter lookahead: The amount of lookahead to allow. Default is `1`.
    /// - Note: The new generator should be considered a copy of `self` for the
    ///   purposes of evaluating requirements (e.g. for `next()`).
    /// - SeeAlso: `BufferedGenerator<Base>`.
    public func buffered(lookahead: Int = default) -> BufferedGenerator<Self>
}

extension BufferedGenerator {
    /// Returns a new `BufferedGenerator` that wraps `self.base`.
    /// If `lookahead < self.lookahead`, the new generator may have a lookahead
    /// that's larger than `lookahead` if necessary to avoid losing elements.
    /// - Parameter lookahead: The amount of lookahead to allow. Default is `1`.
    /// - Invariant: The sequence of elements returned from calling `next()` on
    ///   the new generator is identical to the sequence of elements that would
    ///   have been returned from calling `next()` on `self` regardless of any
    ///   changes to the lookahead amount.
    /// - Note: The new generator should be considered a copy of `self` for the
    ///   purposes of evaluating requirements (e.g. for `next()`).
    public func buffered(lookahead: Int = default) -> BufferedGenerator<Base>
}

As well as exposing the base sequence/generator on both types through a 
property named `base`.

-Kevin Ballard

> On Dec 31, 2015, at 4:16 PM, Kevin Ballard <[email protected]> wrote:
> 
> BufferedSequence is a sequence adaptor that wraps any underlying sequence and 
> provides a stable `first` property. BufferedGenerator is a generator adaptor 
> that wraps any underlying generator and provides arbitrary lookahead with a 
> `peek(n: Int)` method.
>  
> The method name "peek()" has precedent in various languages (e.g. Rust with 
> std::iter::Peekable, C++ with std::basic_istream::peek, Ruby with 
> Enumerator#peek, etc). I considered the name "lookahead()" but I decided it 
> made more sense to use that name for the property that describes how much 
> lookahead there is.
>  
> The proposed API looks like this:
>  
> /// A sequence adaptor that adds a nondestructive `first` property to any
> /// underlying sequence.
> /// - Note: If the underlying sequence is not destructively "consumed" by
> ///   iteration, then neither is `BufferedSequence`.
> public class BufferedSequence<Base : SequenceType> : SequenceType {
>     public init(_ base: Base)
> 
>     /// Returns ` BufferedGenerator` with a lookahead size of `1`.
>     public func generate() -> 
> BufferedSequence.BufferedGenerator<Base.Generator>
> 
>     /// Returns the first element of the underlying sequence, 
> **nondestructively**.
>     public var first: Base.Generator.Element? { get }
> }
> 
> /// A generator adaptor that adds a nondestructive `peek()` method to any
> /// underlying generator.
> public struct BufferedGenerator<Base : GeneratorType> : GeneratorType {
>     /// Construct an instance that buffers access to an underlying generator.
>     /// - Parameter base: The underlying generator.
>     /// - Parameter lookahead: The amount of lookahead to allow. Default is 
> `1`.
>     ///   Values less than `1` will be treated the same as `1`.
>     public init(_ base: Base, lookahead: Int = default)
> 
>     /// The amount of lookahead that this generator offers.
>     /// - Invariant: `lookahead >= 1`.
>     public let lookahead: Int
> 
>     /// Advance to the next element and return it, or `nil` if no next 
> element exists.
>     ///
>     /// - Requires: Neither `next()` nor `peek()` have been applied to a copy 
> of
>     ///   `self` since the copy was made, and no preceding call to 
> `self.next()` has
>     ///   returned `nil`.
>     public mutating func next() -> Base.Element?
> 
>     /// Returns the value that will be returned from subsequent calls to 
> `next()`.
>     /// - Parameter n: The number of elements to look ahead. Default is `0`. 
> A value
>     ///   of `0` means to look at the next element.
>     /// - Precondition: `n >= 0 && n < lookahead`.
>     /// - Requires: Neither `next()` nor `peek()` have been applied to a copy 
> of
>     ///   `self` since the copy was made, and no preceding call to 
> `self.next()` has
>     ///   returned `nil`.
>     /// - Note: It is safe to peek at values past the end of the underlying 
> generator
>     ///  (`peek()` will return `nil` in such cases). It is also safe to call 
> `peek()`
>     ///  repeatedly, even after it's returned `nil`, and similarly it is safe 
> to call
>     ///  `next()` after `peek()` has returned `nil`.
>     public mutating func peek(n: Int = default) -> Base.Element?
> }
> 
> BufferedSequence is a class because the generate() function needs to mutate 
> it. After the `first` property has been accessed, it needs to cache the 
> generator it used for that so it can return it from the next call to 
> generate(), but it also needs to nil out that cache at that time so it 
> doesn't try and return the same generator instance a second time on a 
> subsequent call to generate() (this way BufferedSequence can be written to 
> support non-destructive iteration if the underlying sequence is 
> non-destructive).
>  
> I've already started sketching out an implementation as well. I believe it 
> should be possible to optimize BufferedGenerator for a lookahead of 1 to 
> avoid the heap allocation of an array.
>  
> -Kevin Ballard
>  

_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to