Add new_uninit and assume_init on Box, Rc, and Arc

This commit is contained in:
Simon Sapin 2019-07-06 17:19:58 +02:00
parent 1613fdae37
commit 7b02b9f8ec
4 changed files with 231 additions and 0 deletions

View File

@ -93,6 +93,7 @@ use core::ops::{
use core::ptr::{self, NonNull, Unique};
use core::task::{Context, Poll};
use crate::alloc;
use crate::vec::Vec;
use crate::raw_vec::RawVec;
use crate::str::from_boxed_utf8_unchecked;
@ -121,6 +122,32 @@ impl<T> Box<T> {
box x
}
/// Construct a new box with uninitialized contents.
///
/// # Examples
///
/// ```
/// #![feature(new_uninit)]
///
/// let mut five = Box::<u32>::new_uninit();
///
/// let five = unsafe {
/// // Deferred initialization:
/// five.as_mut_ptr().write(5);
///
/// Box::assume_init(five)
/// };
///
/// assert_eq!(*five, 5)
/// ```
#[unstable(feature = "new_uninit", issue = "0")]
pub fn new_uninit() -> Box<mem::MaybeUninit<T>> {
let layout = alloc::Layout::new::<mem::MaybeUninit<T>>();
let ptr = unsafe { alloc::alloc(layout) };
let unique = Unique::new(ptr).unwrap_or_else(|| alloc::handle_alloc_error(layout));
Box(unique.cast())
}
/// Constructs a new `Pin<Box<T>>`. If `T` does not implement `Unpin`, then
/// `x` will be pinned in memory and unable to be moved.
#[stable(feature = "pin", since = "1.33.0")]
@ -130,6 +157,40 @@ impl<T> Box<T> {
}
}
impl<T> Box<mem::MaybeUninit<T>> {
/// Convert to `Box<T>`.
///
/// # Safety
///
/// As with [`MaybeUninit::assume_init`],
/// it is up to the caller to guarantee that the value
/// really is in an initialized state.
/// Calling this when the content is not yet fully initialized
/// causes immediate undefined behavior.
///
/// # Examples
///
/// ```
/// #![feature(new_uninit)]
///
/// let mut five = Box::<u32>::new_uninit();
///
/// let five: Box<u32> = unsafe {
/// // Deferred initialization:
/// five.as_mut_ptr().write(5);
///
/// Box::assume_init(five)
/// };
///
/// assert_eq!(*five, 5)
/// ```
#[unstable(feature = "new_uninit", issue = "0")]
#[inline]
pub unsafe fn assume_init(this: Self) -> Box<T> {
Box(Box::into_unique(this).cast())
}
}
impl<T: ?Sized> Box<T> {
/// Constructs a box from a raw pointer.
///

View File

@ -327,6 +327,43 @@ impl<T> Rc<T> {
}))
}
/// Construct a new Rc with uninitialized contents.
///
/// # Examples
///
/// ```
/// #![feature(new_uninit)]
/// #![feature(get_mut_unchecked)]
///
/// use std::rc::Rc;
///
/// let mut five = Rc::<u32>::new_uninit();
///
/// let five = unsafe {
/// // Deferred initialization:
/// Rc::get_mut_unchecked(&mut five).as_mut_ptr().write(5);
///
/// Rc::assume_init(five)
/// };
///
/// assert_eq!(*five, 5)
/// ```
#[unstable(feature = "new_uninit", issue = "0")]
pub fn new_uninit() -> Rc<mem::MaybeUninit<T>> {
let layout = Layout::new::<RcBox<mem::MaybeUninit<T>>>();
unsafe {
let mut ptr = Global.alloc(layout)
.unwrap_or_else(|_| handle_alloc_error(layout))
.cast::<RcBox<mem::MaybeUninit<T>>>();
ptr::write(&mut ptr.as_mut().strong, Cell::new(1));
ptr::write(&mut ptr.as_mut().weak, Cell::new(1));
Rc {
ptr,
phantom: PhantomData,
}
}
}
/// Constructs a new `Pin<Rc<T>>`. If `T` does not implement `Unpin`, then
/// `value` will be pinned in memory and unable to be moved.
#[stable(feature = "pin", since = "1.33.0")]
@ -377,6 +414,48 @@ impl<T> Rc<T> {
}
}
impl<T> Rc<mem::MaybeUninit<T>> {
/// Convert to `Rc<T>`.
///
/// # Safety
///
/// As with [`MaybeUninit::assume_init`],
/// it is up to the caller to guarantee that the value
/// really is in an initialized state.
/// Calling this when the content is not yet fully initialized
/// causes immediate undefined behavior.
///
/// # Examples
///
/// ```
/// #![feature(new_uninit)]
/// #![feature(get_mut_unchecked)]
///
/// use std::rc::Rc;
///
/// let mut five = Rc::<u32>::new_uninit();
///
/// let five = unsafe {
/// // Deferred initialization:
/// Rc::get_mut_unchecked(&mut five).as_mut_ptr().write(5);
///
/// Rc::assume_init(five)
/// };
///
/// assert_eq!(*five, 5)
/// ```
#[unstable(feature = "new_uninit", issue = "0")]
#[inline]
pub unsafe fn assume_init(this: Self) -> Rc<T> {
let ptr = this.ptr.cast();
mem::forget(this);
Rc {
ptr,
phantom: PhantomData,
}
}
}
impl<T: ?Sized> Rc<T> {
/// Consumes the `Rc`, returning the wrapped pointer.
///
@ -582,6 +661,8 @@ impl<T: ?Sized> Rc<T> {
/// # Examples
///
/// ```
/// #![feature(get_mut_unchecked)]
///
/// use std::rc::Rc;
///
/// let mut x = Rc::new(String::new());

View File

@ -311,6 +311,43 @@ impl<T> Arc<T> {
Self::from_inner(Box::into_raw_non_null(x))
}
/// Construct a Arc box with uninitialized contents.
///
/// # Examples
///
/// ```
/// #![feature(new_uninit)]
/// #![feature(get_mut_unchecked)]
///
/// use std::sync::Arc;
///
/// let mut five = Arc::<u32>::new_uninit();
///
/// let five = unsafe {
/// // Deferred initialization:
/// Arc::get_mut_unchecked(&mut five).as_mut_ptr().write(5);
///
/// Arc::assume_init(five)
/// };
///
/// assert_eq!(*five, 5)
/// ```
#[unstable(feature = "new_uninit", issue = "0")]
pub fn new_uninit() -> Arc<mem::MaybeUninit<T>> {
let layout = Layout::new::<ArcInner<mem::MaybeUninit<T>>>();
unsafe {
let mut ptr = Global.alloc(layout)
.unwrap_or_else(|_| handle_alloc_error(layout))
.cast::<ArcInner<mem::MaybeUninit<T>>>();
ptr::write(&mut ptr.as_mut().strong, atomic::AtomicUsize::new(1));
ptr::write(&mut ptr.as_mut().weak, atomic::AtomicUsize::new(1));
Arc {
ptr,
phantom: PhantomData,
}
}
}
/// Constructs a new `Pin<Arc<T>>`. If `T` does not implement `Unpin`, then
/// `data` will be pinned in memory and unable to be moved.
#[stable(feature = "pin", since = "1.33.0")]
@ -361,6 +398,48 @@ impl<T> Arc<T> {
}
}
impl<T> Arc<mem::MaybeUninit<T>> {
/// Convert to `Arc<T>`.
///
/// # Safety
///
/// As with [`MaybeUninit::assume_init`],
/// it is up to the caller to guarantee that the value
/// really is in an initialized state.
/// Calling this when the content is not yet fully initialized
/// causes immediate undefined behavior.
///
/// # Examples
///
/// ```
/// #![feature(new_uninit)]
/// #![feature(get_mut_unchecked)]
///
/// use std::sync::Arc;
///
/// let mut five = Arc::<u32>::new_uninit();
///
/// let five = unsafe {
/// // Deferred initialization:
/// Arc::get_mut_unchecked(&mut five).as_mut_ptr().write(5);
///
/// Arc::assume_init(five)
/// };
///
/// assert_eq!(*five, 5)
/// ```
#[unstable(feature = "new_uninit", issue = "0")]
#[inline]
pub unsafe fn assume_init(this: Self) -> Arc<T> {
let ptr = this.ptr.cast();
mem::forget(this);
Arc {
ptr,
phantom: PhantomData,
}
}
}
impl<T: ?Sized> Arc<T> {
/// Consumes the `Arc`, returning the wrapped pointer.
///
@ -967,6 +1046,8 @@ impl<T: ?Sized> Arc<T> {
/// # Examples
///
/// ```
/// #![feature(get_mut_unchecked)]
///
/// use std::sync::Arc;
///
/// let mut x = Arc::new(String::new());

View File

@ -122,6 +122,14 @@ impl<T: ?Sized> Unique<T> {
pub unsafe fn as_mut(&mut self) -> &mut T {
&mut *self.as_ptr()
}
/// Cast to a pointer of another type
#[inline]
pub const fn cast<U>(self) -> Unique<U> {
unsafe {
Unique::new_unchecked(self.as_ptr() as *mut U)
}
}
}
#[unstable(feature = "ptr_internals", issue = "0")]