@@ -84,13 +84,17 @@ extension Chain: Collection where Base1: Collection, Base2: Collection {
84
84
}
85
85
}
86
86
}
87
+
88
+ /// Converts an index of `Base1` to the corresponding `Index` by mapping
89
+ /// `base1.endIndex` to `base2.startIndex`.
90
+ internal func convertIndex( _ i: Base1 . Index ) -> Index {
91
+ i == base1. endIndex ? Index ( second: base2. startIndex) : Index ( first: i)
92
+ }
87
93
88
94
public var startIndex : Index {
89
- // If `base1` is empty, then `base2.startIndex` is either a valid position
90
- // of the first element in `base2` or equal to `base2.endIndex`.
91
- return base1. isEmpty
92
- ? Index ( second: base2. startIndex)
93
- : Index ( first: base1. startIndex)
95
+ // if `base1` is empty, this will return `base2.startIndex` - if `base2` is
96
+ // also empty, this will correctly equal `base2.endIndex`
97
+ convertIndex ( base1. startIndex)
94
98
}
95
99
96
100
public var endIndex : Index {
@@ -110,10 +114,7 @@ extension Chain: Collection where Base1: Collection, Base2: Collection {
110
114
switch i. position {
111
115
case let . first( i) :
112
116
assert ( i != base1. endIndex)
113
- let next = base1. index ( after: i)
114
- return next == base1. endIndex
115
- ? Index ( second: base2. startIndex)
116
- : Index ( first: next)
117
+ return convertIndex ( base1. index ( after: i) )
117
118
case let . second( i) :
118
119
return Index ( second: base2. index ( after: i) )
119
120
}
@@ -142,27 +143,27 @@ extension Chain: Collection where Base1: Collection, Base2: Collection {
142
143
) -> Index ? {
143
144
switch ( i. position, limit. position) {
144
145
case let ( . first( i) , . first( limit) ) :
145
- let d = base1 . distance ( from : i , to : base1 . endIndex )
146
- if n < d {
146
+ if limit >= i {
147
+ // `limit` is relevant, so `base2` cannot be reached
147
148
return base1. index ( i, offsetBy: n, limitedBy: limit)
148
149
. map ( Index . init ( first: ) )
150
+ } else if let j = base1. index ( i, offsetBy: n, limitedBy: base1. endIndex) {
151
+ // the offset stays within the bounds of `base1`
152
+ return convertIndex ( j)
149
153
} else {
150
- // The limit only has an effect here if it's "above" `i`
151
- if limit >= i {
152
- return Index ( first: limit)
153
- } else {
154
- return Index (
155
- second: base2. index ( base2. startIndex, offsetBy: n - d) )
156
- }
154
+ // the offset overflows the bounds of `base1` by `n - d`
155
+ let d = base1. distance ( from: i, to: base1. endIndex)
156
+ return Index ( second: base2. index ( base2. startIndex, offsetBy: n - d) )
157
157
}
158
158
159
159
case let ( . first( i) , . second( limit) ) :
160
- let d = base1. distance ( from : i , to : base1. endIndex)
161
- if n < d {
162
- return Index ( first : base1 . index ( i , offsetBy : n ) )
160
+ if let j = base1. index ( i , offsetBy : n , limitedBy : base1. endIndex) {
161
+ // the offset stays within the bounds of `base1`
162
+ return convertIndex ( j )
163
163
} else {
164
- return base2. index (
165
- base2. startIndex, offsetBy: n - d, limitedBy: limit)
164
+ // the offset overflows the bounds of `base1` by `n - d`
165
+ let d = base1. distance ( from: i, to: base1. endIndex)
166
+ return base2. index ( base2. startIndex, offsetBy: n - d, limitedBy: limit)
166
167
. map ( Index . init ( second: ) )
167
168
}
168
169
@@ -189,22 +190,28 @@ extension Chain: Collection where Base1: Collection, Base2: Collection {
189
190
return Index ( first: base1. index ( i, offsetBy: - n) )
190
191
191
192
case let ( . second( i) , . first( limit) ) :
192
- let d = base2. distance ( from : base2 . startIndex , to : i )
193
- if n <= d {
194
- return Index ( second: base2 . index ( i , offsetBy : - n ) )
193
+ if let j = base2. index ( i , offsetBy : - n , limitedBy : base2 . startIndex ) {
194
+ // the offset stays within the bounds of `base2`
195
+ return Index ( second: j )
195
196
} else {
196
- return base1. index ( base1. endIndex, offsetBy: - n - d, limitedBy: limit)
197
+ // the offset overflows the bounds of `base2` by `n - d`
198
+ let d = base2. distance ( from: base2. startIndex, to: i)
199
+ return base1. index ( base1. endIndex, offsetBy: - ( n - d) , limitedBy: limit)
197
200
. map ( Index . init ( first: ) )
198
201
}
199
202
200
203
case let ( . second( i) , . second( limit) ) :
201
- let d = base2 . distance ( from : base2 . startIndex , to : i )
202
- if n <= d {
204
+ if limit <= i {
205
+ // `limit` is relevant, so `base1` cannot be reached
203
206
return base2. index ( i, offsetBy: - n, limitedBy: limit)
204
207
. map ( Index . init ( second: ) )
208
+ } else if let j = base2. index ( i, offsetBy: - n, limitedBy: base2. startIndex) {
209
+ // the offset stays within the bounds of `base2`
210
+ return Index ( second: j)
205
211
} else {
206
- return Index (
207
- first: base1. index ( base1. endIndex, offsetBy: - n - d) )
212
+ // the offset overflows the bounds of `base2` by `n - d`
213
+ let d = base2. distance ( from: base2. startIndex, to: i)
214
+ return Index ( first: base1. index ( base1. endIndex, offsetBy: - ( n - d) ) )
208
215
}
209
216
}
210
217
}
0 commit comments