Skip to content

Commit e1ac2f9

Browse files
committed
Optimize std::slice::range
Same reasoning as previous commit.
1 parent a2eae7f commit e1ac2f9

File tree

2 files changed

+73
-70
lines changed

2 files changed

+73
-70
lines changed

library/core/src/slice/index.rs

Lines changed: 70 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -67,20 +67,6 @@ const fn slice_index_order_fail(index: usize, end: usize) -> ! {
6767
)
6868
}
6969

70-
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
71-
#[cfg_attr(feature = "panic_immediate_abort", inline)]
72-
#[track_caller]
73-
const fn slice_start_index_overflow_fail() -> ! {
74-
panic!("attempted to index slice from after maximum usize");
75-
}
76-
77-
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
78-
#[cfg_attr(feature = "panic_immediate_abort", inline)]
79-
#[track_caller]
80-
const fn slice_end_index_overflow_fail() -> ! {
81-
panic!("attempted to index slice up to maximum usize");
82-
}
83-
8470
// The UbChecks are great for catching bugs in the unsafe methods, but including
8571
// them in safe indexing is unnecessary and hurts inlining and debug runtime perf.
8672
// Both the safe and unsafe public methods share these helpers,
@@ -853,28 +839,27 @@ where
853839
{
854840
let len = bounds.end;
855841

856-
let start = match range.start_bound() {
857-
ops::Bound::Included(&start) => start,
858-
ops::Bound::Excluded(start) => {
859-
start.checked_add(1).unwrap_or_else(|| slice_start_index_overflow_fail())
860-
}
861-
ops::Bound::Unbounded => 0,
862-
};
863-
864842
let end = match range.end_bound() {
865-
ops::Bound::Included(end) => {
866-
end.checked_add(1).unwrap_or_else(|| slice_end_index_overflow_fail())
867-
}
843+
ops::Bound::Included(&end) if end >= len => slice_end_index_len_fail(end, len),
844+
// Cannot overflow because `end < len` implies `end < usize::MAX`.
845+
ops::Bound::Included(&end) => end + 1,
846+
847+
ops::Bound::Excluded(&end) if end > len => slice_end_index_len_fail(end, len),
868848
ops::Bound::Excluded(&end) => end,
849+
869850
ops::Bound::Unbounded => len,
870851
};
871852

872-
if start > end {
873-
slice_index_order_fail(start, end);
874-
}
875-
if end > len {
876-
slice_end_index_len_fail(end, len);
877-
}
853+
let start = match range.start_bound() {
854+
ops::Bound::Excluded(&start) if start >= end => slice_index_order_fail(start, end),
855+
// Cannot overflow because `start < end` implies `start < usize::MAX`.
856+
ops::Bound::Excluded(&start) => start + 1,
857+
858+
ops::Bound::Included(&start) if start > end => slice_index_order_fail(start, end),
859+
ops::Bound::Included(&start) => start,
860+
861+
ops::Bound::Unbounded => 0,
862+
};
878863

879864
ops::Range { start, end }
880865
}
@@ -917,19 +902,29 @@ where
917902
{
918903
let len = bounds.end;
919904

920-
let start = match range.start_bound() {
921-
ops::Bound::Included(&start) => start,
922-
ops::Bound::Excluded(start) => start.checked_add(1)?,
923-
ops::Bound::Unbounded => 0,
924-
};
925-
926905
let end = match range.end_bound() {
927-
ops::Bound::Included(end) => end.checked_add(1)?,
906+
ops::Bound::Included(&end) if end >= len => return None,
907+
// Cannot overflow because `end < len` implies `end < usize::MAX`.
908+
ops::Bound::Included(end) => end + 1,
909+
910+
ops::Bound::Excluded(&end) if end > len => return None,
928911
ops::Bound::Excluded(&end) => end,
912+
929913
ops::Bound::Unbounded => len,
930914
};
931915

932-
if start > end || end > len { None } else { Some(ops::Range { start, end }) }
916+
let start = match range.start_bound() {
917+
ops::Bound::Excluded(&start) if start >= end => return None,
918+
// Cannot overflow because `start < end` implies `start < usize::MAX`.
919+
ops::Bound::Excluded(&start) => start + 1,
920+
921+
ops::Bound::Included(&start) if start > end => return None,
922+
ops::Bound::Included(&start) => start,
923+
924+
ops::Bound::Unbounded => 0,
925+
};
926+
927+
Some(ops::Range { start, end })
933928
}
934929

935930
/// Converts a pair of `ops::Bound`s into `ops::Range` without performing any
@@ -958,21 +953,27 @@ pub(crate) fn into_range(
958953
len: usize,
959954
(start, end): (ops::Bound<usize>, ops::Bound<usize>),
960955
) -> Option<ops::Range<usize>> {
961-
use ops::Bound;
962-
let start = match start {
963-
Bound::Included(start) => start,
964-
Bound::Excluded(start) => start.checked_add(1)?,
965-
Bound::Unbounded => 0,
966-
};
967-
968956
let end = match end {
969-
Bound::Included(end) => end.checked_add(1)?,
970-
Bound::Excluded(end) => end,
971-
Bound::Unbounded => len,
957+
ops::Bound::Included(end) if end >= len => return None,
958+
// Cannot overflow because `end < len` implies `end < usize::MAX`.
959+
ops::Bound::Included(end) => end + 1,
960+
961+
ops::Bound::Excluded(end) if end > len => return None,
962+
ops::Bound::Excluded(end) => end,
963+
964+
ops::Bound::Unbounded => len,
972965
};
973966

974-
// Don't bother with checking `start < end` and `end <= len`
975-
// since these checks are handled by `Range` impls
967+
let start = match start {
968+
ops::Bound::Excluded(start) if start >= end => return None,
969+
// Cannot overflow because `start < end` implies `start < usize::MAX`.
970+
ops::Bound::Excluded(start) => start + 1,
971+
972+
ops::Bound::Included(start) if start > end => return None,
973+
ops::Bound::Included(start) => start,
974+
975+
ops::Bound::Unbounded => 0,
976+
};
976977

977978
Some(start..end)
978979
}
@@ -983,25 +984,27 @@ pub(crate) fn into_slice_range(
983984
len: usize,
984985
(start, end): (ops::Bound<usize>, ops::Bound<usize>),
985986
) -> ops::Range<usize> {
986-
use ops::Bound;
987-
let start = match start {
988-
Bound::Included(start) => start,
989-
Bound::Excluded(start) => {
990-
start.checked_add(1).unwrap_or_else(|| slice_start_index_overflow_fail())
991-
}
992-
Bound::Unbounded => 0,
993-
};
994-
995987
let end = match end {
996-
Bound::Included(end) => {
997-
end.checked_add(1).unwrap_or_else(|| slice_end_index_overflow_fail())
998-
}
999-
Bound::Excluded(end) => end,
1000-
Bound::Unbounded => len,
988+
ops::Bound::Included(end) if end >= len => slice_end_index_len_fail(end, len),
989+
// Cannot overflow because `end < len` implies `end < usize::MAX`.
990+
ops::Bound::Included(end) => end + 1,
991+
992+
ops::Bound::Excluded(end) if end > len => slice_end_index_len_fail(end, len),
993+
ops::Bound::Excluded(end) => end,
994+
995+
ops::Bound::Unbounded => len,
1001996
};
1002997

1003-
// Don't bother with checking `start < end` and `end <= len`
1004-
// since these checks are handled by `Range` impls
998+
let start = match start {
999+
ops::Bound::Excluded(start) if start >= end => slice_index_order_fail(start, end),
1000+
// Cannot overflow because `start < end` implies `start < usize::MAX`.
1001+
ops::Bound::Excluded(start) => start + 1,
1002+
1003+
ops::Bound::Included(start) if start > end => slice_index_order_fail(start, end),
1004+
ops::Bound::Included(start) => start,
1005+
1006+
ops::Bound::Unbounded => 0,
1007+
};
10051008

10061009
start..end
10071010
}

library/coretests/tests/slice.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1506,14 +1506,14 @@ mod slice_index {
15061506
data: [0; 1];
15071507

15081508
bad: data[(Bound::Unbounded, Bound::Included(usize::MAX))];
1509-
message: "maximum usize";
1509+
message: "out of range";
15101510
}
15111511

15121512
in mod boundpair_overflow_start {
15131513
data: [0; 1];
15141514

15151515
bad: data[(Bound::Excluded(usize::MAX), Bound::Unbounded)];
1516-
message: "maximum usize";
1516+
message: "but ends at 1";
15171517
}
15181518
} // panic_cases!
15191519
}
@@ -2008,7 +2008,7 @@ fn test_copy_within_panics_src_inverted() {
20082008
bytes.copy_within(2..1, 0);
20092009
}
20102010
#[test]
2011-
#[should_panic(expected = "attempted to index slice up to maximum usize")]
2011+
#[should_panic(expected = "out of range")]
20122012
fn test_copy_within_panics_src_out_of_bounds() {
20132013
let mut bytes = *b"Hello, World!";
20142014
// an inclusive range ending at usize::MAX would make src_end overflow

0 commit comments

Comments
 (0)