Skip to content

Commit 5293bde

Browse files
committed
[stdlib] Collection: simplify default _failEarlyRangeCheck implementations
Currently, the default implementations of the various `_failEarlyRangeCheck` forms contain several _precondition invocations, like this: ``` @inlinable public func _failEarlyRangeCheck(_ index: Index, bounds: Range<Index>) { _precondition( bounds.lowerBound <= index, "Out of bounds: index < startIndex") _precondition( index < bounds.upperBound, "Out of bounds: index >= endIndex") } ``` Each such precondition call generates a separate trap instruction, which seems like a waste — theoretically it would be helpful to know which condition was violated, but in practice, that information tends not to be surfaced anyway. Combining these will lead to a minuscule code size improvement. (The separate messages do surface these in debug builds, but only if these generic defaults actually execute, which isn’t often. These are not public entry points, so concrete collection types tend ignore these and roll their own custom index validation instead. From what I’ve seen, custom code tends to combine the upper/lower checks into a single precondition check. These underscored requirements tend to be only called by the standard `Slice`; and it seems reasonable for that to follow suit.) More interestingly, the range-in-range version of `_failEarlyRangeCheck` performs two times as many checks than are necessary: ``` @inlinable public func _failEarlyRangeCheck(_ range: Range<Index>, bounds: Range<Index>) { _precondition( bounds.lowerBound <= range.lowerBound, "Out of bounds: range begins before startIndex") _precondition( range.lowerBound <= bounds.upperBound, "Out of bounds: range ends after endIndex") _precondition( bounds.lowerBound <= range.upperBound, "Out of bounds: range ends before bounds.lowerBound") _precondition( range.upperBound <= bounds.upperBound, "Out of bounds: range begins after bounds.upperBound") } ``` It is safe to assume that `range.lowerBound <= range.upperBound`, so it’s enough to test that `bounds.lowerBound <= range.lowerBound && range.upperBound <= bounds.upperBound` — we don’t need to check each combination separately.
1 parent ac70bf7 commit 5293bde

File tree

1 file changed

+6
-20
lines changed

1 file changed

+6
-20
lines changed

stdlib/public/core/Collection.swift

Lines changed: 6 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -712,39 +712,25 @@ extension Collection {
712712
public func _failEarlyRangeCheck(_ index: Index, bounds: Range<Index>) {
713713
// FIXME: swift-3-indexing-model: tests.
714714
_precondition(
715-
bounds.lowerBound <= index,
716-
"Out of bounds: index < startIndex")
717-
_precondition(
718-
index < bounds.upperBound,
719-
"Out of bounds: index >= endIndex")
715+
bounds.lowerBound <= index && index < bounds.upperBound,
716+
"Index out of bounds")
720717
}
721718

722719
@inlinable
723720
public func _failEarlyRangeCheck(_ index: Index, bounds: ClosedRange<Index>) {
724721
// FIXME: swift-3-indexing-model: tests.
725722
_precondition(
726-
bounds.lowerBound <= index,
727-
"Out of bounds: index < startIndex")
728-
_precondition(
729-
index <= bounds.upperBound,
730-
"Out of bounds: index > endIndex")
723+
bounds.lowerBound <= index && index <= bounds.upperBound,
724+
"Index out of bounds")
731725
}
732726

733727
@inlinable
734728
public func _failEarlyRangeCheck(_ range: Range<Index>, bounds: Range<Index>) {
735729
// FIXME: swift-3-indexing-model: tests.
736730
_precondition(
737-
bounds.lowerBound <= range.lowerBound,
738-
"Out of bounds: range begins before startIndex")
739-
_precondition(
740-
range.lowerBound <= bounds.upperBound,
741-
"Out of bounds: range ends after endIndex")
742-
_precondition(
743-
bounds.lowerBound <= range.upperBound,
744-
"Out of bounds: range ends before bounds.lowerBound")
745-
_precondition(
731+
bounds.lowerBound <= range.lowerBound &&
746732
range.upperBound <= bounds.upperBound,
747-
"Out of bounds: range begins after bounds.upperBound")
733+
"Range out of bounds")
748734
}
749735

750736
/// Returns an index that is the specified distance from the given index.

0 commit comments

Comments
 (0)