@@ -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
@@ -124,21 +113,11 @@ extension AdjacentPairsSequence: Sequence {
124
113
}
125
114
}
126
115
127
- /// A collection of adjacent pairs of elements built from an underlying collection.
116
+ /// A collection of adjacent pairs of elements built from an underlying
117
+ /// collection.
128
118
///
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
- /// ```
119
+ /// Use the `adjacentPairs()` method on a collection to create an
120
+ /// `AdjacentPairsCollection` instance.
142
121
public struct AdjacentPairsCollection < Base: Collection > {
143
122
@usableFromInline
144
123
internal let base : Base
@@ -148,13 +127,25 @@ public struct AdjacentPairsCollection<Base: Collection> {
148
127
@inlinable
149
128
internal init ( base: Base ) {
150
129
self . base = base
130
+
131
+ // Lazily build the end index, since we can't use the instance
132
+ // property pre-initialization
133
+ var endIndex : Index {
134
+ Index ( first: base. endIndex, second: base. endIndex)
135
+ }
151
136
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)
137
+ // Precompute `startIndex` to ensure O(1) behavior.
138
+ guard !base. isEmpty else {
139
+ self . startIndex = endIndex
140
+ return
141
+ }
142
+
143
+ // If there's only one element (i.e. the second index of base == endIndex)
144
+ // then this collection should be empty.
145
+ let secondIndex = base. index ( after: base. startIndex)
146
+ self . startIndex = secondIndex == base. endIndex
147
+ ? endIndex
148
+ : Index ( first: base. startIndex, second: secondIndex)
158
149
}
159
150
}
160
151
@@ -181,22 +172,22 @@ extension AdjacentPairsCollection {
181
172
self . second = second
182
173
}
183
174
175
+ @inlinable
176
+ public static func == ( lhs: Index , rhs: Index ) -> Bool {
177
+ lhs. first == rhs. first
178
+ }
179
+
184
180
@inlinable
185
181
public static func < ( lhs: Index , rhs: Index ) -> Bool {
186
- ( lhs. first, lhs . second ) < ( rhs. first, rhs . second )
182
+ lhs. first < rhs. first
187
183
}
188
184
}
189
185
}
190
186
191
187
extension AdjacentPairsCollection : Collection {
192
188
@inlinable
193
189
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
- }
190
+ Index ( first: base. endIndex, second: base. endIndex)
200
191
}
201
192
202
193
@inlinable
@@ -206,6 +197,7 @@ extension AdjacentPairsCollection: Collection {
206
197
207
198
@inlinable
208
199
public func index( after i: Index ) -> Index {
200
+ precondition ( i != endIndex, " Can't advance beyond endIndex " )
209
201
let next = base. index ( after: i. second)
210
202
return next == base. endIndex
211
203
? endIndex
@@ -214,38 +206,74 @@ extension AdjacentPairsCollection: Collection {
214
206
215
207
@inlinable
216
208
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)
209
+ guard distance != 0 else { return i }
210
+
211
+ guard let result = distance > 0
212
+ ? offsetForward ( i, by: distance, limitedBy: endIndex)
213
+ : offsetBackward ( i, by: - distance, limitedBy: startIndex)
214
+ else { fatalError ( " Index out of bounds " ) }
215
+ return result
216
+ }
217
+
218
+ @inlinable
219
+ public func index(
220
+ _ i: Index , offsetBy distance: Int , limitedBy limit: Index
221
+ ) -> Index ? {
222
+ guard distance != 0 else { return i }
223
+ guard limit != i else { return nil }
224
+
225
+ if distance > 0 {
226
+ let limit = limit > i ? limit : endIndex
227
+ return offsetForward ( i, by: distance, limitedBy: limit)
225
228
} 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)
229
+ let limit = limit < i ? limit : startIndex
230
+ return offsetBackward ( i, by: - distance, limitedBy: limit)
231
231
}
232
232
}
233
+
234
+ @inlinable
235
+ internal func offsetForward(
236
+ _ i: Index , by distance: Int , limitedBy limit: Index
237
+ ) -> Index ? {
238
+ assert ( distance > 0 )
239
+ assert ( limit > i)
240
+
241
+ guard let newFirst = base. index ( i. second, offsetBy: distance - 1 , limitedBy: limit. first) ,
242
+ newFirst != base. endIndex
243
+ else { return nil }
244
+ let newSecond = base. index ( after: newFirst)
245
+
246
+ precondition ( newSecond <= base. endIndex, " Can't advance beyond endIndex " )
247
+ return newSecond == base. endIndex
248
+ ? endIndex
249
+ : Index ( first: newFirst, second: newSecond)
250
+ }
251
+
252
+ @inlinable
253
+ internal func offsetBackward(
254
+ _ i: Index , by distance: Int , limitedBy limit: Index
255
+ ) -> Index ? {
256
+ assert ( distance > 0 )
257
+ assert ( limit < i)
258
+
259
+ let offset = i == endIndex ? 0 : 1
260
+ guard let newSecond = base. index (
261
+ i. first,
262
+ offsetBy: - ( distance - offset) ,
263
+ limitedBy: limit. second)
264
+ else { return nil }
265
+ let newFirst = base. index ( newSecond, offsetBy: - 1 )
266
+ precondition ( newSecond >= base. startIndex, " Can't move before startIndex " )
267
+ return Index ( first: newFirst, second: newSecond)
268
+ }
233
269
234
270
@inlinable
235
271
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
272
+ // While there's a 2-step gap between the `first` base index values in
273
+ // `endIndex` and the penultimate index of this collection, the `second`
274
+ // base index values are consistently one step apart throughout the
275
+ // entire collection.
276
+ base. distance ( from: start. second, to: end. second)
249
277
}
250
278
251
279
@inlinable
@@ -259,13 +287,21 @@ extension AdjacentPairsCollection: BidirectionalCollection
259
287
{
260
288
@inlinable
261
289
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)
290
+ precondition ( i != startIndex, " Can't offset before startIndex " )
291
+ let second = i == endIndex
292
+ ? base. index ( before: base. endIndex)
293
+ : i. first
294
+ let first = base. index ( before: second)
295
+ return Index ( first: first, second: second)
267
296
}
268
297
}
269
298
270
299
extension AdjacentPairsCollection : RandomAccessCollection
271
300
where Base: RandomAccessCollection { }
301
+
302
+ extension AdjacentPairsCollection . Index : Hashable where Base. Index: Hashable {
303
+ @inlinable
304
+ public func hash( into hasher: inout Hasher ) {
305
+ hasher. combine ( first)
306
+ }
307
+ }
0 commit comments