Skip to content
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

array::split_array*(): return arrays instead of slices #111829

Closed
197 changes: 147 additions & 50 deletions library/core/src/array/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,14 @@ use crate::borrow::{Borrow, BorrowMut};
use crate::cmp::Ordering;
use crate::convert::{Infallible, TryFrom};
use crate::error::Error;
use crate::fmt;
use crate::hash::{self, Hash};
use crate::iter::UncheckedIterator;
use crate::mem::{self, MaybeUninit};
use crate::ops::{
ChangeOutputType, ControlFlow, FromResidual, Index, IndexMut, NeverShortCircuit, Residual, Try,
};
use crate::slice::{Iter, IterMut};
use crate::{fmt, ptr};

mod ascii;
mod drain;
Expand Down Expand Up @@ -625,15 +625,65 @@ impl<T, const N: usize> [T; N] {
from_trusted_iterator(self.iter_mut())
}

/// Divides one array reference into two at an index.
/// Divides one array into two at an index.
///
/// The first will contain all indices from `[0, M)` (excluding
/// the index `M` itself) and the second will contain all
/// indices from `[M, N)` (excluding the index `N` itself).
///
/// # Panics
/// # Examples
///
/// ```
/// #![feature(split_array)]
///
/// let v = [1, 2, 3, 4, 5, 6];
///
/// {
/// let (left, right) = v.split_array::<0>();
/// assert_eq!(left, []);
/// assert_eq!(right, [1, 2, 3, 4, 5, 6]);
/// }
///
/// {
/// let (left, right) = v.split_array::<2>();
/// assert_eq!(left, [1, 2]);
/// assert_eq!(right, [3, 4, 5, 6]);
/// }
///
/// {
/// let (left, right) = v.split_array::<6>();
/// assert_eq!(left, [1, 2, 3, 4, 5, 6]);
/// assert_eq!(right, []);
/// }
/// ```
#[unstable(feature = "split_array", reason = "new API", issue = "90091")]
#[inline]
pub const fn split_array<const M: usize>(self) -> ([T; M], [T; N - M]) {
// SAFETY: 0 <= M <= len (N)
let (left, right) = unsafe { self.split_at_unchecked(M) };

let left = left.as_ptr() as *const [T; M];
let right = right.as_ptr() as *const [T; N - M];

// SAFETY: `left` is a valid and aligned pointer to the first `M` elements of `self`
// (guaranteed by `split_at_unchecked()`).
// `self` will be forgotten immediately after (ptr::read() cannot unwind).
let left = unsafe { ptr::read(left) };
// SAFETY: `right` is a valid and aligned pointer to the last `N-M` elements of `self`
// (guaranteed by `split_at_unchecked()`).
// `self` will be forgotten immediately after (ptr::read() cannot unwind).
let right = unsafe { ptr::read(right) };

mem::forget(self);

(left, right)
}

/// Divides one array reference into two at an index.
///
/// Panics if `M > N`.
/// The first will contain all indices from `[0, M)` (excluding
/// the index `M` itself) and the second will contain all
/// indices from `[M, N)` (excluding the index `N` itself).
///
/// # Examples
///
Expand All @@ -643,9 +693,9 @@ impl<T, const N: usize> [T; N] {
/// 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::<0>();
/// assert_eq!(left, &[]);
/// assert_eq!(right, &[1, 2, 3, 4, 5, 6]);
/// }
///
/// {
Expand All @@ -660,14 +710,16 @@ impl<T, const N: usize> [T; N] {
/// assert_eq!(right, &[]);
/// }
/// ```
#[unstable(
feature = "split_array",
reason = "return type should have array as 2nd element",
issue = "90091"
)]
#[unstable(feature = "split_array", reason = "new API", issue = "90091")]
#[inline]
pub fn split_array_ref<const M: usize>(&self) -> (&[T; M], &[T]) {
(&self[..]).split_array_ref::<M>()
pub const fn split_array_ref<const M: usize>(&self) -> (&[T; M], &[T; N - M]) {
// SAFETY: 0 <= M <= len (N)
let (left, right) = unsafe { self.split_at_unchecked(M) };

// SAFETY: `split_at_unchecked()` guarantees that:
// - `left` is a slice of `M` elements,
// - `right` is a slice of `N - M` elements.
unsafe { (from_slice_unchecked(left), from_slice_unchecked(right)) }
}

/// Divides one mutable array reference into two at an index.
Expand All @@ -676,10 +728,6 @@ impl<T, const N: usize> [T; N] {
/// the index `M` itself) and the second will contain all
/// indices from `[M, N)` (excluding the index `N` itself).
///
/// # Panics
///
/// Panics if `M > N`.
///
/// # Examples
///
/// ```
Expand All @@ -693,14 +741,16 @@ impl<T, const N: usize> [T; N] {
/// right[1] = 4;
/// assert_eq!(v, [1, 2, 3, 4, 5, 6]);
/// ```
#[unstable(
feature = "split_array",
reason = "return type should have array as 2nd element",
issue = "90091"
)]
#[unstable(feature = "split_array", reason = "new API", issue = "90091")]
#[inline]
pub fn split_array_mut<const M: usize>(&mut self) -> (&mut [T; M], &mut [T]) {
(&mut self[..]).split_array_mut::<M>()
pub const fn split_array_mut<const M: usize>(&mut self) -> (&mut [T; M], &mut [T; N - M]) {
// SAFETY: 0 <= M <= len (N)
let (left, right) = unsafe { self.split_at_mut_unchecked(M) };

// SAFETY: `split_at_mut_unchecked()` guarantees that:
// - `left` is a slice of `M` elements,
// - `right` is a slice of `N - M` elements.
unsafe { (from_mut_slice_unchecked(left), from_mut_slice_unchecked(right)) }
}

/// Divides one array reference into two at an index from the end.
Expand All @@ -709,10 +759,6 @@ impl<T, const N: usize> [T; N] {
/// the index `N - M` itself) and the second will contain all
/// indices from `[N - M, N)` (excluding the index `N` itself).
///
/// # Panics
///
/// Panics if `M > N`.
///
/// # Examples
///
/// ```
Expand All @@ -721,9 +767,9 @@ impl<T, const N: usize> [T; N] {
/// 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::<0>();
/// assert_eq!(left, &[1, 2, 3, 4, 5, 6]);
/// assert_eq!(right, &[]);
/// }
///
/// {
Expand All @@ -738,14 +784,16 @@ impl<T, const N: usize> [T; N] {
/// assert_eq!(right, &[1, 2, 3, 4, 5, 6]);
/// }
/// ```
#[unstable(
feature = "split_array",
reason = "return type should have array as 2nd element",
issue = "90091"
)]
#[unstable(feature = "split_array", reason = "new API", issue = "90091")]
#[inline]
pub fn rsplit_array_ref<const M: usize>(&self) -> (&[T], &[T; M]) {
(&self[..]).rsplit_array_ref::<M>()
pub const fn rsplit_array_ref<const M: usize>(&self) -> (&[T; N - M], &[T; M]) {
// SAFETY: 0 <= (N-M) <= len (N)
let (left, right) = unsafe { self.split_at_unchecked(N - M) };

// SAFETY: `split_at_unchecked()` guarantees that:
// - `left` is a slice of `N-M` elements,
// - `right` is a slice of `N - (N-M) == M` elements.
unsafe { (from_slice_unchecked(left), from_slice_unchecked(right)) }
}

/// Divides one mutable array reference into two at an index from the end.
Expand All @@ -754,10 +802,6 @@ impl<T, const N: usize> [T; N] {
/// the index `N - M` itself) and the second will contain all
/// indices from `[N - M, N)` (excluding the index `N` itself).
///
/// # Panics
///
/// Panics if `M > N`.
///
/// # Examples
///
/// ```
Expand All @@ -771,17 +815,70 @@ impl<T, const N: usize> [T; N] {
/// right[1] = 4;
/// assert_eq!(v, [1, 2, 3, 4, 5, 6]);
/// ```
#[unstable(
feature = "split_array",
reason = "return type should have array as 2nd element",
issue = "90091"
)]
#[unstable(feature = "split_array", reason = "new API", issue = "90091")]
#[inline]
pub fn rsplit_array_mut<const M: usize>(&mut self) -> (&mut [T], &mut [T; M]) {
(&mut self[..]).rsplit_array_mut::<M>()
pub const fn rsplit_array_mut<const M: usize>(&mut self) -> (&mut [T; N - M], &mut [T; M]) {
// SAFETY: 0 <= (N-M) <= len (N)
let (left, right) = unsafe { self.split_at_mut_unchecked(N - M) };

// SAFETY: `split_at_mut_unchecked()` guarantees that:
// - `left` is a slice of `N-M` elements,
// - `right` is a slice of `N - (N-M) == M` elements.
unsafe { (from_mut_slice_unchecked(left), from_mut_slice_unchecked(right)) }
}
}

/// Unsafely converts a slice of `N` elements to an array reference of `N` elements.
///
/// # Safety
///
/// The caller must ensure that the slice has at least `N` elements. Violating this constraint
/// causes Undefined Behaviour.
///
/// # Examples
///
/// ```
/// #![feature(array_from_slice)]
///
/// let v = [1, 0, 3, 0, 5, 6];
/// // SAFETY: `&v[2..5]` is a slice of 3 elements.
/// let r = unsafe { <&[i32; 3]>::from_slice_unchecked(&v[2..5]) };
/// assert_eq!(r, &[3, 0, 5]);
/// ```
#[inline]
#[must_use]
const unsafe fn from_slice_unchecked<T, const N: usize>(s: &[T]) -> &[T; N] {
// SAFETY: caller guarantees that `s` is a slice of at least `N` elements.
unsafe { &*(s.as_ptr() as *const [T; N]) }
}

/// Unsafely converts a mutable slice of `N` elements to a mutable array reference of `N` elements.
///
/// # Safety
///
/// The caller must ensure that the slice has at least `N` elements. Violating this constraint
/// causes Undefined Behaviour.
///
/// # Examples
///
/// ```
/// #![feature(array_from_slice)]
///
/// let mut v = [1, 0, 3, 0, 5, 6];
/// // SAFETY: `&mut v[2..5]` is a slice of 3 elements.
/// let r = unsafe { <&mut [i32; 3]>::from_mut_slice_unchecked(&mut v[2..5]) };
/// assert_eq!(r, &[3, 0, 5]);
/// r[1] = 9;
/// assert_eq!(r, &[3, 9, 5]);
/// assert_eq!(v, [1, 0, 3, 9, 5, 6]);
/// ```
#[inline]
#[must_use]
const unsafe fn from_mut_slice_unchecked<T, const N: usize>(s: &mut [T]) -> &mut [T; N] {
// SAFETY: caller guarantees that `s` is a slice of at least `N` elements.
unsafe { &mut *(s.as_ptr() as *mut [T; N]) }
}

/// Populate an array from the first `N` elements of `iter`
///
/// # Panics
Expand Down
11 changes: 6 additions & 5 deletions library/core/src/intrinsics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2538,14 +2538,15 @@ pub(crate) fn is_aligned_and_not_null<T>(ptr: *const T) -> bool {
!ptr.is_null() && ptr.is_aligned()
}

const fn max_len<T>() -> usize {
let size = crate::mem::size_of::<T>();
if size == 0 { usize::MAX } else { isize::MAX as usize / size }
}

/// Checks whether an allocation of `len` instances of `T` exceeds
/// the maximum allowed allocation size.
pub(crate) fn is_valid_allocation_size<T>(len: usize) -> bool {
let max_len = const {
let size = crate::mem::size_of::<T>();
if size == 0 { usize::MAX } else { isize::MAX as usize / size }
};
len <= max_len
len <= max_len::<T>()
}

/// Checks whether the regions of memory starting at `src` and `dst` of size
Expand Down
1 change: 1 addition & 0 deletions library/core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@
#![feature(const_waker)]
#![feature(core_panic)]
#![feature(duration_consts_float)]
#![feature(generic_const_exprs)]
#![feature(internal_impls_macro)]
#![feature(ip)]
#![feature(is_ascii_octdigit)]
Expand Down
Loading