@@ -18,35 +18,35 @@ extension Sequence {
1818 /// The following example uses the `adjacentPairs()` method to iterate over
1919 /// adjacent pairs of integers:
2020 ///
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)"
2828 @inlinable
2929 public func adjacentPairs( ) -> AdjacentPairsSequence < Self > {
3030 AdjacentPairsSequence ( base: self )
3131 }
3232}
3333
3434extension 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.
3637 ///
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)"
5050 @inlinable
5151 public func adjacentPairs( ) -> AdjacentPairsCollection < Self > {
5252 AdjacentPairsCollection ( base: self )
@@ -55,19 +55,8 @@ extension Collection {
5555
5656/// A sequence of adjacent pairs of elements built from an underlying sequence.
5757///
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.
7160public struct AdjacentPairsSequence < Base: Sequence > {
7261 @usableFromInline
7362 internal let base : Base
@@ -80,6 +69,7 @@ public struct AdjacentPairsSequence<Base: Sequence> {
8069}
8170
8271extension AdjacentPairsSequence {
72+ /// The iterator for an `AdjacentPairsSequence` or `AdjacentPairsCollection`.
8373 public struct Iterator {
8474 @usableFromInline
8575 internal var base : Base . Iterator
@@ -124,21 +114,14 @@ extension AdjacentPairsSequence: Sequence {
124114 }
125115}
126116
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.
128122///
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.
142125public struct AdjacentPairsCollection < Base: Collection > {
143126 @usableFromInline
144127 internal let base : Base
@@ -148,13 +131,25 @@ public struct AdjacentPairsCollection<Base: Collection> {
148131 @inlinable
149132 internal init ( base: Base ) {
150133 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+ }
151140
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)
158153 }
159154}
160155
@@ -168,6 +163,7 @@ extension AdjacentPairsCollection {
168163}
169164
170165extension AdjacentPairsCollection {
166+ /// A position in an `AdjacentPairsCollection`.
171167 public struct Index : Comparable {
172168 @usableFromInline
173169 internal var first : Base . Index
@@ -181,22 +177,22 @@ extension AdjacentPairsCollection {
181177 self . second = second
182178 }
183179
180+ @inlinable
181+ public static func == ( lhs: Index , rhs: Index ) -> Bool {
182+ lhs. first == rhs. first
183+ }
184+
184185 @inlinable
185186 public static func < ( lhs: Index , rhs: Index ) -> Bool {
186- ( lhs. first, lhs . second ) < ( rhs. first, rhs . second )
187+ lhs. first < rhs. first
187188 }
188189 }
189190}
190191
191192extension AdjacentPairsCollection : Collection {
192193 @inlinable
193194 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)
200196 }
201197
202198 @inlinable
@@ -206,6 +202,7 @@ extension AdjacentPairsCollection: Collection {
206202
207203 @inlinable
208204 public func index( after i: Index ) -> Index {
205+ precondition ( i != endIndex, " Can't advance beyond endIndex " )
209206 let next = base. index ( after: i. second)
210207 return next == base. endIndex
211208 ? endIndex
@@ -214,38 +211,74 @@ extension AdjacentPairsCollection: Collection {
214211
215212 @inlinable
216213 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)
225233 } 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)
231236 }
232237 }
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+ }
233274
234275 @inlinable
235276 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)
249282 }
250283
251284 @inlinable
@@ -259,13 +292,24 @@ extension AdjacentPairsCollection: BidirectionalCollection
259292{
260293 @inlinable
261294 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)
267301 }
268302}
269303
270304extension AdjacentPairsCollection : RandomAccessCollection
271305 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