swap_simple
no longer needs to be a separate function
This commit is contained in:
parent
6d2cb39ac5
commit
d0ce391b14
@ -731,38 +731,6 @@ pub const fn swap<T>(x: &mut T, y: &mut T) {
|
|||||||
unsafe { intrinsics::typed_swap(x, y) }
|
unsafe { intrinsics::typed_swap(x, y) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Same as [`swap`] semantically, but always uses the simple implementation.
|
|
||||||
///
|
|
||||||
/// Used elsewhere in `mem` and `ptr` at the bottom layer of calls.
|
|
||||||
#[rustc_const_unstable(feature = "const_swap", issue = "83163")]
|
|
||||||
#[inline]
|
|
||||||
pub(crate) const fn swap_simple<T>(x: &mut T, y: &mut T) {
|
|
||||||
// We arrange for this to typically be called with small types,
|
|
||||||
// so this reads-and-writes approach is actually better than using
|
|
||||||
// copy_nonoverlapping as it easily puts things in LLVM registers
|
|
||||||
// directly and doesn't end up inlining allocas.
|
|
||||||
// And LLVM actually optimizes it to 3×memcpy if called with
|
|
||||||
// a type larger than it's willing to keep in a register.
|
|
||||||
// Having typed reads and writes in MIR here is also good as
|
|
||||||
// it lets Miri and CTFE understand them better, including things
|
|
||||||
// like enforcing type validity for them.
|
|
||||||
// Importantly, read+copy_nonoverlapping+write introduces confusing
|
|
||||||
// asymmetry to the behaviour where one value went through read+write
|
|
||||||
// whereas the other was copied over by the intrinsic (see #94371).
|
|
||||||
// Furthermore, using only read+write here benefits limited backends
|
|
||||||
// such as SPIR-V that work on an underlying *typed* view of memory,
|
|
||||||
// and thus have trouble with Rust's untyped memory operations.
|
|
||||||
|
|
||||||
// SAFETY: exclusive references are always valid to read/write,
|
|
||||||
// including being aligned, and nothing here panics so it's drop-safe.
|
|
||||||
unsafe {
|
|
||||||
let a = ptr::read(x);
|
|
||||||
let b = ptr::read(y);
|
|
||||||
ptr::write(x, b);
|
|
||||||
ptr::write(y, a);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Replaces `dest` with the default value of `T`, returning the previous `dest` value.
|
/// Replaces `dest` with the default value of `T`, returning the previous `dest` value.
|
||||||
///
|
///
|
||||||
/// * If you want to replace the values of two variables, see [`swap`].
|
/// * If you want to replace the values of two variables, see [`swap`].
|
||||||
|
@ -1062,11 +1062,26 @@ macro_rules! attempt_swap_as_chunks {
|
|||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
while i < count {
|
while i < count {
|
||||||
// SAFETY: By precondition, `i` is in-bounds because it's below `n`
|
// SAFETY: By precondition, `i` is in-bounds because it's below `n`
|
||||||
let x = unsafe { &mut *x.add(i) };
|
let x = unsafe { x.add(i) };
|
||||||
// SAFETY: By precondition, `i` is in-bounds because it's below `n`
|
// SAFETY: By precondition, `i` is in-bounds because it's below `n`
|
||||||
// and it's distinct from `x` since the ranges are non-overlapping
|
// and it's distinct from `x` since the ranges are non-overlapping
|
||||||
let y = unsafe { &mut *y.add(i) };
|
let y = unsafe { y.add(i) };
|
||||||
mem::swap_simple::<MaybeUninit<T>>(x, y);
|
|
||||||
|
// If we end up here, it's because we're using a simple type -- like
|
||||||
|
// a small power-of-two-sized thing -- or a special type with particularly
|
||||||
|
// large alignment, particularly SIMD types.
|
||||||
|
// Thus we're fine just reading-and-writing it, as either it's small
|
||||||
|
// and that works well anyway or it's special and the type's author
|
||||||
|
// presumably wanted things to be done in the larger chunk.
|
||||||
|
|
||||||
|
// SAFETY: we're only ever given pointers that are valid to read/write,
|
||||||
|
// including being aligned, and nothing here panics so it's drop-safe.
|
||||||
|
unsafe {
|
||||||
|
let a: MaybeUninit<T> = read(x);
|
||||||
|
let b: MaybeUninit<T> = read(y);
|
||||||
|
write(x, b);
|
||||||
|
write(y, a);
|
||||||
|
}
|
||||||
|
|
||||||
i += 1;
|
i += 1;
|
||||||
}
|
}
|
||||||
|
@ -5,8 +5,6 @@ error[E0080]: evaluation of constant value failed
|
|||||||
|
|
|
|
||||||
note: inside `std::ptr::read::<MaybeUninit<MaybeUninit<u8>>>`
|
note: inside `std::ptr::read::<MaybeUninit<MaybeUninit<u8>>>`
|
||||||
--> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
|
--> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
|
||||||
note: inside `mem::swap_simple::<MaybeUninit<MaybeUninit<u8>>>`
|
|
||||||
--> $SRC_DIR/core/src/mem/mod.rs:LL:COL
|
|
||||||
note: inside `std::ptr::swap_nonoverlapping_simple_untyped::<MaybeUninit<u8>>`
|
note: inside `std::ptr::swap_nonoverlapping_simple_untyped::<MaybeUninit<u8>>`
|
||||||
--> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
|
--> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
|
||||||
note: inside `swap_nonoverlapping::<MaybeUninit<u8>>`
|
note: inside `swap_nonoverlapping::<MaybeUninit<u8>>`
|
||||||
|
Loading…
Reference in New Issue
Block a user