Skip to content

Commit d0259aa

Browse files
authored
Rollup merge of rust-lang#143554 - okaneco:const_slice_rotate, r=Amanieu,tgross35
slice: Mark `rotate_left`, `rotate_right` unstably const Tracking issue rust-lang#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.
2 parents bfc046a + 3751e13 commit d0259aa

File tree

2 files changed

+21
-9
lines changed

2 files changed

+21
-9
lines changed

library/core/src/slice/mod.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3700,7 +3700,8 @@ impl<T> [T] {
37003700
/// assert_eq!(a, ['a', 'c', 'd', 'e', 'b', 'f']);
37013701
/// ```
37023702
#[stable(feature = "slice_rotate", since = "1.26.0")]
3703-
pub fn rotate_left(&mut self, mid: usize) {
3703+
#[rustc_const_unstable(feature = "const_slice_rotate", issue = "143812")]
3704+
pub const fn rotate_left(&mut self, mid: usize) {
37043705
assert!(mid <= self.len());
37053706
let k = self.len() - mid;
37063707
let p = self.as_mut_ptr();
@@ -3745,7 +3746,8 @@ impl<T> [T] {
37453746
/// assert_eq!(a, ['a', 'e', 'b', 'c', 'd', 'f']);
37463747
/// ```
37473748
#[stable(feature = "slice_rotate", since = "1.26.0")]
3748-
pub fn rotate_right(&mut self, k: usize) {
3749+
#[rustc_const_unstable(feature = "const_slice_rotate", issue = "143812")]
3750+
pub const fn rotate_right(&mut self, k: usize) {
37493751
assert!(k <= self.len());
37503752
let mid = self.len() - k;
37513753
let p = self.as_mut_ptr();

library/core/src/slice/rotate.rs

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use crate::mem::{MaybeUninit, SizedTypeProperties};
2-
use crate::{cmp, ptr};
2+
use crate::ptr;
33

44
type BufType = [usize; 32];
55

@@ -11,7 +11,7 @@ type BufType = [usize; 32];
1111
///
1212
/// The specified range must be valid for reading and writing.
1313
#[inline]
14-
pub(super) unsafe fn ptr_rotate<T>(left: usize, mid: *mut T, right: usize) {
14+
pub(super) const unsafe fn ptr_rotate<T>(left: usize, mid: *mut T, right: usize) {
1515
if T::IS_ZST {
1616
return;
1717
}
@@ -21,7 +21,8 @@ pub(super) unsafe fn ptr_rotate<T>(left: usize, mid: *mut T, right: usize) {
2121
}
2222
// `T` is not a zero-sized type, so it's okay to divide by its size.
2323
if !cfg!(feature = "optimize_for_size")
24-
&& cmp::min(left, right) <= size_of::<BufType>() / size_of::<T>()
24+
// FIXME(const-hack): Use cmp::min when available in const
25+
&& const_min(left, right) <= size_of::<BufType>() / size_of::<T>()
2526
{
2627
// SAFETY: guaranteed by the caller
2728
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) {
4546
///
4647
/// The specified range must be valid for reading and writing.
4748
#[inline]
48-
unsafe fn ptr_rotate_memmove<T>(left: usize, mid: *mut T, right: usize) {
49+
const unsafe fn ptr_rotate_memmove<T>(left: usize, mid: *mut T, right: usize) {
4950
// The `[T; 0]` here is to ensure this is appropriately aligned for T
5051
let mut rawarray = MaybeUninit::<(BufType, [T; 0])>::uninit();
5152
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) {
117118
///
118119
/// The specified range must be valid for reading and writing.
119120
#[inline]
120-
unsafe fn ptr_rotate_gcd<T>(left: usize, mid: *mut T, right: usize) {
121+
const unsafe fn ptr_rotate_gcd<T>(left: usize, mid: *mut T, right: usize) {
121122
// Algorithm 2
122123
// Microbenchmarks indicate that the average performance for random shifts is better all
123124
// 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) {
175176
}
176177
}
177178
// finish the chunk with more rounds
178-
for start in 1..gcd {
179+
// FIXME(const-hack): Use `for start in 1..gcd` when available in const
180+
let mut start = 1;
181+
while start < gcd {
179182
// SAFETY: `gcd` is at most equal to `right` so all values in `1..gcd` are valid for
180183
// reading and writing as per the function's safety contract, see [long-safety-expl]
181184
// above
@@ -201,6 +204,8 @@ unsafe fn ptr_rotate_gcd<T>(left: usize, mid: *mut T, right: usize) {
201204
i += right;
202205
}
203206
}
207+
208+
start += 1;
204209
}
205210
}
206211

@@ -222,7 +227,7 @@ unsafe fn ptr_rotate_gcd<T>(left: usize, mid: *mut T, right: usize) {
222227
///
223228
/// The specified range must be valid for reading and writing.
224229
#[inline]
225-
unsafe fn ptr_rotate_swap<T>(mut left: usize, mut mid: *mut T, mut right: usize) {
230+
const unsafe fn ptr_rotate_swap<T>(mut left: usize, mut mid: *mut T, mut right: usize) {
226231
loop {
227232
if left >= right {
228233
// Algorithm 3
@@ -265,3 +270,8 @@ unsafe fn ptr_rotate_swap<T>(mut left: usize, mut mid: *mut T, mut right: usize)
265270
}
266271
}
267272
}
273+
274+
// FIXME(const-hack): Use cmp::min when available in const
275+
const fn const_min(left: usize, right: usize) -> usize {
276+
if right < left { right } else { left }
277+
}

0 commit comments

Comments
 (0)