Skip to content

core: introduce split_at{,_mut}_checked #118578

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jan 22, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions library/core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,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)]
Expand Down
273 changes: 263 additions & 10 deletions library/core/src/slice/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1842,7 +1842,8 @@ impl<T> [T] {
///
/// # Panics
///
/// Panics if `mid > len`.
/// Panics if `mid > len`. For a non-panicking alternative see
/// [`split_at_checked`](slice::split_at_checked).
///
/// # Examples
///
Expand All @@ -1869,14 +1870,15 @@ impl<T> [T] {
/// ```
#[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.
Expand All @@ -1887,7 +1889,8 @@ impl<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
///
Expand All @@ -1906,10 +1909,10 @@ impl<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.
Expand Down Expand Up @@ -2031,6 +2034,256 @@ impl<T> [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 slice is too
/// short.
///
/// 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).
///
/// Returns `None` if `mid > len`.
///
/// # Examples
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I seem to recall a PR that removed a lot of # Examples headers whenever there was only one example, but it doesn't really matter (I know this is consistent)

///
/// ```
/// #![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]
#[track_caller]
#[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
/// slice is too short.
///
/// 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).
///
/// Returns `None` if `mid > len`.
///
/// # 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]
#[track_caller]
#[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
}
}

/// Divides one slice into an array and a remainder slice at an index.
///
/// The array will contain all indices from `[0, N)` (excluding
/// the index `N` itself) and the slice will contain all
/// indices from `[N, len)` (excluding the index `len` itself).
///
/// # Panics
///
/// Panics if `N > len`.
///
/// # Examples
///
/// ```
/// #![feature(split_array)]
///
/// let v = &[1, 2, 3, 4, 5, 6][..];
///
/// {
/// let (left, right) = v.split_array_ref::<0>();
/// assert_eq!(left, &[]);
/// assert_eq!(right, [1, 2, 3, 4, 5, 6]);
/// }
///
/// {
/// let (left, right) = v.split_array_ref::<2>();
/// assert_eq!(left, &[1, 2]);
/// assert_eq!(right, [3, 4, 5, 6]);
/// }
///
/// {
/// let (left, right) = v.split_array_ref::<6>();
/// assert_eq!(left, &[1, 2, 3, 4, 5, 6]);
/// assert_eq!(right, []);
/// }
/// ```
#[unstable(feature = "split_array", reason = "new API", issue = "90091")]
#[inline]
#[track_caller]
#[must_use]
pub fn split_array_ref<const N: usize>(&self) -> (&[T; N], &[T]) {
let (a, b) = self.split_at(N);
// SAFETY: a points to [T; N]? Yes it's [T] of length N (checked by split_at)
unsafe { (&*(a.as_ptr() as *const [T; N]), b) }
}

/// Divides one mutable slice into an array and a remainder slice at an index.
///
/// The array will contain all indices from `[0, N)` (excluding
/// the index `N` itself) and the slice will contain all
/// indices from `[N, len)` (excluding the index `len` itself).
///
/// # Panics
///
/// Panics if `N > len`.
///
/// # Examples
///
/// ```
/// #![feature(split_array)]
///
/// let mut v = &mut [1, 0, 3, 0, 5, 6][..];
/// let (left, right) = v.split_array_mut::<2>();
/// assert_eq!(left, &mut [1, 0]);
/// assert_eq!(right, [3, 0, 5, 6]);
/// left[1] = 2;
/// right[1] = 4;
/// assert_eq!(v, [1, 2, 3, 4, 5, 6]);
/// ```
#[unstable(feature = "split_array", reason = "new API", issue = "90091")]
#[inline]
#[track_caller]
#[must_use]
pub fn split_array_mut<const N: usize>(&mut self) -> (&mut [T; N], &mut [T]) {
let (a, b) = self.split_at_mut(N);
// SAFETY: a points to [T; N]? Yes it's [T] of length N (checked by split_at_mut)
unsafe { (&mut *(a.as_mut_ptr() as *mut [T; N]), b) }
}

/// Divides one slice into an array and a remainder slice at an index from
/// the end.
///
/// The slice will contain all indices from `[0, len - N)` (excluding
/// the index `len - N` itself) and the array will contain all
/// indices from `[len - N, len)` (excluding the index `len` itself).
///
/// # Panics
///
/// Panics if `N > len`.
///
/// # Examples
///
/// ```
/// #![feature(split_array)]
///
/// let v = &[1, 2, 3, 4, 5, 6][..];
///
/// {
/// let (left, right) = v.rsplit_array_ref::<0>();
/// assert_eq!(left, [1, 2, 3, 4, 5, 6]);
/// assert_eq!(right, &[]);
/// }
///
/// {
/// let (left, right) = v.rsplit_array_ref::<2>();
/// assert_eq!(left, [1, 2, 3, 4]);
/// assert_eq!(right, &[5, 6]);
/// }
///
/// {
/// let (left, right) = v.rsplit_array_ref::<6>();
/// assert_eq!(left, []);
/// assert_eq!(right, &[1, 2, 3, 4, 5, 6]);
/// }
/// ```
#[unstable(feature = "split_array", reason = "new API", issue = "90091")]
#[inline]
#[must_use]
pub fn rsplit_array_ref<const N: usize>(&self) -> (&[T], &[T; N]) {
assert!(N <= self.len());
let (a, b) = self.split_at(self.len() - N);
// SAFETY: b points to [T; N]? Yes it's [T] of length N (checked by split_at)
unsafe { (a, &*(b.as_ptr() as *const [T; N])) }
}

/// Divides one mutable slice into an array and a remainder slice at an
/// index from the end.
///
/// The slice will contain all indices from `[0, len - N)` (excluding
/// the index `N` itself) and the array will contain all
/// indices from `[len - N, len)` (excluding the index `len` itself).
///
/// # Panics
///
/// Panics if `N > len`.
///
/// # Examples
///
/// ```
/// #![feature(split_array)]
///
/// let mut v = &mut [1, 0, 3, 0, 5, 6][..];
/// let (left, right) = v.rsplit_array_mut::<4>();
/// assert_eq!(left, [1, 0]);
/// assert_eq!(right, &mut [3, 0, 5, 6]);
/// left[1] = 2;
/// right[1] = 4;
/// assert_eq!(v, [1, 2, 3, 4, 5, 6]);
/// ```
#[unstable(feature = "split_array", reason = "new API", issue = "90091")]
#[inline]
#[must_use]
pub fn rsplit_array_mut<const N: usize>(&mut self) -> (&mut [T], &mut [T; N]) {
assert!(N <= self.len());
let (a, b) = self.split_at_mut(self.len() - N);
// SAFETY: b points to [T; N]? Yes it's [T] of length N (checked by split_at_mut)
unsafe { (a, &mut *(b.as_mut_ptr() as *mut [T; N])) }
}

/// Returns an iterator over subslices separated by elements that match
/// `pred`. The matched element is not contained in the subslices.
///
Expand Down
Loading