@@ -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
@@ -124,21 +113,11 @@ extension AdjacentPairsSequence: Sequence {
124113 }
125114}
126115
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.
128118///
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.
142121public struct AdjacentPairsCollection < Base: Collection > {
143122 @usableFromInline
144123 internal let base : Base
@@ -148,13 +127,25 @@ public struct AdjacentPairsCollection<Base: Collection> {
148127 @inlinable
149128 internal init ( base: Base ) {
150129 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+ }
151136
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)
158149 }
159150}
160151
@@ -181,22 +172,22 @@ extension AdjacentPairsCollection {
181172 self . second = second
182173 }
183174
175+ @inlinable
176+ public static func == ( lhs: Index , rhs: Index ) -> Bool {
177+ lhs. first == rhs. first
178+ }
179+
184180 @inlinable
185181 public static func < ( lhs: Index , rhs: Index ) -> Bool {
186- ( lhs. first, lhs . second ) < ( rhs. first, rhs . second )
182+ lhs. first < rhs. first
187183 }
188184 }
189185}
190186
191187extension AdjacentPairsCollection : Collection {
192188 @inlinable
193189 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)
200191 }
201192
202193 @inlinable
@@ -206,6 +197,7 @@ extension AdjacentPairsCollection: Collection {
206197
207198 @inlinable
208199 public func index( after i: Index ) -> Index {
200+ precondition ( i != endIndex, " Can't advance beyond endIndex " )
209201 let next = base. index ( after: i. second)
210202 return next == base. endIndex
211203 ? endIndex
@@ -214,38 +206,74 @@ extension AdjacentPairsCollection: Collection {
214206
215207 @inlinable
216208 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)
225228 } 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)
231231 }
232232 }
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+ }
233269
234270 @inlinable
235271 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)
249277 }
250278
251279 @inlinable
@@ -259,13 +287,21 @@ extension AdjacentPairsCollection: BidirectionalCollection
259287{
260288 @inlinable
261289 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)
267296 }
268297}
269298
270299extension AdjacentPairsCollection : RandomAccessCollection
271300 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