@@ -132,15 +132,56 @@ extension Product2: Collection where Base1: Collection {
132132
133133 @inlinable
134134 public func distance( from start: Index , to end: Index ) -> Int {
135- if start > end {
136- return - distance( from: end, to: start)
137- }
138- if start. i1 == end. i1 {
139- return base2 [ start. i2..< end. i2] . count
140- }
135+ guard start. i1 <= end. i1
136+ else { return - distance( from: end, to: start) }
137+ guard start. i1 != end. i1
138+ else { return base2. distance ( from: start. i2, to: end. i2) }
139+
140+ // The number of full cycles through `base2` between `start` and `end`,
141+ // excluding the cycles that `start` and `end` are on.
142+ let fullBase2Cycles = base1 [ start. i1..< end. i1] . count - 1
141143
142- return base2 [ start. i2... ] . count + base2[ ..< end. i2] . count
143- + base2. count * ( base1. distance ( from: start. i1, to: end. i1) - 1 )
144+ if start. i2 <= end. i2 {
145+ // start.i2
146+ // v
147+ // start.i1 > [l l l|c c c c c c r r r]
148+ // [l l l c c c c c c r r r] >
149+ // ... > `fullBase2Cycles` times
150+ // [l l l c c c c c c r r r] >
151+ // end.i1 > [l l l c c c c c c|r r r]
152+ // ^
153+ // end.i2
154+
155+ let left = base2 [ ..< start. i2] . count
156+ let center = base2 [ start. i2..< end. i2] . count
157+ let right = base2 [ end. i2... ] . count
158+
159+ return center + right
160+ + fullBase2Cycles * ( left + center + right)
161+ + left + center
162+ } else {
163+ // start.i2
164+ // v
165+ // start.i1 > [l l l c c c c c c|r r r]
166+ // [l l l c c c c c c r r r] >
167+ // ... > `fullBase2Cycles` times
168+ // [l l l c c c c c c r r r] >
169+ // end.i1 > [l l l|c c c c c c r r r]
170+ // ^
171+ // end.i2
172+
173+ let left = base2 [ ..< end. i2] . count
174+ let right = base2 [ start. i2... ] . count
175+
176+ // We can avoid traversing `base2[end.i2..<start.i2]` if `start` and `end`
177+ // are on consecutive cycles.
178+ guard fullBase2Cycles > 0 else { return right + left }
179+
180+ let center = base2 [ end. i2..< start. i2] . count
181+ return right
182+ + fullBase2Cycles * ( left + center + right)
183+ + left
184+ }
144185 }
145186
146187 @inlinable
0 commit comments