Skip to content

Commit 625b180

Browse files
committed
Optimize SliceIndex::get impl for RangeInclusive
The checks for `self.end() == usize::MAX` and `self.end() + 1 > slice.len()` can be replaced with `self.end() >= slice.len()`, since `self.end() < slice.len()` implies both `self.end() <= slice.len()` and `self.end() < usize::MAX`.
1 parent d74b276 commit 625b180

2 files changed

Lines changed: 27 additions & 29 deletions

File tree

library/core/src/slice/index.rs

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -663,7 +663,6 @@ unsafe impl<T> const SliceIndex<[T]> for ops::RangeFull {
663663
}
664664

665665
/// The methods `index` and `index_mut` panic if:
666-
/// - the end of the range is `usize::MAX` or
667666
/// - the start of the range is greater than the end of the range or
668667
/// - the end of the range is out of bounds.
669668
#[stable(feature = "inclusive_range", since = "1.26.0")]
@@ -673,12 +672,12 @@ unsafe impl<T> const SliceIndex<[T]> for ops::RangeInclusive<usize> {
673672

674673
#[inline]
675674
fn get(self, slice: &[T]) -> Option<&[T]> {
676-
if *self.end() == usize::MAX { None } else { self.into_slice_range().get(slice) }
675+
if *self.end() >= slice.len() { None } else { self.into_slice_range().get(slice) }
677676
}
678677

679678
#[inline]
680679
fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> {
681-
if *self.end() == usize::MAX { None } else { self.into_slice_range().get_mut(slice) }
680+
if *self.end() >= slice.len() { None } else { self.into_slice_range().get_mut(slice) }
682681
}
683682

684683
#[inline]
@@ -950,8 +949,7 @@ where
950949
R: ops::RangeBounds<usize>,
951950
{
952951
let len = bounds.end;
953-
let r = into_range(len, (range.start_bound().copied(), range.end_bound().copied()))?;
954-
if r.start > r.end || r.end > len { None } else { Some(r) }
952+
into_range(len, (range.start_bound().copied(), range.end_bound().copied()))
955953
}
956954

957955
/// Converts a pair of `ops::Bound`s into `ops::Range` without performing any
@@ -982,21 +980,27 @@ pub(crate) const fn into_range(
982980
len: usize,
983981
(start, end): (ops::Bound<usize>, ops::Bound<usize>),
984982
) -> Option<ops::Range<usize>> {
985-
use ops::Bound;
986-
let start = match start {
987-
Bound::Included(start) => start,
988-
Bound::Excluded(start) => start.checked_add(1)?,
989-
Bound::Unbounded => 0,
990-
};
991-
992983
let end = match end {
993-
Bound::Included(end) => end.checked_add(1)?,
994-
Bound::Excluded(end) => end,
995-
Bound::Unbounded => len,
984+
ops::Bound::Included(end) if end >= len => return None,
985+
// Cannot overflow because `end < len` implies `end < usize::MAX`.
986+
ops::Bound::Included(end) => end + 1,
987+
988+
ops::Bound::Excluded(end) if end > len => return None,
989+
ops::Bound::Excluded(end) => end,
990+
991+
ops::Bound::Unbounded => len,
996992
};
997993

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

10011005
Some(start..end)
10021006
}

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

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -33,17 +33,14 @@ macro_rules! tests {
3333
// CHECK: ret
3434
tests!(Range<usize>, get_range, index_range);
3535

36-
// 3 comparisons required:
37-
// end != usize::MAX && end + 1 <= len && start <= end + 1
36+
// 2 comparisons required:
37+
// end < len && start <= end + 1
3838

3939
// CHECK-LABEL: @get_range_inclusive
40-
// CHECK-COUNT-3: %{{.+}} = icmp
40+
// CHECK-COUNT-2: %{{.+}} = icmp
4141
// CHECK-NOT: %{{.+}} = icmp
4242
// CHECK: ret
4343

44-
// 2 comparisons required:
45-
// end < len && start <= end + 1
46-
4744
// CHECK-LABEL: @index_range_inclusive
4845
// CHECK-COUNT-2: %{{.+}} = icmp
4946
// CHECK-NOT: %{{.+}} = icmp
@@ -64,17 +61,14 @@ tests!(RangeInclusive<usize>, get_range_inclusive, index_range_inclusive);
6461
// CHECK: ret
6562
tests!(RangeTo<usize>, get_range_to, index_range_to);
6663

67-
// 2 comparisons required:
68-
// end != usize::MAX && end + 1 <= len
64+
// 1 comparison required:
65+
// end < len
6966

7067
// CHECK-LABEL: @get_range_to_inclusive
71-
// CHECK-COUNT-2: %{{.+}} = icmp
68+
// CHECK-COUNT-1: %{{.+}} = icmp
7269
// CHECK-NOT: %{{.+}} = icmp
7370
// CHECK: ret
7471

75-
// 1 comparison required:
76-
// end < len
77-
7872
// CHECK-LABEL: @index_range_to_inclusive
7973
// CHECK-COUNT-1: %{{.+}} = icmp
8074
// CHECK-NOT: %{{.+}} = icmp

0 commit comments

Comments
 (0)