Rollup merge of #143554 - okaneco:const_slice_rotate, r=Amanieu,tgross35
slice: Mark `rotate_left`, `rotate_right` unstably const Tracking issue rust-lang/rust#143812 - Add the const unstable `const_slice_rotate` feature - Mark `<[T]>::rotate_left` and `<[T]>::rotate_right` as const unstable The internal rotate functions use [`<*mut T>::replace`](https://doc.rust-lang.org/stable/core/primitive.pointer.html#method.replace) and [`ptr::swap_nonoverlapping`](https://doc.rust-lang.org/stable/core/ptr/fn.swap_nonoverlapping.html) which were const-stabilized in 1.88. Two changes were needed in the `rotate.rs` module to make these functions const: 1. A usage of `cmp::min` was replaced with a local function implementation of [`Ord::min`](https://doc.rust-lang.org/1.88.0/src/core/cmp.rs.html#1048-1053). 2. A `for start in 1..gcd` loop was changed to a while loop with an increment variable. This needs libs-api approval and cc-ing const-eval.
This commit is contained in:
commit
061bd28cee
2 changed files with 21 additions and 9 deletions
|
|
@ -3700,7 +3700,8 @@ impl<T> [T] {
|
|||
/// assert_eq!(a, ['a', 'c', 'd', 'e', 'b', 'f']);
|
||||
/// ```
|
||||
#[stable(feature = "slice_rotate", since = "1.26.0")]
|
||||
pub fn rotate_left(&mut self, mid: usize) {
|
||||
#[rustc_const_unstable(feature = "const_slice_rotate", issue = "143812")]
|
||||
pub const fn rotate_left(&mut self, mid: usize) {
|
||||
assert!(mid <= self.len());
|
||||
let k = self.len() - mid;
|
||||
let p = self.as_mut_ptr();
|
||||
|
|
@ -3745,7 +3746,8 @@ impl<T> [T] {
|
|||
/// assert_eq!(a, ['a', 'e', 'b', 'c', 'd', 'f']);
|
||||
/// ```
|
||||
#[stable(feature = "slice_rotate", since = "1.26.0")]
|
||||
pub fn rotate_right(&mut self, k: usize) {
|
||||
#[rustc_const_unstable(feature = "const_slice_rotate", issue = "143812")]
|
||||
pub const fn rotate_right(&mut self, k: usize) {
|
||||
assert!(k <= self.len());
|
||||
let mid = self.len() - k;
|
||||
let p = self.as_mut_ptr();
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
use crate::mem::{MaybeUninit, SizedTypeProperties};
|
||||
use crate::{cmp, ptr};
|
||||
use crate::ptr;
|
||||
|
||||
type BufType = [usize; 32];
|
||||
|
||||
|
|
@ -11,7 +11,7 @@ type BufType = [usize; 32];
|
|||
///
|
||||
/// The specified range must be valid for reading and writing.
|
||||
#[inline]
|
||||
pub(super) unsafe fn ptr_rotate<T>(left: usize, mid: *mut T, right: usize) {
|
||||
pub(super) const unsafe fn ptr_rotate<T>(left: usize, mid: *mut T, right: usize) {
|
||||
if T::IS_ZST {
|
||||
return;
|
||||
}
|
||||
|
|
@ -21,7 +21,8 @@ pub(super) unsafe fn ptr_rotate<T>(left: usize, mid: *mut T, right: usize) {
|
|||
}
|
||||
// `T` is not a zero-sized type, so it's okay to divide by its size.
|
||||
if !cfg!(feature = "optimize_for_size")
|
||||
&& cmp::min(left, right) <= size_of::<BufType>() / size_of::<T>()
|
||||
// FIXME(const-hack): Use cmp::min when available in const
|
||||
&& const_min(left, right) <= size_of::<BufType>() / size_of::<T>()
|
||||
{
|
||||
// SAFETY: guaranteed by the caller
|
||||
unsafe { ptr_rotate_memmove(left, mid, right) };
|
||||
|
|
@ -45,7 +46,7 @@ pub(super) unsafe fn ptr_rotate<T>(left: usize, mid: *mut T, right: usize) {
|
|||
///
|
||||
/// The specified range must be valid for reading and writing.
|
||||
#[inline]
|
||||
unsafe fn ptr_rotate_memmove<T>(left: usize, mid: *mut T, right: usize) {
|
||||
const unsafe fn ptr_rotate_memmove<T>(left: usize, mid: *mut T, right: usize) {
|
||||
// The `[T; 0]` here is to ensure this is appropriately aligned for T
|
||||
let mut rawarray = MaybeUninit::<(BufType, [T; 0])>::uninit();
|
||||
let buf = rawarray.as_mut_ptr() as *mut T;
|
||||
|
|
@ -117,7 +118,7 @@ unsafe fn ptr_rotate_memmove<T>(left: usize, mid: *mut T, right: usize) {
|
|||
///
|
||||
/// The specified range must be valid for reading and writing.
|
||||
#[inline]
|
||||
unsafe fn ptr_rotate_gcd<T>(left: usize, mid: *mut T, right: usize) {
|
||||
const unsafe fn ptr_rotate_gcd<T>(left: usize, mid: *mut T, right: usize) {
|
||||
// Algorithm 2
|
||||
// Microbenchmarks indicate that the average performance for random shifts is better all
|
||||
// the way until about `left + right == 32`, but the worst case performance breaks even
|
||||
|
|
@ -175,7 +176,9 @@ unsafe fn ptr_rotate_gcd<T>(left: usize, mid: *mut T, right: usize) {
|
|||
}
|
||||
}
|
||||
// finish the chunk with more rounds
|
||||
for start in 1..gcd {
|
||||
// FIXME(const-hack): Use `for start in 1..gcd` when available in const
|
||||
let mut start = 1;
|
||||
while start < gcd {
|
||||
// SAFETY: `gcd` is at most equal to `right` so all values in `1..gcd` are valid for
|
||||
// reading and writing as per the function's safety contract, see [long-safety-expl]
|
||||
// above
|
||||
|
|
@ -201,6 +204,8 @@ unsafe fn ptr_rotate_gcd<T>(left: usize, mid: *mut T, right: usize) {
|
|||
i += right;
|
||||
}
|
||||
}
|
||||
|
||||
start += 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -222,7 +227,7 @@ unsafe fn ptr_rotate_gcd<T>(left: usize, mid: *mut T, right: usize) {
|
|||
///
|
||||
/// The specified range must be valid for reading and writing.
|
||||
#[inline]
|
||||
unsafe fn ptr_rotate_swap<T>(mut left: usize, mut mid: *mut T, mut right: usize) {
|
||||
const unsafe fn ptr_rotate_swap<T>(mut left: usize, mut mid: *mut T, mut right: usize) {
|
||||
loop {
|
||||
if left >= right {
|
||||
// Algorithm 3
|
||||
|
|
@ -265,3 +270,8 @@ unsafe fn ptr_rotate_swap<T>(mut left: usize, mut mid: *mut T, mut right: usize)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME(const-hack): Use cmp::min when available in const
|
||||
const fn const_min(left: usize, right: usize) -> usize {
|
||||
if right < left { right } else { left }
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue