@@ -18,35 +18,35 @@ extension Sequence {
18
18
/// The following example uses the `adjacentPairs()` method to iterate over
19
19
/// adjacent pairs of integers:
20
20
///
21
- /// for pair in (1...5).adjacentPairs() {
22
- /// print(pair)
23
- /// }
24
- /// // Prints "(1, 2)"
25
- /// // Prints "(2, 3)"
26
- /// // Prints "(3, 4)"
27
- /// // Prints "(4, 5)"
21
+ /// for pair in (1...).prefix( 5).adjacentPairs() {
22
+ /// print(pair)
23
+ /// }
24
+ /// // Prints "(1, 2)"
25
+ /// // Prints "(2, 3)"
26
+ /// // Prints "(3, 4)"
27
+ /// // Prints "(4, 5)"
28
28
@inlinable
29
29
public func adjacentPairs( ) -> AdjacentPairsSequence < Self > {
30
30
AdjacentPairsSequence ( base: self )
31
31
}
32
32
}
33
33
34
34
extension Collection {
35
- /// A collection of adjacent pairs of elements built from an underlying collection.
35
+ /// A collection of adjacent pairs of elements built from an underlying
36
+ /// collection.
36
37
///
37
- /// In an `AdjacentPairsCollection`, the elements of the *i*th pair are the *i*th
38
- /// and *(i+1)*th elements of the underlying sequence. The following example
39
- /// uses the `adjacentPairs()` method to iterate over adjacent pairs of
40
- /// integers:
41
- /// ```
42
- /// for pair in (1...5).adjacentPairs() {
43
- /// print(pair)
44
- /// }
45
- /// // Prints "(1, 2)"
46
- /// // Prints "(2, 3)"
47
- /// // Prints "(3, 4)"
48
- /// // Prints "(4, 5)"
49
- /// ```
38
+ /// In an `AdjacentPairsCollection`, the elements of the *i*th pair are the
39
+ /// *i*th and *(i+1)*th elements of the underlying sequence. The following
40
+ /// example uses the `adjacentPairs()` method to iterate over adjacent pairs
41
+ /// of integers:
42
+ ///
43
+ /// for pair in (1...5).adjacentPairs() {
44
+ /// print(pair)
45
+ /// }
46
+ /// // Prints "(1, 2)"
47
+ /// // Prints "(2, 3)"
48
+ /// // Prints "(3, 4)"
49
+ /// // Prints "(4, 5)"
50
50
@inlinable
51
51
public func adjacentPairs( ) -> AdjacentPairsCollection < Self > {
52
52
AdjacentPairsCollection ( base: self )
@@ -55,19 +55,8 @@ extension Collection {
55
55
56
56
/// A sequence of adjacent pairs of elements built from an underlying sequence.
57
57
///
58
- /// In an `AdjacentPairsSequence`, the elements of the *i*th pair are the *i*th
59
- /// and *(i+1)*th elements of the underlying sequence. The following example
60
- /// uses the `adjacentPairs()` method to iterate over adjacent pairs of
61
- /// integers:
62
- /// ```
63
- /// for pair in (1...5).adjacentPairs() {
64
- /// print(pair)
65
- /// }
66
- /// // Prints "(1, 2)"
67
- /// // Prints "(2, 3)"
68
- /// // Prints "(3, 4)"
69
- /// // Prints "(4, 5)"
70
- /// ```
58
+ /// Use the `adjacentPairs()` method on a sequence to create an
59
+ /// `AdjacentPairsSequence` instance.
71
60
public struct AdjacentPairsSequence < Base: Sequence > {
72
61
@usableFromInline
73
62
internal let base : Base
@@ -80,6 +69,7 @@ public struct AdjacentPairsSequence<Base: Sequence> {
80
69
}
81
70
82
71
extension AdjacentPairsSequence {
72
+ /// The iterator for an `AdjacentPairsSequence` or `AdjacentPairsCollection`.
83
73
public struct Iterator {
84
74
@usableFromInline
85
75
internal var base : Base . Iterator
@@ -124,21 +114,14 @@ extension AdjacentPairsSequence: Sequence {
124
114
}
125
115
}
126
116
127
- /// A collection of adjacent pairs of elements built from an underlying collection.
117
+ extension AdjacentPairsSequence : LazySequenceProtocol
118
+ where Base: LazySequenceProtocol { }
119
+
120
+ /// A collection of adjacent pairs of elements built from an underlying
121
+ /// collection.
128
122
///
129
- /// In an `AdjacentPairsCollection`, the elements of the *i*th pair are the *i*th
130
- /// and *(i+1)*th elements of the underlying sequence. The following example
131
- /// uses the `adjacentPairs()` method to iterate over adjacent pairs of
132
- /// integers:
133
- /// ```
134
- /// for pair in (1...5).adjacentPairs() {
135
- /// print(pair)
136
- /// }
137
- /// // Prints "(1, 2)"
138
- /// // Prints "(2, 3)"
139
- /// // Prints "(3, 4)"
140
- /// // Prints "(4, 5)"
141
- /// ```
123
+ /// Use the `adjacentPairs()` method on a collection to create an
124
+ /// `AdjacentPairsCollection` instance.
142
125
public struct AdjacentPairsCollection < Base: Collection > {
143
126
@usableFromInline
144
127
internal let base : Base
@@ -148,13 +131,25 @@ public struct AdjacentPairsCollection<Base: Collection> {
148
131
@inlinable
149
132
internal init ( base: Base ) {
150
133
self . base = base
134
+
135
+ // Lazily build the end index, since we can't use the instance
136
+ // property pre-initialization
137
+ var endIndex : Index {
138
+ Index ( first: base. endIndex, second: base. endIndex)
139
+ }
151
140
152
- // Precompute `startIndex` to ensure O(1) behavior,
153
- // avoiding indexing past `endIndex`
154
- let start = base. startIndex
155
- let end = base. endIndex
156
- let second = start == end ? start : base. index ( after: start)
157
- self . startIndex = Index ( first: start, second: second)
141
+ // Precompute `startIndex` to ensure O(1) behavior.
142
+ guard !base. isEmpty else {
143
+ self . startIndex = endIndex
144
+ return
145
+ }
146
+
147
+ // If there's only one element (i.e. the second index of base == endIndex)
148
+ // then this collection should be empty.
149
+ let secondIndex = base. index ( after: base. startIndex)
150
+ self . startIndex = secondIndex == base. endIndex
151
+ ? endIndex
152
+ : Index ( first: base. startIndex, second: secondIndex)
158
153
}
159
154
}
160
155
@@ -168,6 +163,7 @@ extension AdjacentPairsCollection {
168
163
}
169
164
170
165
extension AdjacentPairsCollection {
166
+ /// A position in an `AdjacentPairsCollection`.
171
167
public struct Index : Comparable {
172
168
@usableFromInline
173
169
internal var first : Base . Index
@@ -181,22 +177,22 @@ extension AdjacentPairsCollection {
181
177
self . second = second
182
178
}
183
179
180
+ @inlinable
181
+ public static func == ( lhs: Index , rhs: Index ) -> Bool {
182
+ lhs. first == rhs. first
183
+ }
184
+
184
185
@inlinable
185
186
public static func < ( lhs: Index , rhs: Index ) -> Bool {
186
- ( lhs. first, lhs . second ) < ( rhs. first, rhs . second )
187
+ lhs. first < rhs. first
187
188
}
188
189
}
189
190
}
190
191
191
192
extension AdjacentPairsCollection : Collection {
192
193
@inlinable
193
194
public var endIndex : Index {
194
- switch base. endIndex {
195
- case startIndex. first, startIndex. second:
196
- return startIndex
197
- case let end:
198
- return Index ( first: end, second: end)
199
- }
195
+ Index ( first: base. endIndex, second: base. endIndex)
200
196
}
201
197
202
198
@inlinable
@@ -206,6 +202,7 @@ extension AdjacentPairsCollection: Collection {
206
202
207
203
@inlinable
208
204
public func index( after i: Index ) -> Index {
205
+ precondition ( i != endIndex, " Can't advance beyond endIndex " )
209
206
let next = base. index ( after: i. second)
210
207
return next == base. endIndex
211
208
? endIndex
@@ -214,38 +211,74 @@ extension AdjacentPairsCollection: Collection {
214
211
215
212
@inlinable
216
213
public func index( _ i: Index , offsetBy distance: Int ) -> Index {
217
- if distance == 0 {
218
- return i
219
- } else if distance > 0 {
220
- let firstOffsetIndex = base. index ( i. first, offsetBy: distance)
221
- let secondOffsetIndex = base. index ( after: firstOffsetIndex)
222
- return secondOffsetIndex == base. endIndex
223
- ? endIndex
224
- : Index ( first: firstOffsetIndex, second: secondOffsetIndex)
214
+ guard distance != 0 else { return i }
215
+
216
+ guard let result = distance > 0
217
+ ? offsetForward ( i, by: distance, limitedBy: endIndex)
218
+ : offsetBackward ( i, by: - distance, limitedBy: startIndex)
219
+ else { fatalError ( " Index out of bounds " ) }
220
+ return result
221
+ }
222
+
223
+ @inlinable
224
+ public func index(
225
+ _ i: Index , offsetBy distance: Int , limitedBy limit: Index
226
+ ) -> Index ? {
227
+ guard distance != 0 else { return i }
228
+ guard limit != i else { return nil }
229
+
230
+ if distance > 0 {
231
+ let limit = limit > i ? limit : endIndex
232
+ return offsetForward ( i, by: distance, limitedBy: limit)
225
233
} else {
226
- return i == endIndex
227
- ? Index ( first: base. index ( i. first, offsetBy: distance - 1 ) ,
228
- second: base. index ( i. first, offsetBy: distance) )
229
- : Index ( first: base. index ( i. first, offsetBy: distance) ,
230
- second: i. first)
234
+ let limit = limit < i ? limit : startIndex
235
+ return offsetBackward ( i, by: - distance, limitedBy: limit)
231
236
}
232
237
}
238
+
239
+ @inlinable
240
+ internal func offsetForward(
241
+ _ i: Index , by distance: Int , limitedBy limit: Index
242
+ ) -> Index ? {
243
+ assert ( distance > 0 )
244
+ assert ( limit > i)
245
+
246
+ guard let newFirst = base. index ( i. second, offsetBy: distance - 1 , limitedBy: limit. first) ,
247
+ newFirst != base. endIndex
248
+ else { return nil }
249
+ let newSecond = base. index ( after: newFirst)
250
+
251
+ precondition ( newSecond <= base. endIndex, " Can't advance beyond endIndex " )
252
+ return newSecond == base. endIndex
253
+ ? endIndex
254
+ : Index ( first: newFirst, second: newSecond)
255
+ }
256
+
257
+ @inlinable
258
+ internal func offsetBackward(
259
+ _ i: Index , by distance: Int , limitedBy limit: Index
260
+ ) -> Index ? {
261
+ assert ( distance > 0 )
262
+ assert ( limit < i)
263
+
264
+ let offset = i == endIndex ? 0 : 1
265
+ guard let newSecond = base. index (
266
+ i. first,
267
+ offsetBy: - ( distance - offset) ,
268
+ limitedBy: limit. second)
269
+ else { return nil }
270
+ let newFirst = base. index ( newSecond, offsetBy: - 1 )
271
+ precondition ( newFirst >= base. startIndex, " Can't move before startIndex " )
272
+ return Index ( first: newFirst, second: newSecond)
273
+ }
233
274
234
275
@inlinable
235
276
public func distance( from start: Index , to end: Index ) -> Int {
236
- let offset : Int
237
- switch ( start. first, end. first) {
238
- case ( base. endIndex, base. endIndex) :
239
- return 0
240
- case ( base. endIndex, _) :
241
- offset = + 1
242
- case ( _, base. endIndex) :
243
- offset = - 1
244
- default :
245
- offset = 0
246
- }
247
-
248
- return base. distance ( from: start. first, to: end. first) + offset
277
+ // While there's a 2-step gap between the `first` base index values in
278
+ // `endIndex` and the penultimate index of this collection, the `second`
279
+ // base index values are consistently one step apart throughout the
280
+ // entire collection.
281
+ base. distance ( from: start. second, to: end. second)
249
282
}
250
283
251
284
@inlinable
@@ -259,13 +292,24 @@ extension AdjacentPairsCollection: BidirectionalCollection
259
292
{
260
293
@inlinable
261
294
public func index( before i: Index ) -> Index {
262
- i == endIndex
263
- ? Index ( first: base. index ( i. first, offsetBy: - 2 ) ,
264
- second: base. index ( before: i. first) )
265
- : Index ( first: base. index ( before: i. first) ,
266
- second: i. first)
295
+ precondition ( i != startIndex, " Can't offset before startIndex " )
296
+ let second = i == endIndex
297
+ ? base. index ( before: base. endIndex)
298
+ : i. first
299
+ let first = base. index ( before: second)
300
+ return Index ( first: first, second: second)
267
301
}
268
302
}
269
303
270
304
extension AdjacentPairsCollection : RandomAccessCollection
271
305
where Base: RandomAccessCollection { }
306
+
307
+ extension AdjacentPairsCollection : LazySequenceProtocol , LazyCollectionProtocol
308
+ where Base: LazyCollectionProtocol { }
309
+
310
+ extension AdjacentPairsCollection . Index : Hashable where Base. Index: Hashable {
311
+ @inlinable
312
+ public func hash( into hasher: inout Hasher ) {
313
+ hasher. combine ( first)
314
+ }
315
+ }
0 commit comments