Skip to content

Commit bb70e52

Browse files
committed
Add slice::check_range
1 parent 22ee68d commit bb70e52

File tree

1 file changed

+87
-6
lines changed

1 file changed

+87
-6
lines changed

library/core/src/slice/mod.rs

Lines changed: 87 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ use crate::intrinsics::{assume, exact_div, is_aligned_and_not_null, unchecked_su
3030
use crate::iter::*;
3131
use crate::marker::{self, Copy, Send, Sized, Sync};
3232
use crate::mem;
33-
use crate::ops::{self, FnMut, Range};
33+
use crate::ops::{self, Bound, FnMut, Range, RangeBounds};
3434
use crate::option::Option;
3535
use crate::option::Option::{None, Some};
3636
use crate::ptr::{self, NonNull};
@@ -350,6 +350,80 @@ impl<T> [T] {
350350
unsafe { &mut *index.get_unchecked_mut(self) }
351351
}
352352

353+
/// Converts a range over this slice to [`Range`].
354+
///
355+
/// The returned range is safe to pass to [`get_unchecked`] and [`get_unchecked_mut`].
356+
///
357+
/// [`get_unchecked`]: #method.get_unchecked
358+
/// [`get_unchecked_mut`]: #method.get_unchecked_mut
359+
/// [`Range`]: ../ops/struct.Range.html
360+
///
361+
/// # Panics
362+
///
363+
/// Panics if the range is out of bounds.
364+
///
365+
/// # Examples
366+
///
367+
/// ```
368+
/// #![feature(slice_check_range)]
369+
///
370+
/// let v = [10, 40, 30];
371+
/// assert_eq!(1..2, v.check_range(1..2));
372+
/// assert_eq!(0..2, v.check_range(..2));
373+
/// assert_eq!(1..3, v.check_range(1..));
374+
/// ```
375+
///
376+
/// Panics when [`Index::index`] would panic:
377+
///
378+
/// ```should_panic
379+
/// #![feature(slice_check_range)]
380+
///
381+
/// [10, 40, 30].check_range(2..1);
382+
/// ```
383+
///
384+
/// ```should_panic
385+
/// #![feature(slice_check_range)]
386+
///
387+
/// [10, 40, 30].check_range(1..4);
388+
/// ```
389+
///
390+
/// ```should_panic
391+
/// #![feature(slice_check_range)]
392+
///
393+
/// [10, 40, 30].check_range(1..=usize::MAX);
394+
/// ```
395+
///
396+
/// [`Index::index`]: ../ops/trait.Index.html#tymethod.index
397+
#[track_caller]
398+
#[unstable(feature = "slice_check_range", issue = "none")]
399+
pub fn check_range<R: RangeBounds<usize>>(&self, range: R) -> Range<usize> {
400+
let start = match range.start_bound() {
401+
Bound::Included(&start) => start,
402+
Bound::Excluded(start) => {
403+
start.checked_add(1).unwrap_or_else(|| slice_start_index_overflow_fail())
404+
}
405+
Bound::Unbounded => 0,
406+
};
407+
408+
let len = self.len();
409+
let end = match range.end_bound() {
410+
Bound::Included(end) => {
411+
end.checked_add(1).unwrap_or_else(|| slice_end_index_overflow_fail())
412+
}
413+
Bound::Excluded(&end) => end,
414+
Bound::Unbounded => len,
415+
};
416+
417+
if start > end {
418+
slice_index_order_fail(start, end);
419+
}
420+
if end > len {
421+
slice_end_index_len_fail(end, len);
422+
}
423+
424+
Range { start, end }
425+
}
426+
353427
/// Returns a raw pointer to the slice's buffer.
354428
///
355429
/// The caller must ensure that the slice outlives the pointer this
@@ -2445,13 +2519,13 @@ impl<T> [T] {
24452519
let src_start = match src.start_bound() {
24462520
ops::Bound::Included(&n) => n,
24472521
ops::Bound::Excluded(&n) => {
2448-
n.checked_add(1).unwrap_or_else(|| slice_index_overflow_fail())
2522+
n.checked_add(1).unwrap_or_else(|| slice_start_index_overflow_fail())
24492523
}
24502524
ops::Bound::Unbounded => 0,
24512525
};
24522526
let src_end = match src.end_bound() {
24532527
ops::Bound::Included(&n) => {
2454-
n.checked_add(1).unwrap_or_else(|| slice_index_overflow_fail())
2528+
n.checked_add(1).unwrap_or_else(|| slice_end_index_overflow_fail())
24552529
}
24562530
ops::Bound::Excluded(&n) => n,
24572531
ops::Bound::Unbounded => self.len(),
@@ -3034,7 +3108,14 @@ fn slice_index_order_fail(index: usize, end: usize) -> ! {
30343108
#[inline(never)]
30353109
#[cold]
30363110
#[track_caller]
3037-
fn slice_index_overflow_fail() -> ! {
3111+
fn slice_start_index_overflow_fail() -> ! {
3112+
panic!("attempted to index slice from after maximum usize");
3113+
}
3114+
3115+
#[inline(never)]
3116+
#[cold]
3117+
#[track_caller]
3118+
fn slice_end_index_overflow_fail() -> ! {
30383119
panic!("attempted to index slice up to maximum usize");
30393120
}
30403121

@@ -3370,15 +3451,15 @@ unsafe impl<T> SliceIndex<[T]> for ops::RangeInclusive<usize> {
33703451
#[inline]
33713452
fn index(self, slice: &[T]) -> &[T] {
33723453
if *self.end() == usize::MAX {
3373-
slice_index_overflow_fail();
3454+
slice_end_index_overflow_fail();
33743455
}
33753456
(*self.start()..self.end() + 1).index(slice)
33763457
}
33773458

33783459
#[inline]
33793460
fn index_mut(self, slice: &mut [T]) -> &mut [T] {
33803461
if *self.end() == usize::MAX {
3381-
slice_index_overflow_fail();
3462+
slice_end_index_overflow_fail();
33823463
}
33833464
(*self.start()..self.end() + 1).index_mut(slice)
33843465
}

0 commit comments

Comments
 (0)