diff options
| author | bors <bors@rust-lang.org> | 2020-08-22 18:46:42 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2020-08-22 18:46:42 +0000 |
| commit | 663d2f5cd3163f17eddb74ee1e028d542255f21a (patch) | |
| tree | 9fa6ffb91539e291d601c8ce585949a3ef830c0e | |
| parent | 5528caf91442729b47b8f818be0a0ddfd0c17ffb (diff) | |
| parent | 5aba816672d08a076eaa8005a109968af8ce1083 (diff) | |
Auto merge of #75171 - amosonn:new_zeroed_slice, r=Amanieu
New zeroed slice
Add to #63291 the methods
```rust
impl<T> Box<[T]> { pub fn new_zeroed_slice(len: usize) -> Box<[MaybeUninit<T>]> {…} }
impl<T> Rc<[T]> { pub fn new_zeroed_slice(len: usize) -> Rc<[MaybeUninit<T>]> {…} }
impl<T> Arc<[T]> { pub fn new_zeroed_slice(len: usize) -> Arc<[MaybeUninit<T>]> {…} }
```
as suggested in https://github.com/rust-lang/rust/issues/63291#issuecomment-605511675 .
Also optimize `{Rc, Arc}::new_zeroed` to use `alloc_zeroed`, otherwise they are no more efficient than using `new_uninit` and zeroing the memory manually (which was the original implementation).
| -rw-r--r-- | library/alloc/src/boxed.rs | 23 | ||||
| -rw-r--r-- | library/alloc/src/rc.rs | 73 | ||||
| -rw-r--r-- | library/alloc/src/sync.rs | 73 |
3 files changed, 139 insertions, 30 deletions
diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index 93d0df448ea..05211e2037b 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -271,6 +271,29 @@ impl<T> Box<[T]> { pub fn new_uninit_slice(len: usize) -> Box<[mem::MaybeUninit<T>]> { unsafe { RawVec::with_capacity(len).into_box(len) } } + + /// Constructs a new boxed slice with uninitialized contents, with the memory + /// being filled with `0` bytes. + /// + /// See [`MaybeUninit::zeroed`][zeroed] for examples of correct and incorrect usage + /// of this method. + /// + /// # Examples + /// + /// ``` + /// #![feature(new_uninit)] + /// + /// let values = Box::<[u32]>::new_zeroed_slice(3); + /// let values = unsafe { values.assume_init() }; + /// + /// assert_eq!(*values, [0, 0, 0]) + /// ``` + /// + /// [zeroed]: ../../std/mem/union.MaybeUninit.html#method.zeroed + #[unstable(feature = "new_uninit", issue = "63291")] + pub fn new_zeroed_slice(len: usize) -> Box<[mem::MaybeUninit<T>]> { + unsafe { RawVec::with_capacity_zeroed(len).into_box(len) } + } } impl<T> Box<mem::MaybeUninit<T>> { diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index f8b1c21e977..1046397f4be 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -247,7 +247,7 @@ use core::pin::Pin; use core::ptr::{self, NonNull}; use core::slice::from_raw_parts_mut; -use crate::alloc::{box_free, handle_alloc_error, AllocRef, Global, Layout}; +use crate::alloc::{box_free, handle_alloc_error, AllocErr, AllocRef, Global, Layout}; use crate::borrow::{Cow, ToOwned}; use crate::string::String; use crate::vec::Vec; @@ -349,9 +349,11 @@ impl<T> Rc<T> { #[unstable(feature = "new_uninit", issue = "63291")] pub fn new_uninit() -> Rc<mem::MaybeUninit<T>> { unsafe { - Rc::from_ptr(Rc::allocate_for_layout(Layout::new::<T>(), |mem| { - mem as *mut RcBox<mem::MaybeUninit<T>> - })) + Rc::from_ptr(Rc::allocate_for_layout( + Layout::new::<T>(), + |layout| Global.alloc(layout), + |mem| mem as *mut RcBox<mem::MaybeUninit<T>>, + )) } } @@ -378,9 +380,11 @@ impl<T> Rc<T> { #[unstable(feature = "new_uninit", issue = "63291")] pub fn new_zeroed() -> Rc<mem::MaybeUninit<T>> { unsafe { - let mut uninit = Self::new_uninit(); - ptr::write_bytes::<T>(Rc::get_mut_unchecked(&mut uninit).as_mut_ptr(), 0, 1); - uninit + Rc::from_ptr(Rc::allocate_for_layout( + Layout::new::<T>(), + |layout| Global.alloc_zeroed(layout), + |mem| mem as *mut RcBox<mem::MaybeUninit<T>>, + )) } } @@ -460,6 +464,40 @@ impl<T> Rc<[T]> { pub fn new_uninit_slice(len: usize) -> Rc<[mem::MaybeUninit<T>]> { unsafe { Rc::from_ptr(Rc::allocate_for_slice(len)) } } + + /// Constructs a new reference-counted slice with uninitialized contents, with the memory being + /// filled with `0` bytes. + /// + /// See [`MaybeUninit::zeroed`][zeroed] for examples of correct and + /// incorrect usage of this method. + /// + /// # Examples + /// + /// ``` + /// #![feature(new_uninit)] + /// + /// use std::rc::Rc; + /// + /// let values = Rc::<[u32]>::new_zeroed_slice(3); + /// let values = unsafe { values.assume_init() }; + /// + /// assert_eq!(*values, [0, 0, 0]) + /// ``` + /// + /// [zeroed]: ../../std/mem/union.MaybeUninit.html#method.zeroed + #[unstable(feature = "new_uninit", issue = "63291")] + pub fn new_zeroed_slice(len: usize) -> Rc<[mem::MaybeUninit<T>]> { + unsafe { + Rc::from_ptr(Rc::allocate_for_layout( + Layout::array::<T>(len).unwrap(), + |layout| Global.alloc_zeroed(layout), + |mem| { + ptr::slice_from_raw_parts_mut(mem as *mut T, len) + as *mut RcBox<[mem::MaybeUninit<T>]> + }, + )) + } + } } impl<T> Rc<mem::MaybeUninit<T>> { @@ -905,6 +943,7 @@ impl<T: ?Sized> Rc<T> { /// and must return back a (potentially fat)-pointer for the `RcBox<T>`. unsafe fn allocate_for_layout( value_layout: Layout, + allocate: impl FnOnce(Layout) -> Result<NonNull<[u8]>, AllocErr>, mem_to_rcbox: impl FnOnce(*mut u8) -> *mut RcBox<T>, ) -> *mut RcBox<T> { // Calculate layout using the given value layout. @@ -914,7 +953,7 @@ impl<T: ?Sized> Rc<T> { let layout = Layout::new::<RcBox<()>>().extend(value_layout).unwrap().0.pad_to_align(); // Allocate for the layout. - let ptr = Global.alloc(layout).unwrap_or_else(|_| handle_alloc_error(layout)); + let ptr = allocate(layout).unwrap_or_else(|_| handle_alloc_error(layout)); // Initialize the RcBox let inner = mem_to_rcbox(ptr.as_non_null_ptr().as_ptr()); @@ -932,9 +971,11 @@ impl<T: ?Sized> Rc<T> { unsafe fn allocate_for_ptr(ptr: *const T) -> *mut RcBox<T> { // Allocate for the `RcBox<T>` using the given value. unsafe { - Self::allocate_for_layout(Layout::for_value(&*ptr), |mem| { - set_data_ptr(ptr as *mut T, mem) as *mut RcBox<T> - }) + Self::allocate_for_layout( + Layout::for_value(&*ptr), + |layout| Global.alloc(layout), + |mem| set_data_ptr(ptr as *mut T, mem) as *mut RcBox<T>, + ) } } @@ -965,9 +1006,11 @@ impl<T> Rc<[T]> { /// Allocates an `RcBox<[T]>` with the given length. unsafe fn allocate_for_slice(len: usize) -> *mut RcBox<[T]> { unsafe { - Self::allocate_for_layout(Layout::array::<T>(len).unwrap(), |mem| { - ptr::slice_from_raw_parts_mut(mem as *mut T, len) as *mut RcBox<[T]> - }) + Self::allocate_for_layout( + Layout::array::<T>(len).unwrap(), + |layout| Global.alloc(layout), + |mem| ptr::slice_from_raw_parts_mut(mem as *mut T, len) as *mut RcBox<[T]>, + ) } } } @@ -2061,7 +2104,7 @@ impl<T: ?Sized> AsRef<T> for Rc<T> { #[stable(feature = "pin", since = "1.33.0")] impl<T: ?Sized> Unpin for Rc<T> {} -/// Get the offset within an `ArcInner` for +/// Get the offset within an `RcBox` for /// a payload of type described by a pointer. /// /// # Safety diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index 4444a7a3132..2e5e3b713a1 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -21,7 +21,7 @@ use core::slice::from_raw_parts_mut; use core::sync::atomic; use core::sync::atomic::Ordering::{Acquire, Relaxed, Release, SeqCst}; -use crate::alloc::{box_free, handle_alloc_error, AllocRef, Global, Layout}; +use crate::alloc::{box_free, handle_alloc_error, AllocErr, AllocRef, Global, Layout}; use crate::borrow::{Cow, ToOwned}; use crate::boxed::Box; use crate::rc::is_dangling; @@ -343,9 +343,11 @@ impl<T> Arc<T> { #[unstable(feature = "new_uninit", issue = "63291")] pub fn new_uninit() -> Arc<mem::MaybeUninit<T>> { unsafe { - Arc::from_ptr(Arc::allocate_for_layout(Layout::new::<T>(), |mem| { - mem as *mut ArcInner<mem::MaybeUninit<T>> - })) + Arc::from_ptr(Arc::allocate_for_layout( + Layout::new::<T>(), + |layout| Global.alloc(layout), + |mem| mem as *mut ArcInner<mem::MaybeUninit<T>>, + )) } } @@ -372,9 +374,11 @@ impl<T> Arc<T> { #[unstable(feature = "new_uninit", issue = "63291")] pub fn new_zeroed() -> Arc<mem::MaybeUninit<T>> { unsafe { - let mut uninit = Self::new_uninit(); - ptr::write_bytes::<T>(Arc::get_mut_unchecked(&mut uninit).as_mut_ptr(), 0, 1); - uninit + Arc::from_ptr(Arc::allocate_for_layout( + Layout::new::<T>(), + |layout| Global.alloc_zeroed(layout), + |mem| mem as *mut ArcInner<mem::MaybeUninit<T>>, + )) } } @@ -426,7 +430,7 @@ impl<T> Arc<T> { } impl<T> Arc<[T]> { - /// Constructs a new reference-counted slice with uninitialized contents. + /// Constructs a new atomically reference-counted slice with uninitialized contents. /// /// # Examples /// @@ -453,6 +457,40 @@ impl<T> Arc<[T]> { pub fn new_uninit_slice(len: usize) -> Arc<[mem::MaybeUninit<T>]> { unsafe { Arc::from_ptr(Arc::allocate_for_slice(len)) } } + + /// Constructs a new atomically reference-counted slice with uninitialized contents, with the memory being + /// filled with `0` bytes. + /// + /// See [`MaybeUninit::zeroed`][zeroed] for examples of correct and + /// incorrect usage of this method. + /// + /// # Examples + /// + /// ``` + /// #![feature(new_uninit)] + /// + /// use std::sync::Arc; + /// + /// let values = Arc::<[u32]>::new_zeroed_slice(3); + /// let values = unsafe { values.assume_init() }; + /// + /// assert_eq!(*values, [0, 0, 0]) + /// ``` + /// + /// [zeroed]: ../../std/mem/union.MaybeUninit.html#method.zeroed + #[unstable(feature = "new_uninit", issue = "63291")] + pub fn new_zeroed_slice(len: usize) -> Arc<[mem::MaybeUninit<T>]> { + unsafe { + Arc::from_ptr(Arc::allocate_for_layout( + Layout::array::<T>(len).unwrap(), + |layout| Global.alloc_zeroed(layout), + |mem| { + ptr::slice_from_raw_parts_mut(mem as *mut T, len) + as *mut ArcInner<[mem::MaybeUninit<T>]> + }, + )) + } + } } impl<T> Arc<mem::MaybeUninit<T>> { @@ -858,6 +896,7 @@ impl<T: ?Sized> Arc<T> { /// and must return back a (potentially fat)-pointer for the `ArcInner<T>`. unsafe fn allocate_for_layout( value_layout: Layout, + allocate: impl FnOnce(Layout) -> Result<NonNull<[u8]>, AllocErr>, mem_to_arcinner: impl FnOnce(*mut u8) -> *mut ArcInner<T>, ) -> *mut ArcInner<T> { // Calculate layout using the given value layout. @@ -866,7 +905,7 @@ impl<T: ?Sized> Arc<T> { // reference (see #54908). let layout = Layout::new::<ArcInner<()>>().extend(value_layout).unwrap().0.pad_to_align(); - let ptr = Global.alloc(layout).unwrap_or_else(|_| handle_alloc_error(layout)); + let ptr = allocate(layout).unwrap_or_else(|_| handle_alloc_error(layout)); // Initialize the ArcInner let inner = mem_to_arcinner(ptr.as_non_null_ptr().as_ptr()); @@ -884,9 +923,11 @@ impl<T: ?Sized> Arc<T> { unsafe fn allocate_for_ptr(ptr: *const T) -> *mut ArcInner<T> { // Allocate for the `ArcInner<T>` using the given value. unsafe { - Self::allocate_for_layout(Layout::for_value(&*ptr), |mem| { - set_data_ptr(ptr as *mut T, mem) as *mut ArcInner<T> - }) + Self::allocate_for_layout( + Layout::for_value(&*ptr), + |layout| Global.alloc(layout), + |mem| set_data_ptr(ptr as *mut T, mem) as *mut ArcInner<T>, + ) } } @@ -917,9 +958,11 @@ impl<T> Arc<[T]> { /// Allocates an `ArcInner<[T]>` with the given length. unsafe fn allocate_for_slice(len: usize) -> *mut ArcInner<[T]> { unsafe { - Self::allocate_for_layout(Layout::array::<T>(len).unwrap(), |mem| { - ptr::slice_from_raw_parts_mut(mem as *mut T, len) as *mut ArcInner<[T]> - }) + Self::allocate_for_layout( + Layout::array::<T>(len).unwrap(), + |layout| Global.alloc(layout), + |mem| ptr::slice_from_raw_parts_mut(mem as *mut T, len) as *mut ArcInner<[T]>, + ) } } } |
