mirror of
https://github.com/rust-lang/rust.git
synced 2025-01-30 16:43:41 +00:00
Implement indexing slices with pairs of ops::Bound<usize>
This commit is contained in:
parent
2e7eb85b1d
commit
7efba4f982
@ -81,6 +81,8 @@ mod private_slice_index {
|
||||
impl Sealed for ops::RangeInclusive<usize> {}
|
||||
#[stable(feature = "slice_get_slice", since = "1.28.0")]
|
||||
impl Sealed for ops::RangeToInclusive<usize> {}
|
||||
#[stable(feature = "slice_index_with_ops_bound_pair", since = "1.51.0")]
|
||||
impl Sealed for (ops::Bound<usize>, ops::Bound<usize>) {}
|
||||
}
|
||||
|
||||
/// A helper trait used for indexing operations.
|
||||
@ -546,3 +548,113 @@ where
|
||||
|
||||
ops::Range { start, end }
|
||||
}
|
||||
|
||||
/// Convert pair of `ops::Bound`s into `ops::Range` without performing any bounds checking and (in debug) overflow checking
|
||||
fn into_range_unchecked(
|
||||
len: usize,
|
||||
(start, end): (ops::Bound<usize>, ops::Bound<usize>),
|
||||
) -> ops::Range<usize> {
|
||||
use ops::Bound;
|
||||
let start = match start {
|
||||
Bound::Included(i) => i,
|
||||
Bound::Excluded(i) => i + 1,
|
||||
Bound::Unbounded => 0,
|
||||
};
|
||||
let end = match end {
|
||||
Bound::Included(i) => i + 1,
|
||||
Bound::Excluded(i) => i,
|
||||
Bound::Unbounded => len,
|
||||
};
|
||||
start..end
|
||||
}
|
||||
|
||||
/// Convert pair of `ops::Bound`s into `ops::Range`.
|
||||
/// Returns `None` on overflowing indices.
|
||||
fn into_range(
|
||||
len: usize,
|
||||
(start, end): (ops::Bound<usize>, ops::Bound<usize>),
|
||||
) -> Option<ops::Range<usize>> {
|
||||
use ops::Bound;
|
||||
let start = match start {
|
||||
Bound::Included(start) => start,
|
||||
Bound::Excluded(start) => start.checked_add(1)?,
|
||||
Bound::Unbounded => 0,
|
||||
};
|
||||
|
||||
let end = match end {
|
||||
Bound::Included(end) => end.checked_add(1)?,
|
||||
Bound::Excluded(end) => end,
|
||||
Bound::Unbounded => len,
|
||||
};
|
||||
|
||||
// Don't bother with checking `start < end` and `end <= len`
|
||||
// since these checks are handled by `Range` impls
|
||||
|
||||
Some(start..end)
|
||||
}
|
||||
|
||||
/// Convert pair of `ops::Bound`s into `ops::Range`.
|
||||
/// Panics on overflowing indices.
|
||||
fn into_slice_range(
|
||||
len: usize,
|
||||
(start, end): (ops::Bound<usize>, ops::Bound<usize>),
|
||||
) -> ops::Range<usize> {
|
||||
use ops::Bound;
|
||||
let start = match start {
|
||||
Bound::Included(start) => start,
|
||||
Bound::Excluded(start) => {
|
||||
start.checked_add(1).unwrap_or_else(|| slice_start_index_overflow_fail())
|
||||
}
|
||||
Bound::Unbounded => 0,
|
||||
};
|
||||
|
||||
let end = match end {
|
||||
Bound::Included(end) => {
|
||||
end.checked_add(1).unwrap_or_else(|| slice_end_index_overflow_fail())
|
||||
}
|
||||
Bound::Excluded(end) => end,
|
||||
Bound::Unbounded => len,
|
||||
};
|
||||
|
||||
// Don't bother with checking `start < end` and `end <= len`
|
||||
// since these checks are handled by `Range` impls
|
||||
|
||||
start..end
|
||||
}
|
||||
|
||||
#[stable(feature = "slice_index_with_ops_bound_pair", since = "1.51.0")]
|
||||
unsafe impl<T> SliceIndex<[T]> for (ops::Bound<usize>, ops::Bound<usize>) {
|
||||
type Output = [T];
|
||||
|
||||
#[inline]
|
||||
fn get(self, slice: &[T]) -> Option<&Self::Output> {
|
||||
into_range(slice.len(), self)?.get(slice)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn get_mut(self, slice: &mut [T]) -> Option<&mut Self::Output> {
|
||||
into_range(slice.len(), self)?.get_mut(slice)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn get_unchecked(self, slice: *const [T]) -> *const Self::Output {
|
||||
// SAFETY: the caller has to uphold the safety contract for `get_unchecked`.
|
||||
unsafe { into_range_unchecked(slice.len(), self).get_unchecked(slice) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut Self::Output {
|
||||
// SAFETY: the caller has to uphold the safety contract for `get_unchecked_mut`.
|
||||
unsafe { into_range_unchecked(slice.len(), self).get_unchecked_mut(slice) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn index(self, slice: &[T]) -> &Self::Output {
|
||||
into_slice_range(slice.len(), self).index(slice)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn index_mut(self, slice: &mut [T]) -> &mut Self::Output {
|
||||
into_slice_range(slice.len(), self).index_mut(slice)
|
||||
}
|
||||
}
|
||||
|
@ -1280,6 +1280,9 @@ mod slice_index {
|
||||
}
|
||||
)*) => {$(
|
||||
mod $case_name {
|
||||
#[allow(unused_imports)]
|
||||
use core::ops::Bound;
|
||||
|
||||
#[test]
|
||||
fn pass() {
|
||||
let mut v = $data;
|
||||
@ -1376,6 +1379,24 @@ mod slice_index {
|
||||
bad: data[7..=6];
|
||||
message: "out of range";
|
||||
}
|
||||
|
||||
in mod boundpair_len {
|
||||
data: [0, 1, 2, 3, 4, 5];
|
||||
|
||||
good: data[(Bound::Included(6), Bound::Unbounded)] == [];
|
||||
good: data[(Bound::Unbounded, Bound::Included(5))] == [0, 1, 2, 3, 4, 5];
|
||||
good: data[(Bound::Unbounded, Bound::Excluded(6))] == [0, 1, 2, 3, 4, 5];
|
||||
good: data[(Bound::Included(0), Bound::Included(5))] == [0, 1, 2, 3, 4, 5];
|
||||
good: data[(Bound::Included(0), Bound::Excluded(6))] == [0, 1, 2, 3, 4, 5];
|
||||
good: data[(Bound::Included(2), Bound::Excluded(4))] == [2, 3];
|
||||
good: data[(Bound::Excluded(1), Bound::Included(4))] == [2, 3, 4];
|
||||
good: data[(Bound::Excluded(5), Bound::Excluded(6))] == [];
|
||||
good: data[(Bound::Included(6), Bound::Excluded(6))] == [];
|
||||
good: data[(Bound::Excluded(5), Bound::Included(5))] == [];
|
||||
good: data[(Bound::Included(6), Bound::Included(5))] == [];
|
||||
bad: data[(Bound::Unbounded, Bound::Included(6))];
|
||||
message: "out of range";
|
||||
}
|
||||
}
|
||||
|
||||
panic_cases! {
|
||||
@ -1416,6 +1437,14 @@ mod slice_index {
|
||||
bad: data[4..=2];
|
||||
message: "but ends at";
|
||||
}
|
||||
|
||||
in mod boundpair_neg_width {
|
||||
data: [0, 1, 2, 3, 4, 5];
|
||||
|
||||
good: data[(Bound::Included(4), Bound::Excluded(4))] == [];
|
||||
bad: data[(Bound::Included(4), Bound::Excluded(3))];
|
||||
message: "but ends at";
|
||||
}
|
||||
}
|
||||
|
||||
panic_cases! {
|
||||
@ -1434,6 +1463,20 @@ mod slice_index {
|
||||
bad: data[..= usize::MAX];
|
||||
message: "maximum usize";
|
||||
}
|
||||
|
||||
in mod boundpair_overflow_end {
|
||||
data: [0; 1];
|
||||
|
||||
bad: data[(Bound::Unbounded, Bound::Included(usize::MAX))];
|
||||
message: "maximum usize";
|
||||
}
|
||||
|
||||
in mod boundpair_overflow_start {
|
||||
data: [0; 1];
|
||||
|
||||
bad: data[(Bound::Excluded(usize::MAX), Bound::Unbounded)];
|
||||
message: "maximum usize";
|
||||
}
|
||||
} // panic_cases!
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user