@@ -84,13 +84,17 @@ extension Chain: Collection where Base1: Collection, Base2: Collection {
8484 }
8585 }
8686 }
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+ }
8793
8894 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)
9498 }
9599
96100 public var endIndex : Index {
@@ -110,10 +114,7 @@ extension Chain: Collection where Base1: Collection, Base2: Collection {
110114 switch i. position {
111115 case let . first( i) :
112116 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) )
117118 case let . second( i) :
118119 return Index ( second: base2. index ( after: i) )
119120 }
@@ -142,27 +143,27 @@ extension Chain: Collection where Base1: Collection, Base2: Collection {
142143 ) -> Index ? {
143144 switch ( i. position, limit. position) {
144145 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
147148 return base1. index ( i, offsetBy: n, limitedBy: limit)
148149 . 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)
149153 } 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) )
157157 }
158158
159159 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 )
163163 } 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)
166167 . map ( Index . init ( second: ) )
167168 }
168169
@@ -189,22 +190,28 @@ extension Chain: Collection where Base1: Collection, Base2: Collection {
189190 return Index ( first: base1. index ( i, offsetBy: - n) )
190191
191192 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 )
195196 } 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)
197200 . map ( Index . init ( first: ) )
198201 }
199202
200203 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
203206 return base2. index ( i, offsetBy: - n, limitedBy: limit)
204207 . 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)
205211 } 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) ) )
208215 }
209216 }
210217 }
0 commit comments