Skip to content

Commit 401f8d1

Browse files
committed
FlattenSequence/distance(from:to:) untrapping Int.min
This patch makes it so FlattenSequence/distance(from:to:) can return Int.min without trapping.
1 parent bb6de77 commit 401f8d1

File tree

1 file changed

+23
-9
lines changed

1 file changed

+23
-9
lines changed

stdlib/public/core/Flatten.swift

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -289,41 +289,55 @@ extension FlattenCollection: Collection {
289289

290290
@inlinable // lazy-performance
291291
public func distance(from start: Index, to end: Index) -> Int {
292+
let minus = start > end
293+
292294
// The following check ensures that distance(from:to:) is invoked on
293295
// the _base at least once, to trigger a _precondition in forward only
294296
// collections.
295-
if start > end {
297+
if minus {
296298
_ = _base.distance(from: _base.endIndex, to: _base.startIndex)
297299
}
298300

299-
// This handles indices belonging to the same collection.
301+
// This path handles indices belonging to the same collection.
300302
if start._outer == end._outer {
301303
guard let i = start._inner, let j = end._inner else { return 0 }
302304
return _base[start._outer].distance(from: i, to: j)
303305
}
304306

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
307309
var outer = range.lowerBound._outer
308-
var count = 0 as Int // 0...Int.max
309310

311+
var distance: Int = 0
312+
let step: Int = minus ? -1 : 1
313+
314+
// This unwrap always succeeds.
310315
if let inner = range.lowerBound._inner {
311316
let collection = _base[outer]
312-
count += collection.distance(from: inner, to: collection.endIndex)
313317
_base.formIndex(after: &outer)
318+
distance += minus
319+
? collection.distance(from: collection.endIndex, to: inner)
320+
: collection.distance(from: inner, to: collection.endIndex)
314321
}
315322

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")
316326
while outer < range.upperBound._outer {
317-
count += _base[outer].count
327+
// 0...Int.max can always be negated.
328+
let collection = _base[outer]
318329
_base.formIndex(after: &outer)
330+
distance += collection.count &* step
319331
}
320332

321333
if let inner = range.upperBound._inner {
322334
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)
324338
}
325339

326-
return start <= end ? count : -count
340+
return distance
327341
}
328342

329343
@inline(__always)

0 commit comments

Comments
 (0)