diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index 04033905728ab..aa8b024f5cd8b 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -1229,13 +1229,9 @@ impl From<&[T]> for Box<[T]> { /// /// println!("{:?}", boxed_slice); /// ``` + #[inline] fn from(slice: &[T]) -> Box<[T]> { - let len = slice.len(); - let buf = RawVec::with_capacity(len); - unsafe { - ptr::copy_nonoverlapping(slice.as_ptr(), buf.ptr(), len); - buf.into_box(slice.len()).assume_init() - } + slice.to_boxed_slice() } } @@ -1578,7 +1574,7 @@ impl FromIterator for Box<[I]> { impl Clone for Box<[T], A> { fn clone(&self) -> Self { let alloc = Box::allocator(self).clone(); - self.to_vec_in(alloc).into_boxed_slice() + self.to_boxed_slice_in(alloc) } fn clone_from(&mut self, other: &Self) { diff --git a/library/alloc/src/slice.rs b/library/alloc/src/slice.rs index 0c911cea1bb1e..d5574f55c89a7 100644 --- a/library/alloc/src/slice.rs +++ b/library/alloc/src/slice.rs @@ -143,6 +143,7 @@ pub use hack::to_vec; // `test_permutations` test mod hack { use core::alloc::Allocator; + use core::mem::MaybeUninit; use crate::boxed::Box; use crate::vec::Vec; @@ -159,64 +160,62 @@ mod hack { } #[inline] - pub fn to_vec(s: &[T], alloc: A) -> Vec { - T::to_vec(s, alloc) + pub fn to_vec(s: &[T], alloc: A) -> Vec { + into_vec(to_boxed_slice(s, alloc)) } - pub trait ConvertVec { - fn to_vec(s: &[Self], alloc: A) -> Vec + #[inline] + pub fn to_boxed_slice(s: &[T], alloc: A) -> Box<[T], A> { + T::to_boxed_slice(s, alloc) + } + + pub trait ConvertBoxed { + fn to_boxed_slice(s: &[Self], alloc: A) -> Box<[Self], A> where Self: Sized; } - impl ConvertVec for T { + impl ConvertBoxed for T { #[inline] - default fn to_vec(s: &[Self], alloc: A) -> Vec { - struct DropGuard<'a, T, A: Allocator> { - vec: &'a mut Vec, + default fn to_boxed_slice(s: &[Self], alloc: A) -> Box<[Self], A> { + struct DropGuard { + dst: *mut T, num_init: usize, } - impl<'a, T, A: Allocator> Drop for DropGuard<'a, T, A> { + impl Drop for DropGuard { #[inline] fn drop(&mut self) { - // SAFETY: - // items were marked initialized in the loop below + let init_slice = core::ptr::slice_from_raw_parts_mut(self.dst, self.num_init); + // SAFETY: all elements in this slice have been initialized unsafe { - self.vec.set_len(self.num_init); + core::ptr::drop_in_place(init_slice); } } } - let mut vec = Vec::with_capacity_in(s.len(), alloc); - let mut guard = DropGuard { vec: &mut vec, num_init: 0 }; - let slots = guard.vec.spare_capacity_mut(); - // .take(slots.len()) is necessary for LLVM to remove bounds checks - // and has better codegen than zip. - for (i, b) in s.iter().enumerate().take(slots.len()) { - guard.num_init = i; - slots[i].write(b.clone()); + + let mut boxed = Box::new_uninit_slice_in(s.len(), alloc); + let mut guard = + DropGuard { dst: MaybeUninit::slice_as_mut_ptr(&mut boxed), num_init: 0 }; + while guard.num_init < s.len() { + boxed[guard.num_init].write(s[guard.num_init].clone()); + guard.num_init += 1; } core::mem::forget(guard); - // SAFETY: - // the vec was allocated and initialized above to at least this length. - unsafe { - vec.set_len(s.len()); - } - vec + // SAFETY: each element is initialized by the loop above + unsafe { boxed.assume_init() } } } - impl ConvertVec for T { + impl ConvertBoxed for T { #[inline] - fn to_vec(s: &[Self], alloc: A) -> Vec { - let mut v = Vec::with_capacity_in(s.len(), alloc); - // SAFETY: - // allocated above with the capacity of `s`, and initialize to `s.len()` in - // ptr::copy_to_non_overlapping below. + fn to_boxed_slice(s: &[Self], alloc: A) -> Box<[Self], A> { + let mut boxed = Box::new_uninit_slice_in(s.len(), alloc); + let boxed_ptr = MaybeUninit::slice_as_mut_ptr(&mut boxed); + // SAFETY: `boxed` contains `s.len()` elements and all are initialized unsafe { - s.as_ptr().copy_to_nonoverlapping(v.as_mut_ptr(), s.len()); - v.set_len(s.len()); + s.as_ptr().copy_to_nonoverlapping(boxed_ptr, s.len()); + boxed.assume_init() } - v } } } @@ -477,6 +476,49 @@ impl [T] { hack::to_vec(self, alloc) } + /// Clones `self` into a new boxed slice. + /// + /// # Examples + /// + /// ``` + /// #![feature(slice_to_boxed)] + /// + /// let s = [1, 2, 3]; + /// let x: Box<[i32]> = s.to_boxed_slice(); + /// assert_eq!(&s, x.as_ref()); + /// ``` + #[inline] + #[unstable(feature = "slice_to_boxed", issue = "82725")] + pub fn to_boxed_slice(&self) -> Box + where + T: Clone, + { + self.to_boxed_slice_in(Global) + } + + /// Clones `self` into a new boxed slice with an allocator. + /// + /// # Examples + /// + /// ``` + /// #![feature(allocator_api)] + /// + /// use std::alloc::System; + /// + /// let s = [1, 2, 3]; + /// let x: Box<[i32], System> = s.to_boxed_slice_in(System); + /// assert_eq!(&s, x.as_ref()); + /// ``` + #[inline] + #[unstable(feature = "allocator_api", issue = "32838")] + // #[unstable(feature = "slice_to_boxed", issue = "82725")] + pub fn to_boxed_slice_in(&self, alloc: A) -> Box + where + T: Clone, + { + hack::to_boxed_slice(self, alloc) + } + /// Converts `self` into a vector without clones or allocation. /// /// The resulting vector can be converted back into a box via diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs index d1b0ad9e5f847..633380276dde6 100644 --- a/library/std/src/sys/unix/fs.rs +++ b/library/std/src/sys/unix/fs.rs @@ -464,8 +464,7 @@ impl Iterator for ReadDir { let ret = DirEntry { entry: *entry_ptr, name: slice::from_raw_parts(name as *const u8, namelen as usize) - .to_owned() - .into_boxed_slice(), + .to_boxed_slice(), dir: Arc::clone(&self.inner), }; if ret.name_bytes() != b"." && ret.name_bytes() != b".." {