Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add APIs for uninitialized Box, Rc, and Arc. (Plus get_mut_unchecked) #62451

Merged
merged 14 commits into from
Aug 18, 2019
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
135 changes: 135 additions & 0 deletions src/liballoc/boxed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,10 @@ use core::ops::{
CoerceUnsized, DispatchFromDyn, Deref, DerefMut, Receiver, Generator, GeneratorState
};
use core::ptr::{self, NonNull, Unique};
use core::slice;
use core::task::{Context, Poll};

use crate::alloc::{self, Global, Alloc};
use crate::vec::Vec;
use crate::raw_vec::RawVec;
use crate::str::from_boxed_utf8_unchecked;
Expand Down Expand Up @@ -121,6 +123,34 @@ impl<T> Box<T> {
box x
}

/// Construct a new box with uninitialized contents.
SimonSapin marked this conversation as resolved.
Show resolved Hide resolved
///
/// # Examples
///
/// ```
/// #![feature(new_uninit)]
///
/// let mut five = Box::<u32>::new_uninit();
///
/// let five = unsafe {
/// // Deferred initialization:
/// five.as_mut_ptr().write(5);
///
/// five.assume_init()
/// };
///
/// assert_eq!(*five, 5)
/// ```
#[unstable(feature = "new_uninit", issue = "63291")]
pub fn new_uninit() -> Box<mem::MaybeUninit<T>> {
let layout = alloc::Layout::new::<mem::MaybeUninit<T>>();
let ptr = unsafe {
Global.alloc(layout)
.unwrap_or_else(|_| alloc::handle_alloc_error(layout))
};
Box(ptr.cast().into())
}

/// 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")]
Expand All @@ -130,6 +160,111 @@ impl<T> Box<T> {
}
}

impl<T> Box<[T]> {
/// Construct a new boxed slice with uninitialized contents.
SimonSapin marked this conversation as resolved.
Show resolved Hide resolved
///
/// # Examples
///
/// ```
/// #![feature(new_uninit)]
///
/// let mut values = Box::<[u32]>::new_uninit_slice(3);
///
/// let values = unsafe {
/// // Deferred initialization:
/// values[0].as_mut_ptr().write(1);
/// values[1].as_mut_ptr().write(2);
/// values[2].as_mut_ptr().write(3);
///
/// values.assume_init()
/// };
///
/// assert_eq!(*values, [1, 2, 3])
/// ```
#[unstable(feature = "new_uninit", issue = "63291")]
pub fn new_uninit_slice(len: usize) -> Box<[mem::MaybeUninit<T>]> {
let layout = alloc::Layout::array::<mem::MaybeUninit<T>>(len).unwrap();
let ptr = unsafe { alloc::alloc(layout) };
RalfJung marked this conversation as resolved.
Show resolved Hide resolved
let unique = Unique::new(ptr).unwrap_or_else(|| alloc::handle_alloc_error(layout));
let slice = unsafe { slice::from_raw_parts_mut(unique.cast().as_ptr(), len) };
Box(Unique::from(slice))
}
}

impl<T> Box<mem::MaybeUninit<T>> {
SimonSapin marked this conversation as resolved.
Show resolved Hide resolved
/// Convert to `Box<T>`.
SimonSapin marked this conversation as resolved.
Show resolved Hide resolved
///
/// # 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.
///
/// [`MaybeUninit::assume_init`]: ../../std/mem/union.MaybeUninit.html#method.assume_init
///
/// # Examples
///
/// ```
/// #![feature(new_uninit)]
///
/// let mut five = Box::<u32>::new_uninit();
///
/// let five: Box<u32> = unsafe {
/// // Deferred initialization:
/// five.as_mut_ptr().write(5);
///
/// five.assume_init()
/// };
///
/// assert_eq!(*five, 5)
/// ```
#[unstable(feature = "new_uninit", issue = "63291")]
#[inline]
pub unsafe fn assume_init(self) -> Box<T> {
Box(Box::into_unique(self).cast())
}
}

impl<T> Box<[mem::MaybeUninit<T>]> {
/// Convert to `Box<[T]>`.
SimonSapin marked this conversation as resolved.
Show resolved Hide resolved
///
/// # Safety
///
/// As with [`MaybeUninit::assume_init`],
/// it is up to the caller to guarantee that the values
/// really are in an initialized state.
/// Calling this when the content is not yet fully initialized
/// causes immediate undefined behavior.
///
/// [`MaybeUninit::assume_init`]: ../../std/mem/union.MaybeUninit.html#method.assume_init
///
/// # Examples
///
/// ```
/// #![feature(new_uninit)]
///
/// let mut values = Box::<[u32]>::new_uninit_slice(3);
///
/// let values = unsafe {
/// // Deferred initialization:
/// values[0].as_mut_ptr().write(1);
/// values[1].as_mut_ptr().write(2);
/// values[2].as_mut_ptr().write(3);
///
/// values.assume_init()
/// };
///
/// assert_eq!(*values, [1, 2, 3])
/// ```
#[unstable(feature = "new_uninit", issue = "63291")]
#[inline]
pub unsafe fn assume_init(self) -> Box<[T]> {
Box(Unique::new_unchecked(Box::into_raw(self) as _))
}
}

impl<T: ?Sized> Box<T> {
/// Constructs a box from a raw pointer.
///
Expand Down
178 changes: 177 additions & 1 deletion src/liballoc/rc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,37 @@ impl<T> Rc<T> {
}))
}

/// Construct a new Rc with uninitialized contents.
SimonSapin marked this conversation as resolved.
Show resolved Hide resolved
///
/// # 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);
///
/// five.assume_init()
/// };
///
/// assert_eq!(*five, 5)
/// ```
#[unstable(feature = "new_uninit", issue = "63291")]
pub fn new_uninit() -> Rc<mem::MaybeUninit<T>> {
unsafe {
Rc::from_ptr(Rc::allocate_for_unsized(
SimonSapin marked this conversation as resolved.
Show resolved Hide resolved
Layout::new::<T>(),
|mem| mem as *mut RcBox<mem::MaybeUninit<T>>,
))
}
}

/// 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")]
Expand Down Expand Up @@ -377,6 +408,118 @@ impl<T> Rc<T> {
}
}

impl<T> Rc<[T]> {
/// Construct a new reference-counted slice with uninitialized contents.
SimonSapin marked this conversation as resolved.
Show resolved Hide resolved
///
/// # Examples
///
/// ```
/// #![feature(new_uninit)]
/// #![feature(get_mut_unchecked)]
///
/// use std::rc::Rc;
///
/// let mut values = Rc::<[u32]>::new_uninit_slice(3);
///
/// let values = unsafe {
/// // Deferred initialization:
/// Rc::get_mut_unchecked(&mut values)[0].as_mut_ptr().write(1);
/// Rc::get_mut_unchecked(&mut values)[1].as_mut_ptr().write(2);
/// Rc::get_mut_unchecked(&mut values)[2].as_mut_ptr().write(3);
///
/// values.assume_init()
/// };
///
/// assert_eq!(*values, [1, 2, 3])
/// ```
#[unstable(feature = "new_uninit", issue = "63291")]
pub fn new_uninit_slice(len: usize) -> Rc<[mem::MaybeUninit<T>]> {
SimonSapin marked this conversation as resolved.
Show resolved Hide resolved
unsafe {
Rc::from_ptr(Rc::allocate_for_slice(len))
}
}
}

impl<T> Rc<mem::MaybeUninit<T>> {
/// Convert to `Rc<T>`.
SimonSapin marked this conversation as resolved.
Show resolved Hide resolved
///
/// # 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.
///
/// [`MaybeUninit::assume_init`]: ../../std/mem/union.MaybeUninit.html#method.assume_init
///
/// # 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);
///
/// five.assume_init()
/// };
///
/// assert_eq!(*five, 5)
/// ```
#[unstable(feature = "new_uninit", issue = "63291")]
#[inline]
pub unsafe fn assume_init(self) -> Rc<T> {
Rc::from_inner(mem::ManuallyDrop::new(self).ptr.cast())
}
}

impl<T> Rc<[mem::MaybeUninit<T>]> {
/// Convert to `Rc<[T]>`.
SimonSapin marked this conversation as resolved.
Show resolved Hide resolved
///
/// # 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.
///
/// [`MaybeUninit::assume_init`]: ../../std/mem/union.MaybeUninit.html#method.assume_init
///
/// # Examples
///
/// ```
/// #![feature(new_uninit)]
/// #![feature(get_mut_unchecked)]
///
/// use std::rc::Rc;
///
/// let mut values = Rc::<[u32]>::new_uninit_slice(3);
///
/// let values = unsafe {
/// // Deferred initialization:
/// Rc::get_mut_unchecked(&mut values)[0].as_mut_ptr().write(1);
/// Rc::get_mut_unchecked(&mut values)[1].as_mut_ptr().write(2);
/// Rc::get_mut_unchecked(&mut values)[2].as_mut_ptr().write(3);
///
/// values.assume_init()
/// };
///
/// assert_eq!(*values, [1, 2, 3])
RalfJung marked this conversation as resolved.
Show resolved Hide resolved
/// ```
#[unstable(feature = "new_uninit", issue = "63291")]
#[inline]
pub unsafe fn assume_init(self) -> Rc<[T]> {
Rc::from_ptr(mem::ManuallyDrop::new(self).ptr.as_ptr() as _)
}
}

impl<T: ?Sized> Rc<T> {
/// Consumes the `Rc`, returning the wrapped pointer.
///
Expand Down Expand Up @@ -560,13 +703,46 @@ impl<T: ?Sized> Rc<T> {
pub fn get_mut(this: &mut Self) -> Option<&mut T> {
if Rc::is_unique(this) {
unsafe {
Some(&mut this.ptr.as_mut().value)
Some(Rc::get_mut_unchecked(this))
}
} else {
None
}
}

/// Returns a mutable reference to the inner value,
/// without any check.
///
/// See also [`get_mut`], which is safe and does appropriate checks.
///
/// [`get_mut`]: struct.Rc.html#method.get_mut
///
/// # Safety
///
/// Any other `Rc` or [`Weak`] pointers to the same value must not be dereferenced
/// for the duration of the returned borrow.
/// This is trivially the case if no such pointer exist,
SimonSapin marked this conversation as resolved.
Show resolved Hide resolved
/// for example immediately after `Rc::new`.
///
/// # Examples
///
/// ```
/// #![feature(get_mut_unchecked)]
///
/// use std::rc::Rc;
///
/// let mut x = Rc::new(String::new());
/// unsafe {
/// Rc::get_mut_unchecked(&mut x).push_str("foo")
/// }
/// assert_eq!(*x, "foo");
/// ```
#[inline]
#[unstable(feature = "get_mut_unchecked", issue = "63292")]
pub unsafe fn get_mut_unchecked(this: &mut Self) -> &mut T {
&mut this.ptr.as_mut().value
}

#[inline]
#[stable(feature = "ptr_eq", since = "1.17.0")]
/// Returns `true` if the two `Rc`s point to the same value (not
Expand Down
Loading