about summary refs log tree commit diff
path: root/src/liballoc
diff options
context:
space:
mode:
authorSimon Sapin <simon.sapin@exyr.org>2019-07-06 17:19:58 +0200
committerSimon Sapin <simon.sapin@exyr.org>2019-08-16 17:11:18 +0200
commit7b02b9f8ec2850ac687ee5c7d869a626e09d22cb (patch)
tree3c5a4f49589032d666c3b87aeca4a72bd392688c /src/liballoc
parent1613fdae37df044f2c254d25d356b3a57eb61a50 (diff)
downloadrust-7b02b9f8ec2850ac687ee5c7d869a626e09d22cb.tar.gz
rust-7b02b9f8ec2850ac687ee5c7d869a626e09d22cb.zip
Add new_uninit and assume_init on Box, Rc, and Arc
Diffstat (limited to 'src/liballoc')
-rw-r--r--src/liballoc/boxed.rs61
-rw-r--r--src/liballoc/rc.rs81
-rw-r--r--src/liballoc/sync.rs81
3 files changed, 223 insertions, 0 deletions
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<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.
     ///
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<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());
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<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());