mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
These APIs are from the Swift 1.2 => Swift 2.0 transition, and are not relevant anymore. Removing them reduces the surface area of the library that needs to be reviewed.
200 lines
7.2 KiB
Swift
200 lines
7.2 KiB
Swift
//===--- LazySequence.swift -----------------------------------------------===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See http://swift.org/LICENSE.txt for license information
|
|
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
/// A sequence on which normally-eager operations such as `map` and
|
|
/// `filter` are implemented lazily.
|
|
///
|
|
/// Lazy sequences can be used to avoid needless storage allocation
|
|
/// and computation, because they use an underlying sequence for
|
|
/// storage and compute their elements on demand. For example,
|
|
///
|
|
/// [1, 2, 3].lazy.map { $0 * 2 }
|
|
///
|
|
/// is a sequence containing { `2`, `4`, `6` }. Each time an element
|
|
/// of the lazy sequence is accessed, an element of the underlying
|
|
/// array is accessed and transformed by the closure.
|
|
///
|
|
/// Sequence operations taking closure arguments, such as `map` and
|
|
/// `filter`, are normally eager: they use the closure immediately and
|
|
/// return a new array. Using the `lazy` property gives the standard
|
|
/// library explicit permission to store the closure and the sequence
|
|
/// in the result, and defer computation until it is needed.
|
|
///
|
|
/// To add new lazy sequence operations, extend this protocol with
|
|
/// methods that return lazy wrappers that are themselves
|
|
/// `LazySequenceType`s. For example, given an eager `scan`
|
|
/// method defined as follows
|
|
///
|
|
/// extension SequenceType {
|
|
/// /// Returns an array containing the results of
|
|
/// ///
|
|
/// /// p.reduce(initial, combine: combine)
|
|
/// ///
|
|
/// /// for each prefix `p` of `self`, in order from shortest to
|
|
/// /// longest. For example:
|
|
/// ///
|
|
/// /// (1..<6).scan(0, combine: +) // [0, 1, 3, 6, 10, 15]
|
|
/// ///
|
|
/// /// - Complexity: O(N)
|
|
/// func scan<ResultElement>(
|
|
/// initial: ResultElement,
|
|
/// @noescape combine: (ResultElement, Generator.Element)->ResultElement
|
|
/// ) -> [ResultElement] {
|
|
/// var result = [initial]
|
|
/// for x in self {
|
|
/// result.append(combine(result.last!, x))
|
|
/// }
|
|
/// return result
|
|
/// }
|
|
/// }
|
|
///
|
|
/// we can build a sequence that lazily computes the elements in the
|
|
/// result of `scan`:
|
|
///
|
|
/// struct LazyScanGenerator<Base: GeneratorType, ResultElement>
|
|
/// : GeneratorType {
|
|
/// mutating func next() -> ResultElement? {
|
|
/// return nextElement.map { result in
|
|
/// nextElement = base.next().map { combine(result, $0) }
|
|
/// return result
|
|
/// }
|
|
/// }
|
|
/// private var nextElement: ResultElement? // The next result of next().
|
|
/// private var base: Base // The underlying generator.
|
|
/// private let combine: (ResultElement, Base.Element)->ResultElement
|
|
/// }
|
|
///
|
|
/// struct LazyScanSequence<Base: SequenceType, ResultElement>
|
|
/// : LazySequenceType // Chained operations on self are lazy, too
|
|
/// {
|
|
/// func generate() -> LazyScanGenerator<Base.Generator, ResultElement> {
|
|
/// return LazyScanGenerator(
|
|
/// nextElement: initial, base: base.generate(), combine: combine)
|
|
/// }
|
|
/// private let initial: ResultElement
|
|
/// private let base: Base
|
|
/// private let combine:
|
|
/// (ResultElement, Base.Generator.Element)->ResultElement
|
|
/// }
|
|
///
|
|
/// and finally, we can give all lazy sequences a lazy `scan` method:
|
|
///
|
|
/// extension LazySequenceType {
|
|
/// /// Returns a sequence containing the results of
|
|
/// ///
|
|
/// /// p.reduce(initial, combine: combine)
|
|
/// ///
|
|
/// /// for each prefix `p` of `self`, in order from shortest to
|
|
/// /// longest. For example:
|
|
/// ///
|
|
/// /// Array((1..<6).lazy.scan(0, combine: +)) // [0, 1, 3, 6, 10, 15]
|
|
/// ///
|
|
/// /// - Complexity: O(1)
|
|
/// func scan<ResultElement>(
|
|
/// initial: ResultElement,
|
|
/// combine: (ResultElement, Generator.Element)->ResultElement
|
|
/// ) -> LazyScanSequence<Self, ResultElement> {
|
|
/// return LazyScanSequence(
|
|
/// initial: initial, base: self, combine: combine)
|
|
/// }
|
|
/// }
|
|
///
|
|
/// - See also: `LazySequence`, `LazyCollectionType`, `LazyCollection`
|
|
///
|
|
/// - Note: The explicit permission to implement further operations
|
|
/// lazily applies only in contexts where the sequence is statically
|
|
/// known to conform to `LazySequenceType`. Thus, side-effects such
|
|
/// as the accumulation of `result` below are never unexpectedly
|
|
/// dropped or deferred:
|
|
///
|
|
/// extension SequenceType where Generator.Element == Int {
|
|
/// func sum() -> Int {
|
|
/// var result = 0
|
|
/// _ = self.map { result += $0 }
|
|
/// return result
|
|
/// }
|
|
/// }
|
|
///
|
|
/// [We don't recommend that you use `map` this way, because it
|
|
/// creates and discards an array. `sum` would be better implemented
|
|
/// using `reduce`].
|
|
public protocol LazySequenceType : SequenceType {
|
|
/// A `SequenceType` that can contain the same elements as this one,
|
|
/// possibly with a simpler type.
|
|
///
|
|
/// - See also: `elements`
|
|
typealias Elements: SequenceType = Self
|
|
|
|
/// A sequence containing the same elements as this one, possibly with
|
|
/// a simpler type.
|
|
///
|
|
/// When implementing lazy operations, wrapping `elements` instead
|
|
/// of `self` can prevent result types from growing an extra
|
|
/// `LazySequence` layer. For example,
|
|
///
|
|
/// _prext_ example neeeded
|
|
///
|
|
/// Note: this property need not be implemented by conforming types,
|
|
/// it has a default implementation in a protocol extension that
|
|
/// just returns `self`.
|
|
var elements: Elements {get}
|
|
}
|
|
|
|
/// When there's no special associated `Elements` type, the `elements`
|
|
/// property is provided.
|
|
extension LazySequenceType where Elements == Self {
|
|
/// Identical to `self`.
|
|
public var elements: Self { return self }
|
|
}
|
|
|
|
/// A sequence containing the same elements as a `Base` sequence, but
|
|
/// on which some operations such as `map` and `filter` are
|
|
/// implemented lazily.
|
|
///
|
|
/// - See also: `LazySequenceType`
|
|
public struct LazySequence<Base : SequenceType>
|
|
: LazySequenceType, _SequenceWrapperType {
|
|
|
|
/// Creates a sequence that has the same elements as `base`, but on
|
|
/// which some operations such as `map` and `filter` are implemented
|
|
/// lazily.
|
|
public init(_ base: Base) {
|
|
self._base = base
|
|
}
|
|
|
|
public var _base: Base
|
|
|
|
/// The `Base` (presumably non-lazy) sequence from which `self` was created.
|
|
public var elements: Base { return _base }
|
|
}
|
|
|
|
extension SequenceType {
|
|
/// A sequence containing the same elements as a `Base` sequence,
|
|
/// but on which some operations such as `map` and `filter` are
|
|
/// implemented lazily.
|
|
///
|
|
/// - See also: `LazySequenceType`, `LazySequence`
|
|
public var lazy: LazySequence<Self> {
|
|
return LazySequence(self)
|
|
}
|
|
}
|
|
|
|
/// Avoid creating multiple layers of `LazySequence` wrapper.
|
|
/// Anything conforming to `LazySequenceType` is already lazy.
|
|
extension LazySequenceType {
|
|
/// Identical to `self`.
|
|
public var lazy: Self {
|
|
return self
|
|
}
|
|
}
|
|
|