Skip to content

Commit f90aeeb

Browse files
committed
Add function to clone a slice into a boxed slice
1 parent 939b143 commit f90aeeb

File tree

3 files changed

+97
-9
lines changed

3 files changed

+97
-9
lines changed

library/alloc/src/boxed.rs

+3-7
Original file line numberDiff line numberDiff line change
@@ -1229,13 +1229,9 @@ impl<T: Copy> From<&[T]> for Box<[T]> {
12291229
///
12301230
/// println!("{:?}", boxed_slice);
12311231
/// ```
1232+
#[inline]
12321233
fn from(slice: &[T]) -> Box<[T]> {
1233-
let len = slice.len();
1234-
let buf = RawVec::with_capacity(len);
1235-
unsafe {
1236-
ptr::copy_nonoverlapping(slice.as_ptr(), buf.ptr(), len);
1237-
buf.into_box(slice.len()).assume_init()
1238-
}
1234+
slice.to_boxed_slice()
12391235
}
12401236
}
12411237

@@ -1578,7 +1574,7 @@ impl<I> FromIterator<I> for Box<[I]> {
15781574
impl<T: Clone, A: Allocator + Clone> Clone for Box<[T], A> {
15791575
fn clone(&self) -> Self {
15801576
let alloc = Box::allocator(self).clone();
1581-
self.to_vec_in(alloc).into_boxed_slice()
1577+
self.to_boxed_slice_in(alloc)
15821578
}
15831579

15841580
fn clone_from(&mut self, other: &Self) {

library/alloc/src/slice.rs

+93
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,7 @@ pub use hack::to_vec;
143143
// `test_permutations` test
144144
mod hack {
145145
use core::alloc::Allocator;
146+
use core::mem::MaybeUninit;
146147

147148
use crate::boxed::Box;
148149
use crate::vec::Vec;
@@ -163,10 +164,19 @@ mod hack {
163164
T::to_vec(s, alloc)
164165
}
165166

167+
#[inline]
168+
pub fn to_boxed_slice<T: ConvertVec, A: Allocator>(s: &[T], alloc: A) -> Box<[T], A> {
169+
T::to_boxed_slice(s, alloc)
170+
}
171+
166172
pub trait ConvertVec {
167173
fn to_vec<A: Allocator>(s: &[Self], alloc: A) -> Vec<Self, A>
168174
where
169175
Self: Sized;
176+
177+
fn to_boxed_slice<A: Allocator>(s: &[Self], alloc: A) -> Box<[Self], A>
178+
where
179+
Self: Sized;
170180
}
171181

172182
impl<T: Clone> ConvertVec for T {
@@ -203,6 +213,35 @@ mod hack {
203213
}
204214
vec
205215
}
216+
217+
#[inline]
218+
default fn to_boxed_slice<A: Allocator>(s: &[Self], alloc: A) -> Box<[Self], A> {
219+
struct DropGuard<T> {
220+
dst: *mut T,
221+
num_init: usize,
222+
}
223+
impl<T> Drop for DropGuard<T> {
224+
#[inline]
225+
fn drop(&mut self) {
226+
let init_slice = core::ptr::slice_from_raw_parts_mut(self.dst, self.num_init);
227+
// SAFETY: all elements in this slice have been initialized
228+
unsafe {
229+
core::ptr::drop_in_place(init_slice);
230+
}
231+
}
232+
}
233+
234+
let mut boxed = Box::new_uninit_slice_in(s.len(), alloc);
235+
let mut guard =
236+
DropGuard { dst: MaybeUninit::slice_as_mut_ptr(&mut boxed), num_init: 0 };
237+
while guard.num_init < s.len() {
238+
boxed[guard.num_init].write(s[guard.num_init].clone());
239+
guard.num_init += 1;
240+
}
241+
core::mem::forget(guard);
242+
// SAFETY: each element is initialized by the loop above
243+
unsafe { boxed.assume_init() }
244+
}
206245
}
207246

208247
impl<T: Copy> ConvertVec for T {
@@ -218,6 +257,17 @@ mod hack {
218257
}
219258
v
220259
}
260+
261+
#[inline]
262+
fn to_boxed_slice<A: Allocator>(s: &[Self], alloc: A) -> Box<[Self], A> {
263+
let mut boxed = Box::new_uninit_slice_in(s.len(), alloc);
264+
let boxed_ptr = MaybeUninit::slice_as_mut_ptr(&mut boxed);
265+
// SAFETY: `boxed` contains `s.len()` elements and all are initialized
266+
unsafe {
267+
s.as_ptr().copy_to_nonoverlapping(boxed_ptr, s.len());
268+
boxed.assume_init()
269+
}
270+
}
221271
}
222272
}
223273

@@ -477,6 +527,49 @@ impl<T> [T] {
477527
hack::to_vec(self, alloc)
478528
}
479529

530+
/// Clones `self` into a new boxed slice.
531+
///
532+
/// # Examples
533+
///
534+
/// ```
535+
/// #![feature(slice_to_boxed)]
536+
///
537+
/// let s = [1, 2, 3];
538+
/// let x: Box<[i32]> = s.to_boxed_slice();
539+
/// assert_eq!(&s, x.as_ref());
540+
/// ```
541+
#[inline]
542+
#[unstable(feature = "slice_to_boxed", issue = "82725")]
543+
pub fn to_boxed_slice(&self) -> Box<Self>
544+
where
545+
T: Clone,
546+
{
547+
self.to_boxed_slice_in(Global)
548+
}
549+
550+
/// Clones `self` into a new boxed slice with an allocator.
551+
///
552+
/// # Examples
553+
///
554+
/// ```
555+
/// #![feature(allocator_api)]
556+
///
557+
/// use std::alloc::System;
558+
///
559+
/// let s = [1, 2, 3];
560+
/// let x: Box<[i32], System> = s.to_boxed_slice_in(System);
561+
/// assert_eq!(&s, x.as_ref());
562+
/// ```
563+
#[inline]
564+
#[unstable(feature = "allocator_api", issue = "32838")]
565+
// #[unstable(feature = "slice_to_boxed", issue = "82725")]
566+
pub fn to_boxed_slice_in<A: Allocator>(&self, alloc: A) -> Box<Self, A>
567+
where
568+
T: Clone,
569+
{
570+
hack::to_boxed_slice(self, alloc)
571+
}
572+
480573
/// Converts `self` into a vector without clones or allocation.
481574
///
482575
/// The resulting vector can be converted back into a box via

library/std/src/sys/unix/fs.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -464,8 +464,7 @@ impl Iterator for ReadDir {
464464
let ret = DirEntry {
465465
entry: *entry_ptr,
466466
name: slice::from_raw_parts(name as *const u8, namelen as usize)
467-
.to_owned()
468-
.into_boxed_slice(),
467+
.to_boxed_slice(),
469468
dir: Arc::clone(&self.inner),
470469
};
471470
if ret.name_bytes() != b"." && ret.name_bytes() != b".." {

0 commit comments

Comments
 (0)