forked from swiftlang/swift
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathLazySequence.swift
214 lines (200 loc) · 7.72 KB
/
LazySequence.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
//===--- 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}
var array: [Generator.Element] {get}
}
extension LazySequenceType {
@available(*, unavailable, message="please construct an Array from your lazy sequence: Array(...)")
public var array: [Generator.Element] { fatalError("unavailable") }
}
/// 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 }
@available(*, unavailable, renamed="Base")
public typealias S = Void
}
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
}
}
@available(*, unavailable, message="Please use the sequence's '.lazy' property")
public func lazy<Base : SequenceType>(s: Base) -> LazySequence<Base> {
fatalError("unavailable")
}