@@ -289,41 +289,55 @@ extension FlattenCollection: Collection {
289
289
290
290
@inlinable // lazy-performance
291
291
public func distance( from start: Index , to end: Index ) -> Int {
292
+ let minus = start > end
293
+
292
294
// The following check ensures that distance(from:to:) is invoked on
293
295
// the _base at least once, to trigger a _precondition in forward only
294
296
// collections.
295
- if start > end {
297
+ if minus {
296
298
_ = _base. distance ( from: _base. endIndex, to: _base. startIndex)
297
299
}
298
300
299
- // This handles indices belonging to the same collection.
301
+ // This path handles indices belonging to the same collection.
300
302
if start. _outer == end. _outer {
301
303
guard let i = start. _inner, let j = end. _inner else { return 0 }
302
304
return _base [ start. _outer] . distance ( from: i, to: j)
303
305
}
304
306
305
- // The following combines the distance of three sections .
306
- let range = start <= end ? start ..< end : end ..< start
307
+ // The following path combines the distances of three regions .
308
+ let range = minus ? end ..< start : start ..< end
307
309
var outer = range. lowerBound. _outer
308
- var count = 0 as Int // 0...Int.max
309
310
311
+ var distance : Int = 0
312
+ let step : Int = minus ? - 1 : 1
313
+
314
+ // This unwrap always succeeds.
310
315
if let inner = range. lowerBound. _inner {
311
316
let collection = _base [ outer]
312
- count += collection. distance ( from: inner, to: collection. endIndex)
313
317
_base. formIndex ( after: & outer)
318
+ distance += minus
319
+ ? collection. distance ( from: collection. endIndex, to: inner)
320
+ : collection. distance ( from: inner, to: collection. endIndex)
314
321
}
315
322
323
+ // Using count is fine because the distance is nonzero here.
324
+ // In other words, the most negative nontrapping value is -Int.max.
325
+ _internalInvariant ( distance != 0 , " distance should not be zero " )
316
326
while outer < range. upperBound. _outer {
317
- count += _base [ outer] . count
327
+ // 0...Int.max can always be negated.
328
+ let collection = _base [ outer]
318
329
_base. formIndex ( after: & outer)
330
+ distance += collection. count &* step
319
331
}
320
332
321
333
if let inner = range. upperBound. _inner {
322
334
let collection = _base [ outer]
323
- count += collection. distance ( from: collection. startIndex, to: inner)
335
+ distance += minus
336
+ ? collection. distance ( from: inner, to: collection. startIndex)
337
+ : collection. distance ( from: collection. startIndex, to: inner)
324
338
}
325
339
326
- return start <= end ? count : - count
340
+ return distance
327
341
}
328
342
329
343
@inline ( __always)
0 commit comments