From 7b02b9f8ec2850ac687ee5c7d869a626e09d22cb Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Sat, 6 Jul 2019 17:19:58 +0200 Subject: Add new_uninit and assume_init on Box, Rc, and Arc --- src/liballoc/boxed.rs | 61 ++++++++++++++++++++++++++++++++++++++ src/liballoc/rc.rs | 81 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/liballoc/sync.rs | 81 +++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 223 insertions(+) (limited to 'src/liballoc') diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index c92db517cad..5ea7847ca45 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -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 Box { box x } + /// Construct a new box with uninitialized contents. + /// + /// # Examples + /// + /// ``` + /// #![feature(new_uninit)] + /// + /// let mut five = Box::::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> { + let layout = alloc::Layout::new::>(); + 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>`. 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 Box { } } +impl Box> { + /// Convert to `Box`. + /// + /// # 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::::new_uninit(); + /// + /// let five: Box = 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 { + Box(Box::into_unique(this).cast()) + } +} + impl Box { /// Constructs a box from a raw pointer. /// diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index 22d06180d8d..c902580354d 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -327,6 +327,43 @@ impl Rc { })) } + /// Construct a new Rc with uninitialized contents. + /// + /// # Examples + /// + /// ``` + /// #![feature(new_uninit)] + /// #![feature(get_mut_unchecked)] + /// + /// use std::rc::Rc; + /// + /// let mut five = Rc::::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> { + let layout = Layout::new::>>(); + unsafe { + let mut ptr = Global.alloc(layout) + .unwrap_or_else(|_| handle_alloc_error(layout)) + .cast::>>(); + 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>`. 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 Rc { } } +impl Rc> { + /// Convert to `Rc`. + /// + /// # 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::::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 { + let ptr = this.ptr.cast(); + mem::forget(this); + Rc { + ptr, + phantom: PhantomData, + } + } +} + impl Rc { /// Consumes the `Rc`, returning the wrapped pointer. /// @@ -582,6 +661,8 @@ impl Rc { /// # Examples /// /// ``` + /// #![feature(get_mut_unchecked)] + /// /// use std::rc::Rc; /// /// let mut x = Rc::new(String::new()); diff --git a/src/liballoc/sync.rs b/src/liballoc/sync.rs index 4cd8e1fd4dd..8c63c81ee27 100644 --- a/src/liballoc/sync.rs +++ b/src/liballoc/sync.rs @@ -311,6 +311,43 @@ impl Arc { 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::::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> { + let layout = Layout::new::>>(); + unsafe { + let mut ptr = Global.alloc(layout) + .unwrap_or_else(|_| handle_alloc_error(layout)) + .cast::>>(); + 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>`. 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 Arc { } } +impl Arc> { + /// Convert to `Arc`. + /// + /// # 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::::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 { + let ptr = this.ptr.cast(); + mem::forget(this); + Arc { + ptr, + phantom: PhantomData, + } + } +} + impl Arc { /// Consumes the `Arc`, returning the wrapped pointer. /// @@ -967,6 +1046,8 @@ impl Arc { /// # Examples /// /// ``` + /// #![feature(get_mut_unchecked)] + /// /// use std::sync::Arc; /// /// let mut x = Arc::new(String::new()); -- cgit 1.4.1-3-g733a5