Skip to content

Commit ec8b641

Browse files
committed
Optimize SliceIndex::get impl for RangeInclusive
The check for `self.end() == usize::MAX` can be combined with the `self.end() + 1 > slice.len()` check into `self.end() >= slice.len()`, since `self.end() < slice.len()` implies both `self.end() <= slice.len()` and `self.end() < usize::MAX`.
1 parent f29c7b6 commit ec8b641

File tree

2 files changed

+46
-25
lines changed

2 files changed

+46
-25
lines changed

library/core/src/slice/index.rs

Lines changed: 42 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -657,8 +657,25 @@ unsafe impl<T> const SliceIndex<[T]> for ops::RangeFull {
657657
}
658658
}
659659

660+
/// Return `Ok((start, new_len))` if the `RangeInclusive` is valid for a slice of
661+
/// length `len`, or `Err((start, end))` if it is not.
662+
#[inline(always)]
663+
const fn check_inclusive(
664+
range: ops::RangeInclusive<usize>,
665+
len: usize,
666+
) -> Result<(usize, usize), (usize, usize)> {
667+
let ops::RangeInclusive { mut start, mut end, exhausted } = range;
668+
if end < len {
669+
end = end + 1;
670+
start = if exhausted { end } else { start };
671+
if let Some(new_len) = usize::checked_sub(end, start) {
672+
return Ok((start, new_len));
673+
}
674+
}
675+
Err((start, end))
676+
}
677+
660678
/// The methods `index` and `index_mut` panic if:
661-
/// - the end of the range is `usize::MAX` or
662679
/// - the start of the range is greater than the end of the range or
663680
/// - the end of the range is out of bounds.
664681
#[stable(feature = "inclusive_range", since = "1.26.0")]
@@ -668,12 +685,24 @@ unsafe impl<T> const SliceIndex<[T]> for ops::RangeInclusive<usize> {
668685

669686
#[inline]
670687
fn get(self, slice: &[T]) -> Option<&[T]> {
671-
if *self.end() == usize::MAX { None } else { self.into_slice_range().get(slice) }
688+
match check_inclusive(self, slice.len()) {
689+
Ok((start, new_len)) => {
690+
// SAFETY: We checked that the range is valid above.
691+
unsafe { Some(&*get_offset_len_noubcheck(slice, start, new_len)) }
692+
}
693+
Err(_) => None,
694+
}
672695
}
673696

674697
#[inline]
675698
fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> {
676-
if *self.end() == usize::MAX { None } else { self.into_slice_range().get_mut(slice) }
699+
match check_inclusive(self, slice.len()) {
700+
Ok((start, new_len)) => {
701+
// SAFETY: We checked that the range is valid above.
702+
unsafe { Some(&mut *get_offset_len_mut_noubcheck(slice, start, new_len)) }
703+
}
704+
Err(_) => None,
705+
}
677706
}
678707

679708
#[inline]
@@ -690,32 +719,24 @@ unsafe impl<T> const SliceIndex<[T]> for ops::RangeInclusive<usize> {
690719

691720
#[inline]
692721
fn index(self, slice: &[T]) -> &[T] {
693-
let Self { mut start, mut end, exhausted } = self;
694-
let len = slice.len();
695-
if end < len {
696-
end = end + 1;
697-
start = if exhausted { end } else { start };
698-
if let Some(new_len) = usize::checked_sub(end, start) {
699-
// SAFETY: `self` is checked to be valid and in bounds above.
700-
unsafe { return &*get_offset_len_noubcheck(slice, start, new_len) }
722+
match check_inclusive(self, slice.len()) {
723+
Ok((start, new_len)) => {
724+
// SAFETY: We checked that the range is valid above.
725+
unsafe { &*get_offset_len_noubcheck(slice, start, new_len) }
701726
}
727+
Err((start, end)) => slice_index_fail(start, end, slice.len()),
702728
}
703-
slice_index_fail(start, end, slice.len())
704729
}
705730

706731
#[inline]
707732
fn index_mut(self, slice: &mut [T]) -> &mut [T] {
708-
let Self { mut start, mut end, exhausted } = self;
709-
let len = slice.len();
710-
if end < len {
711-
end = end + 1;
712-
start = if exhausted { end } else { start };
713-
if let Some(new_len) = usize::checked_sub(end, start) {
714-
// SAFETY: `self` is checked to be valid and in bounds above.
715-
unsafe { return &mut *get_offset_len_mut_noubcheck(slice, start, new_len) }
733+
match check_inclusive(self, slice.len()) {
734+
Ok((start, new_len)) => {
735+
// SAFETY: We checked that the range is valid above.
736+
unsafe { &mut *get_offset_len_mut_noubcheck(slice, start, new_len) }
716737
}
738+
Err((start, end)) => slice_index_fail(start, end, slice.len()),
717739
}
718-
slice_index_fail(start, end, slice.len())
719740
}
720741
}
721742

tests/codegen-llvm/slice-range-indexing.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,16 +43,16 @@ tests!(RangeTo<usize>, get_range_to, index_range_to);
4343
tests!(RangeFrom<usize>, get_range_from, index_range_from);
4444

4545
// CHECK-LABEL: @get_range_inclusive
46-
// CHECK-COUNT-3: icmp
47-
// 3 comparisons required: (range.end != usize::MAX) && (range.end < slice.len()) && (range.start <= range.end + 1)
46+
// CHECK-COUNT-2: icmp
47+
// 2 comparisons required: (range.end < slice.len()) && (range.start <= range.end + 1)
4848
// CHECK-LABEL: @index_range_inclusive
4949
// CHECK-COUNT-2: icmp
5050
// 2 comparisons required: (range.end < slice.len()) && (range.start <= range.end + 1)
5151
tests!(RangeInclusive<usize>, get_range_inclusive, index_range_inclusive);
5252

5353
// CHECK-LABEL: @get_range_to_inclusive
54-
// CHECK-COUNT-2: icmp
55-
// 2 comparisons required: (range.end != usize::MAX) && (range.end < slice.len())
54+
// CHECK-COUNT-1: icmp
55+
// 1 comparison required: (range.end < slice.len())
5656
// CHECK-LABEL: @index_range_to_inclusive
5757
// CHECK-COUNT-1: icmp
5858
// 1 comparison required: (range.end < slice.len())

0 commit comments

Comments
 (0)