Rollup merge of #83091 - usbalbin:const_copy, r=oli-obk
Constify `copy` related functions Constify * `*const T::copy_to[_nonoverlapping]` * `*mut T::copy_to[_nonoverlapping]` * `*mut T::copy_from[_nonoverlapping]` * `mem::transmute_copy` * `mem::swap` * `ptr::swap[_nonoverlapping]` * `mem::replace` * `ptr::replace`
This commit is contained in:
commit
d3460cd3c8
|
@ -1902,18 +1902,6 @@ pub(crate) fn is_aligned_and_not_null<T>(ptr: *const T) -> bool {
|
|||
!ptr.is_null() && ptr as usize % mem::align_of::<T>() == 0
|
||||
}
|
||||
|
||||
/// Checks whether the regions of memory starting at `src` and `dst` of size
|
||||
/// `count * size_of::<T>()` do *not* overlap.
|
||||
pub(crate) fn is_nonoverlapping<T>(src: *const T, dst: *const T, count: usize) -> bool {
|
||||
let src_usize = src as usize;
|
||||
let dst_usize = dst as usize;
|
||||
let size = mem::size_of::<T>().checked_mul(count).unwrap();
|
||||
let diff = if src_usize > dst_usize { src_usize - dst_usize } else { dst_usize - src_usize };
|
||||
// If the absolute distance between the ptrs is at least as big as the size of the buffer,
|
||||
// they do not overlap.
|
||||
diff >= size
|
||||
}
|
||||
|
||||
/// Sets `count * size_of::<T>()` bytes of memory starting at `dst` to
|
||||
/// `val`.
|
||||
///
|
||||
|
|
|
@ -98,6 +98,7 @@
|
|||
#![feature(const_slice_from_raw_parts)]
|
||||
#![feature(const_slice_ptr_len)]
|
||||
#![feature(const_size_of_val)]
|
||||
#![feature(const_swap)]
|
||||
#![feature(const_align_of_val)]
|
||||
#![feature(const_type_id)]
|
||||
#![feature(const_type_name)]
|
||||
|
|
|
@ -682,7 +682,8 @@ pub unsafe fn uninitialized<T>() -> T {
|
|||
/// ```
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn swap<T>(x: &mut T, y: &mut T) {
|
||||
#[rustc_const_unstable(feature = "const_swap", issue = "83163")]
|
||||
pub const fn swap<T>(x: &mut T, y: &mut T) {
|
||||
// SAFETY: the raw pointers have been created from safe mutable references satisfying all the
|
||||
// constraints on `ptr::swap_nonoverlapping_one`
|
||||
unsafe {
|
||||
|
@ -812,7 +813,8 @@ pub fn take<T: Default>(dest: &mut T) -> T {
|
|||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[must_use = "if you don't need the old value, you can just assign the new value directly"]
|
||||
pub fn replace<T>(dest: &mut T, src: T) -> T {
|
||||
#[rustc_const_unstable(feature = "const_replace", issue = "83164")]
|
||||
pub const fn replace<T>(dest: &mut T, src: T) -> T {
|
||||
// SAFETY: We read from `dest` but directly write `src` into it afterwards,
|
||||
// such that the old value is not duplicated. Nothing is dropped and
|
||||
// nothing here can panic.
|
||||
|
@ -931,7 +933,8 @@ pub fn drop<T>(_x: T) {}
|
|||
/// ```
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub unsafe fn transmute_copy<T, U>(src: &T) -> U {
|
||||
#[rustc_const_unstable(feature = "const_transmute_copy", issue = "83165")]
|
||||
pub const unsafe fn transmute_copy<T, U>(src: &T) -> U {
|
||||
// If U has a higher alignment requirement, src may not be suitably aligned.
|
||||
if align_of::<U>() > align_of::<T>() {
|
||||
// SAFETY: `src` is a reference which is guaranteed to be valid for reads.
|
||||
|
|
|
@ -819,9 +819,10 @@ impl<T: ?Sized> *const T {
|
|||
/// See [`ptr::copy`] for safety concerns and examples.
|
||||
///
|
||||
/// [`ptr::copy`]: crate::ptr::copy()
|
||||
#[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")]
|
||||
#[stable(feature = "pointer_methods", since = "1.26.0")]
|
||||
#[inline]
|
||||
pub unsafe fn copy_to(self, dest: *mut T, count: usize)
|
||||
pub const unsafe fn copy_to(self, dest: *mut T, count: usize)
|
||||
where
|
||||
T: Sized,
|
||||
{
|
||||
|
@ -837,9 +838,10 @@ impl<T: ?Sized> *const T {
|
|||
/// See [`ptr::copy_nonoverlapping`] for safety concerns and examples.
|
||||
///
|
||||
/// [`ptr::copy_nonoverlapping`]: crate::ptr::copy_nonoverlapping()
|
||||
#[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")]
|
||||
#[stable(feature = "pointer_methods", since = "1.26.0")]
|
||||
#[inline]
|
||||
pub unsafe fn copy_to_nonoverlapping(self, dest: *mut T, count: usize)
|
||||
pub const unsafe fn copy_to_nonoverlapping(self, dest: *mut T, count: usize)
|
||||
where
|
||||
T: Sized,
|
||||
{
|
||||
|
|
|
@ -67,7 +67,7 @@
|
|||
use crate::cmp::Ordering;
|
||||
use crate::fmt;
|
||||
use crate::hash;
|
||||
use crate::intrinsics::{self, abort, is_aligned_and_not_null, is_nonoverlapping};
|
||||
use crate::intrinsics::{self, abort, is_aligned_and_not_null};
|
||||
use crate::mem::{self, MaybeUninit};
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
@ -394,7 +394,8 @@ pub const fn slice_from_raw_parts_mut<T>(data: *mut T, len: usize) -> *mut [T] {
|
|||
/// ```
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub unsafe fn swap<T>(x: *mut T, y: *mut T) {
|
||||
#[rustc_const_unstable(feature = "const_swap", issue = "83163")]
|
||||
pub const unsafe fn swap<T>(x: *mut T, y: *mut T) {
|
||||
// Give ourselves some scratch space to work with.
|
||||
// We do not have to worry about drops: `MaybeUninit` does nothing when dropped.
|
||||
let mut tmp = MaybeUninit::<T>::uninit();
|
||||
|
@ -451,16 +452,8 @@ pub unsafe fn swap<T>(x: *mut T, y: *mut T) {
|
|||
/// ```
|
||||
#[inline]
|
||||
#[stable(feature = "swap_nonoverlapping", since = "1.27.0")]
|
||||
pub unsafe fn swap_nonoverlapping<T>(x: *mut T, y: *mut T, count: usize) {
|
||||
if cfg!(debug_assertions)
|
||||
&& !(is_aligned_and_not_null(x)
|
||||
&& is_aligned_and_not_null(y)
|
||||
&& is_nonoverlapping(x, y, count))
|
||||
{
|
||||
// Not panicking to keep codegen impact smaller.
|
||||
abort();
|
||||
}
|
||||
|
||||
#[rustc_const_unstable(feature = "const_swap", issue = "83163")]
|
||||
pub const unsafe fn swap_nonoverlapping<T>(x: *mut T, y: *mut T, count: usize) {
|
||||
let x = x as *mut u8;
|
||||
let y = y as *mut u8;
|
||||
let len = mem::size_of::<T>() * count;
|
||||
|
@ -470,7 +463,8 @@ pub unsafe fn swap_nonoverlapping<T>(x: *mut T, y: *mut T, count: usize) {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) unsafe fn swap_nonoverlapping_one<T>(x: *mut T, y: *mut T) {
|
||||
#[rustc_const_unstable(feature = "const_swap", issue = "83163")]
|
||||
pub(crate) const unsafe fn swap_nonoverlapping_one<T>(x: *mut T, y: *mut T) {
|
||||
// For types smaller than the block optimization below,
|
||||
// just swap directly to avoid pessimizing codegen.
|
||||
if mem::size_of::<T>() < 32 {
|
||||
|
@ -488,7 +482,8 @@ pub(crate) unsafe fn swap_nonoverlapping_one<T>(x: *mut T, y: *mut T) {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn swap_nonoverlapping_bytes(x: *mut u8, y: *mut u8, len: usize) {
|
||||
#[rustc_const_unstable(feature = "const_swap", issue = "83163")]
|
||||
const unsafe fn swap_nonoverlapping_bytes(x: *mut u8, y: *mut u8, len: usize) {
|
||||
// The approach here is to utilize simd to swap x & y efficiently. Testing reveals
|
||||
// that swapping either 32 bytes or 64 bytes at a time is most efficient for Intel
|
||||
// Haswell E processors. LLVM is more able to optimize if we give a struct a
|
||||
|
@ -589,7 +584,8 @@ unsafe fn swap_nonoverlapping_bytes(x: *mut u8, y: *mut u8, len: usize) {
|
|||
/// ```
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub unsafe fn replace<T>(dst: *mut T, mut src: T) -> T {
|
||||
#[rustc_const_unstable(feature = "const_replace", issue = "83164")]
|
||||
pub const unsafe fn replace<T>(dst: *mut T, mut src: T) -> T {
|
||||
// SAFETY: the caller must guarantee that `dst` is valid to be
|
||||
// cast to a mutable reference (valid for writes, aligned, initialized),
|
||||
// and cannot overlap `src` since `dst` must point to a distinct
|
||||
|
|
|
@ -926,9 +926,10 @@ impl<T: ?Sized> *mut T {
|
|||
/// See [`ptr::copy`] for safety concerns and examples.
|
||||
///
|
||||
/// [`ptr::copy`]: crate::ptr::copy()
|
||||
#[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")]
|
||||
#[stable(feature = "pointer_methods", since = "1.26.0")]
|
||||
#[inline]
|
||||
pub unsafe fn copy_to(self, dest: *mut T, count: usize)
|
||||
pub const unsafe fn copy_to(self, dest: *mut T, count: usize)
|
||||
where
|
||||
T: Sized,
|
||||
{
|
||||
|
@ -944,9 +945,10 @@ impl<T: ?Sized> *mut T {
|
|||
/// See [`ptr::copy_nonoverlapping`] for safety concerns and examples.
|
||||
///
|
||||
/// [`ptr::copy_nonoverlapping`]: crate::ptr::copy_nonoverlapping()
|
||||
#[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")]
|
||||
#[stable(feature = "pointer_methods", since = "1.26.0")]
|
||||
#[inline]
|
||||
pub unsafe fn copy_to_nonoverlapping(self, dest: *mut T, count: usize)
|
||||
pub const unsafe fn copy_to_nonoverlapping(self, dest: *mut T, count: usize)
|
||||
where
|
||||
T: Sized,
|
||||
{
|
||||
|
@ -962,9 +964,10 @@ impl<T: ?Sized> *mut T {
|
|||
/// See [`ptr::copy`] for safety concerns and examples.
|
||||
///
|
||||
/// [`ptr::copy`]: crate::ptr::copy()
|
||||
#[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")]
|
||||
#[stable(feature = "pointer_methods", since = "1.26.0")]
|
||||
#[inline]
|
||||
pub unsafe fn copy_from(self, src: *const T, count: usize)
|
||||
pub const unsafe fn copy_from(self, src: *const T, count: usize)
|
||||
where
|
||||
T: Sized,
|
||||
{
|
||||
|
@ -980,9 +983,10 @@ impl<T: ?Sized> *mut T {
|
|||
/// See [`ptr::copy_nonoverlapping`] for safety concerns and examples.
|
||||
///
|
||||
/// [`ptr::copy_nonoverlapping`]: crate::ptr::copy_nonoverlapping()
|
||||
#[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")]
|
||||
#[stable(feature = "pointer_methods", since = "1.26.0")]
|
||||
#[inline]
|
||||
pub unsafe fn copy_from_nonoverlapping(self, src: *const T, count: usize)
|
||||
pub const unsafe fn copy_from_nonoverlapping(self, src: *const T, count: usize)
|
||||
where
|
||||
T: Sized,
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue