@@ -132,15 +132,56 @@ extension Product2: Collection where Base1: Collection {
132
132
133
133
@inlinable
134
134
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
141
143
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
+ }
144
185
}
145
186
146
187
@inlinable
0 commit comments