Skip to content

Commit 41e21aa

Browse files
committed
Implement write() method for Box<MaybeUninit<T>>
This adds method similar to `MaybeUninit::write` main difference being it returns owned `Box`. This can be used to elide copy from stack safely, however it's not currently tested that the optimization actually occurs. Analogous methods are not provided for `Rc` and `Arc` as those need to handle the possibility of sharing. Some version of them may be added in the future. This was discussed in #63291 which this change extends.
1 parent 18bb8c6 commit 41e21aa

File tree

2 files changed

+38
-4
lines changed

2 files changed

+38
-4
lines changed

compiler/rustc_data_structures/src/functor.rs

+2-4
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,9 @@ impl<T> IdFunctor for Box<T> {
3131
let value = raw.read();
3232
// SAFETY: Converts `Box<T>` to `Box<MaybeUninit<T>>` which is the
3333
// inverse of `Box::assume_init()` and should be safe.
34-
let mut raw: Box<mem::MaybeUninit<T>> = Box::from_raw(raw.cast());
34+
let raw: Box<mem::MaybeUninit<T>> = Box::from_raw(raw.cast());
3535
// SAFETY: Write the mapped value back into the `Box`.
36-
raw.write(f(value)?);
37-
// SAFETY: We just initialized `raw`.
38-
raw.assume_init()
36+
Box::write(raw, f(value)?)
3937
})
4038
}
4139
}

library/alloc/src/boxed.rs

+36
Original file line numberDiff line numberDiff line change
@@ -763,6 +763,42 @@ impl<T, A: Allocator> Box<mem::MaybeUninit<T>, A> {
763763
let (raw, alloc) = Box::into_raw_with_allocator(self);
764764
unsafe { Box::from_raw_in(raw as *mut T, alloc) }
765765
}
766+
767+
/// Writes the value and converts to `Box<T, A>`.
768+
///
769+
/// This method converts the box similarly to [`Box::assume_init`] but
770+
/// writes `value` into it before conversion thus guaranteeing safety.
771+
/// In some scenarios use of this method may improve performance because
772+
/// the compiler may be able to optimize copying from stack.
773+
///
774+
/// # Examples
775+
///
776+
/// ```
777+
/// #![feature(new_uninit)]
778+
///
779+
/// let big_box = Box::<[usize; 1024]>::new_uninit();
780+
///
781+
/// let mut array = [0; 1024];
782+
/// for (i, place) in array.iter_mut().enumerate() {
783+
/// *place = i;
784+
/// }
785+
///
786+
/// // The optimizer may be able to elide this copy, so previous code writes
787+
/// // to heap directly.
788+
/// let big_box = Box::write(big_box, array);
789+
///
790+
/// for (i, x) in big_box.iter().enumerate() {
791+
/// assert_eq!(*x, i);
792+
/// }
793+
/// ```
794+
#[unstable(feature = "new_uninit", issue = "63291")]
795+
#[inline]
796+
pub fn write(mut boxed: Self, value: T) -> Box<T, A> {
797+
unsafe {
798+
(*boxed).write(value);
799+
boxed.assume_init()
800+
}
801+
}
766802
}
767803

768804
impl<T, A: Allocator> Box<[mem::MaybeUninit<T>], A> {

0 commit comments

Comments
 (0)