Rollup merge of #118578 - mina86:c, r=dtolnay
core: introduce split_at{,_mut}_checked Introduce split_at_checked and split_at_mut_checked methods to slices types (including str) which are non-panicking versions of split_at and split_at_mut respectively. This is analogous to get method being non-panicking version of indexing. - https://github.com/rust-lang/libs-team/issues/308 - https://github.com/rust-lang/rust/issues/119128
This commit is contained in:
commit
99b4f80f73
@ -185,6 +185,7 @@
|
||||
#![feature(set_ptr_value)]
|
||||
#![feature(slice_ptr_get)]
|
||||
#![feature(slice_split_at_unchecked)]
|
||||
#![feature(split_at_checked)]
|
||||
#![feature(str_internals)]
|
||||
#![feature(str_split_inclusive_remainder)]
|
||||
#![feature(str_split_remainder)]
|
||||
|
@ -1842,7 +1842,8 @@ pub fn group_by_mut<F>(&mut self, pred: F) -> GroupByMut<'_, T, F>
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if `mid > len`.
|
||||
/// Panics if `mid > len`. For a non-panicking alternative see
|
||||
/// [`split_at_checked`](slice::split_at_checked).
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
@ -1869,14 +1870,15 @@ pub fn group_by_mut<F>(&mut self, pred: F) -> GroupByMut<'_, T, F>
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[rustc_const_stable(feature = "const_slice_split_at_not_mut", since = "1.71.0")]
|
||||
#[rustc_allow_const_fn_unstable(split_at_checked)]
|
||||
#[inline]
|
||||
#[track_caller]
|
||||
#[must_use]
|
||||
pub const fn split_at(&self, mid: usize) -> (&[T], &[T]) {
|
||||
assert!(mid <= self.len());
|
||||
// SAFETY: `[ptr; mid]` and `[mid; len]` are inside `self`, which
|
||||
// fulfills the requirements of `split_at_unchecked`.
|
||||
unsafe { self.split_at_unchecked(mid) }
|
||||
match self.split_at_checked(mid) {
|
||||
Some(pair) => pair,
|
||||
None => panic!("mid > len"),
|
||||
}
|
||||
}
|
||||
|
||||
/// Divides one mutable slice into two at an index.
|
||||
@ -1887,7 +1889,8 @@ pub const fn split_at(&self, mid: usize) -> (&[T], &[T]) {
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if `mid > len`.
|
||||
/// Panics if `mid > len`. For a non-panicking alternative see
|
||||
/// [`split_at_mut_checked`](slice::split_at_mut_checked).
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
@ -1906,10 +1909,10 @@ pub const fn split_at(&self, mid: usize) -> (&[T], &[T]) {
|
||||
#[must_use]
|
||||
#[rustc_const_unstable(feature = "const_slice_split_at_mut", issue = "101804")]
|
||||
pub const fn split_at_mut(&mut self, mid: usize) -> (&mut [T], &mut [T]) {
|
||||
assert!(mid <= self.len());
|
||||
// SAFETY: `[ptr; mid]` and `[mid; len]` are inside `self`, which
|
||||
// fulfills the requirements of `from_raw_parts_mut`.
|
||||
unsafe { self.split_at_mut_unchecked(mid) }
|
||||
match self.split_at_mut_checked(mid) {
|
||||
Some(pair) => pair,
|
||||
None => panic!("mid > len"),
|
||||
}
|
||||
}
|
||||
|
||||
/// Divides one slice into two at an index, without doing bounds checking.
|
||||
@ -2031,6 +2034,98 @@ pub const fn split_at_mut(&mut self, mid: usize) -> (&mut [T], &mut [T]) {
|
||||
unsafe { (from_raw_parts_mut(ptr, mid), from_raw_parts_mut(ptr.add(mid), len - mid)) }
|
||||
}
|
||||
|
||||
/// Divides one slice into two at an index, returning `None` if the slice is
|
||||
/// too short.
|
||||
///
|
||||
/// If `mid ≤ len` returns a pair of slices where the first will contain all
|
||||
/// indices from `[0, mid)` (excluding the index `mid` itself) and the
|
||||
/// second will contain all indices from `[mid, len)` (excluding the index
|
||||
/// `len` itself).
|
||||
///
|
||||
/// Otherwise, if `mid > len`, returns `None`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(split_at_checked)]
|
||||
///
|
||||
/// let v = [1, -2, 3, -4, 5, -6];
|
||||
///
|
||||
/// {
|
||||
/// let (left, right) = v.split_at_checked(0).unwrap();
|
||||
/// assert_eq!(left, []);
|
||||
/// assert_eq!(right, [1, -2, 3, -4, 5, -6]);
|
||||
/// }
|
||||
///
|
||||
/// {
|
||||
/// let (left, right) = v.split_at_checked(2).unwrap();
|
||||
/// assert_eq!(left, [1, -2]);
|
||||
/// assert_eq!(right, [3, -4, 5, -6]);
|
||||
/// }
|
||||
///
|
||||
/// {
|
||||
/// let (left, right) = v.split_at_checked(6).unwrap();
|
||||
/// assert_eq!(left, [1, -2, 3, -4, 5, -6]);
|
||||
/// assert_eq!(right, []);
|
||||
/// }
|
||||
///
|
||||
/// assert_eq!(None, v.split_at_checked(7));
|
||||
/// ```
|
||||
#[unstable(feature = "split_at_checked", reason = "new API", issue = "119128")]
|
||||
#[rustc_const_unstable(feature = "split_at_checked", issue = "119128")]
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub const fn split_at_checked(&self, mid: usize) -> Option<(&[T], &[T])> {
|
||||
if mid <= self.len() {
|
||||
// SAFETY: `[ptr; mid]` and `[mid; len]` are inside `self`, which
|
||||
// fulfills the requirements of `split_at_unchecked`.
|
||||
Some(unsafe { self.split_at_unchecked(mid) })
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Divides one mutable slice into two at an index, returning `None` if the
|
||||
/// slice is too short.
|
||||
///
|
||||
/// If `mid ≤ len` returns a pair of slices where the first will contain all
|
||||
/// indices from `[0, mid)` (excluding the index `mid` itself) and the
|
||||
/// second will contain all indices from `[mid, len)` (excluding the index
|
||||
/// `len` itself).
|
||||
///
|
||||
/// Otherwise, if `mid > len`, returns `None`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(split_at_checked)]
|
||||
///
|
||||
/// let mut v = [1, 0, 3, 0, 5, 6];
|
||||
///
|
||||
/// if let Some((left, right)) = v.split_at_mut_checked(2) {
|
||||
/// assert_eq!(left, [1, 0]);
|
||||
/// assert_eq!(right, [3, 0, 5, 6]);
|
||||
/// left[1] = 2;
|
||||
/// right[1] = 4;
|
||||
/// }
|
||||
/// assert_eq!(v, [1, 2, 3, 4, 5, 6]);
|
||||
///
|
||||
/// assert_eq!(None, v.split_at_mut_checked(7));
|
||||
/// ```
|
||||
#[unstable(feature = "split_at_checked", reason = "new API", issue = "119128")]
|
||||
#[rustc_const_unstable(feature = "split_at_checked", issue = "119128")]
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub const fn split_at_mut_checked(&mut self, mid: usize) -> Option<(&mut [T], &mut [T])> {
|
||||
if mid <= self.len() {
|
||||
// SAFETY: `[ptr; mid]` and `[mid; len]` are inside `self`, which
|
||||
// fulfills the requirements of `split_at_unchecked`.
|
||||
Some(unsafe { self.split_at_mut_unchecked(mid) })
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns an iterator over subslices separated by elements that match
|
||||
/// `pred`. The matched element is not contained in the subslices.
|
||||
///
|
||||
|
@ -641,8 +641,9 @@ pub unsafe fn slice_mut_unchecked(&mut self, begin: usize, end: usize) -> &mut s
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if `mid` is not on a UTF-8 code point boundary, or if it is
|
||||
/// past the end of the last code point of the string slice.
|
||||
/// Panics if `mid` is not on a UTF-8 code point boundary, or if it is past
|
||||
/// the end of the last code point of the string slice. For a non-panicking
|
||||
/// alternative see [`split_at_checked`](str::split_at_checked).
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
@ -658,12 +659,9 @@ pub unsafe fn slice_mut_unchecked(&mut self, begin: usize, end: usize) -> &mut s
|
||||
#[must_use]
|
||||
#[stable(feature = "str_split_at", since = "1.4.0")]
|
||||
pub fn split_at(&self, mid: usize) -> (&str, &str) {
|
||||
// is_char_boundary checks that the index is in [0, .len()]
|
||||
if self.is_char_boundary(mid) {
|
||||
// SAFETY: just checked that `mid` is on a char boundary.
|
||||
unsafe { (self.get_unchecked(0..mid), self.get_unchecked(mid..self.len())) }
|
||||
} else {
|
||||
slice_error_fail(self, 0, mid)
|
||||
match self.split_at_checked(mid) {
|
||||
None => slice_error_fail(self, 0, mid),
|
||||
Some(pair) => pair,
|
||||
}
|
||||
}
|
||||
|
||||
@ -681,8 +679,9 @@ pub fn split_at(&self, mid: usize) -> (&str, &str) {
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if `mid` is not on a UTF-8 code point boundary, or if it is
|
||||
/// past the end of the last code point of the string slice.
|
||||
/// Panics if `mid` is not on a UTF-8 code point boundary, or if it is past
|
||||
/// the end of the last code point of the string slice. For a non-panicking
|
||||
/// alternative see [`split_at_mut_checked`](str::split_at_mut_checked).
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
@ -702,20 +701,114 @@ pub fn split_at(&self, mid: usize) -> (&str, &str) {
|
||||
pub fn split_at_mut(&mut self, mid: usize) -> (&mut str, &mut str) {
|
||||
// is_char_boundary checks that the index is in [0, .len()]
|
||||
if self.is_char_boundary(mid) {
|
||||
let len = self.len();
|
||||
let ptr = self.as_mut_ptr();
|
||||
// SAFETY: just checked that `mid` is on a char boundary.
|
||||
unsafe {
|
||||
(
|
||||
from_utf8_unchecked_mut(slice::from_raw_parts_mut(ptr, mid)),
|
||||
from_utf8_unchecked_mut(slice::from_raw_parts_mut(ptr.add(mid), len - mid)),
|
||||
)
|
||||
}
|
||||
unsafe { self.split_at_mut_unchecked(mid) }
|
||||
} else {
|
||||
slice_error_fail(self, 0, mid)
|
||||
}
|
||||
}
|
||||
|
||||
/// Divide one string slice into two at an index.
|
||||
///
|
||||
/// The argument, `mid`, should be a valid byte offset from the start of the
|
||||
/// string. It must also be on the boundary of a UTF-8 code point. The
|
||||
/// method returns `None` if that’s not the case.
|
||||
///
|
||||
/// The two slices returned go from the start of the string slice to `mid`,
|
||||
/// and from `mid` to the end of the string slice.
|
||||
///
|
||||
/// To get mutable string slices instead, see the [`split_at_mut_checked`]
|
||||
/// method.
|
||||
///
|
||||
/// [`split_at_mut_checked`]: str::split_at_mut_checked
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(split_at_checked)]
|
||||
///
|
||||
/// let s = "Per Martin-Löf";
|
||||
///
|
||||
/// let (first, last) = s.split_at_checked(3).unwrap();
|
||||
/// assert_eq!("Per", first);
|
||||
/// assert_eq!(" Martin-Löf", last);
|
||||
///
|
||||
/// assert_eq!(None, s.split_at_checked(13)); // Inside “ö”
|
||||
/// assert_eq!(None, s.split_at_checked(16)); // Beyond the string length
|
||||
/// ```
|
||||
#[inline]
|
||||
#[must_use]
|
||||
#[unstable(feature = "split_at_checked", reason = "new API", issue = "119128")]
|
||||
pub fn split_at_checked(&self, mid: usize) -> Option<(&str, &str)> {
|
||||
// is_char_boundary checks that the index is in [0, .len()]
|
||||
if self.is_char_boundary(mid) {
|
||||
// SAFETY: just checked that `mid` is on a char boundary.
|
||||
Some(unsafe { (self.get_unchecked(0..mid), self.get_unchecked(mid..self.len())) })
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Divide one mutable string slice into two at an index.
|
||||
///
|
||||
/// The argument, `mid`, should be a valid byte offset from the start of the
|
||||
/// string. It must also be on the boundary of a UTF-8 code point. The
|
||||
/// method returns `None` if that’s not the case.
|
||||
///
|
||||
/// The two slices returned go from the start of the string slice to `mid`,
|
||||
/// and from `mid` to the end of the string slice.
|
||||
///
|
||||
/// To get immutable string slices instead, see the [`split_at_checked`] method.
|
||||
///
|
||||
/// [`split_at_checked`]: str::split_at_checked
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(split_at_checked)]
|
||||
///
|
||||
/// let mut s = "Per Martin-Löf".to_string();
|
||||
/// if let Some((first, last)) = s.split_at_mut_checked(3) {
|
||||
/// first.make_ascii_uppercase();
|
||||
/// assert_eq!("PER", first);
|
||||
/// assert_eq!(" Martin-Löf", last);
|
||||
/// }
|
||||
/// assert_eq!("PER Martin-Löf", s);
|
||||
///
|
||||
/// assert_eq!(None, s.split_at_mut_checked(13)); // Inside “ö”
|
||||
/// assert_eq!(None, s.split_at_mut_checked(16)); // Beyond the string length
|
||||
/// ```
|
||||
#[inline]
|
||||
#[must_use]
|
||||
#[unstable(feature = "split_at_checked", reason = "new API", issue = "119128")]
|
||||
pub fn split_at_mut_checked(&mut self, mid: usize) -> Option<(&mut str, &mut str)> {
|
||||
// is_char_boundary checks that the index is in [0, .len()]
|
||||
if self.is_char_boundary(mid) {
|
||||
// SAFETY: just checked that `mid` is on a char boundary.
|
||||
Some(unsafe { self.split_at_mut_unchecked(mid) })
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Divide one string slice into two at an index.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The caller must ensure that `mid` is a valid byte offset from the start
|
||||
/// of the string and falls on the boundary of a UTF-8 code point.
|
||||
unsafe fn split_at_mut_unchecked(&mut self, mid: usize) -> (&mut str, &mut str) {
|
||||
let len = self.len();
|
||||
let ptr = self.as_mut_ptr();
|
||||
// SAFETY: caller guarantees `mid` is on a char boundary.
|
||||
unsafe {
|
||||
(
|
||||
from_utf8_unchecked_mut(slice::from_raw_parts_mut(ptr, mid)),
|
||||
from_utf8_unchecked_mut(slice::from_raw_parts_mut(ptr.add(mid), len - mid)),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns an iterator over the [`char`]s of a string slice.
|
||||
///
|
||||
/// As a string slice consists of valid UTF-8, we can iterate through a
|
||||
|
Loading…
Reference in New Issue
Block a user