Skip to content

Commit 3e7ff96

Browse files
authored
Unrolled build for #160432
Rollup merge of #160432 - joboet:ensure_init_generic, r=clarfonthey core: generalize `BorrowedCursor::ensure_init` Tracking issue: #160476 This implements the future possibility left out in #149749 (comment) and makes `ensure_init` generic over `Default`. I used specialisation to make sure the performance in the `u8` case stays equivalent to `memset` irrespective of how clever the optimiser happens to be. CC @joshtriplett as you've been working on this stuff recently. This also adds a public `write_default` method on `[MaybeUninit<T>]` that's doing the equivalent of `.write_init(|_| Default::default())`, but uses specialisation for integers. This uses the existing [tracking issue for `maybe_uninit_fill`](#117428).
2 parents 0e72e32 + 0100285 commit 3e7ff96

2 files changed

Lines changed: 76 additions & 13 deletions

File tree

library/core/src/io/borrowed_buf.rs

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
use crate::fmt::{self, Debug, Formatter};
44
use crate::mem::{self, MaybeUninit};
5-
use crate::ptr;
65

76
/// A borrowed buffer of initially uninitialized elements, which is incrementally filled.
87
///
@@ -357,24 +356,21 @@ impl<'a, T: Copy> BorrowedCursor<'a, T> {
357356
}
358357
}
359358

360-
impl<'a> BorrowedCursor<'a, u8> {
361-
/// Initializes all bytes in the cursor and returns them.
359+
impl<'a, T: Default + Copy> BorrowedCursor<'a, T> {
360+
/// Initializes all elements in the cursor with their default value and
361+
/// returns them.
362362
#[unstable(feature = "borrowed_buf_init", issue = "160476")]
363363
#[inline]
364-
pub fn ensure_init(&mut self) -> &mut [u8] {
365-
// SAFETY: always in bounds and we never uninitialize these bytes.
364+
pub fn ensure_init(&mut self) -> &mut [T] {
365+
// SAFETY: always in bounds and we never uninitialize these elements.
366366
let unfilled = unsafe { self.buf.buf.get_unchecked_mut(self.buf.filled..) };
367367

368368
if !self.buf.init {
369-
// SAFETY: 0 is a valid value for MaybeUninit<u8> and the length matches the allocation
370-
// since it is comes from a slice reference.
371-
unsafe {
372-
ptr::write_bytes(unfilled.as_mut_ptr(), 0, unfilled.len());
373-
}
369+
unfilled.write_default();
374370
self.buf.init = true;
375371
}
376372

377-
// SAFETY: these bytes have just been initialized if they weren't before
373+
// SAFETY: these elements have just been initialized if they weren't before
378374
unsafe { unfilled.assume_init_mut() }
379375
}
380376
}

library/core/src/mem/maybe_uninit.rs

Lines changed: 69 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1286,8 +1286,8 @@ impl<T> [MaybeUninit<T>] {
12861286
/// Fills a slice with elements returned by calling a closure for each index.
12871287
///
12881288
/// This method uses a closure to create new values. If you'd rather `Clone` a given value, use
1289-
/// [slice::write_filled]. If you want to use the `Default` trait to generate values, you can
1290-
/// pass [`|_| Default::default()`][Default::default] as the argument.
1289+
/// [`slice::write_filled`]. If you want to use the `Default` trait to generate values, use
1290+
/// [`slice::write_default`].
12911291
///
12921292
/// # Panics
12931293
///
@@ -1324,6 +1324,73 @@ impl<T> [MaybeUninit<T>] {
13241324
unsafe { self.assume_init_mut() }
13251325
}
13261326

1327+
/// Fills a slice with elements returned by calling [`Default::default`] for each index.
1328+
///
1329+
/// # Panics
1330+
///
1331+
/// This function will panic if any call to [`Default::default`] panics.
1332+
///
1333+
/// If such a panic occurs, any elements previously initialized during this operation will be
1334+
/// dropped.
1335+
///
1336+
/// # Examples
1337+
///
1338+
/// ```
1339+
/// #![feature(maybe_uninit_fill)]
1340+
/// use std::mem::MaybeUninit;
1341+
///
1342+
/// let mut buf = [const { MaybeUninit::<usize>::uninit() }; 5];
1343+
/// let initialized = buf.write_default();
1344+
/// assert_eq!(initialized, &mut [0, 0, 0, 0, 0]);
1345+
/// ```
1346+
#[unstable(feature = "maybe_uninit_fill", issue = "117428")]
1347+
pub fn write_default(&mut self) -> &mut [T]
1348+
where
1349+
T: Default,
1350+
{
1351+
trait DefaultSpec: Default {
1352+
fn write_default(buf: &mut [MaybeUninit<Self>]) -> &mut [Self];
1353+
}
1354+
1355+
impl<T: Default> DefaultSpec for T {
1356+
default fn write_default(buf: &mut [MaybeUninit<Self>]) -> &mut [Self] {
1357+
buf.write_with(|_| T::default())
1358+
}
1359+
}
1360+
1361+
macro_rules! spec_default_zero {
1362+
($ty:ty) => {
1363+
impl DefaultSpec for $ty {
1364+
fn write_default(buf: &mut [MaybeUninit<Self>]) -> &mut [Self] {
1365+
// SAFETY:
1366+
// `Default::default` is equivalent to zero-initialization
1367+
// for all these types, and this initializes the entire
1368+
// slice.
1369+
unsafe {
1370+
buf.as_mut_ptr().write_bytes(0, buf.len());
1371+
buf.assume_init_mut()
1372+
}
1373+
}
1374+
}
1375+
};
1376+
}
1377+
1378+
spec_default_zero!(i8);
1379+
spec_default_zero!(u8);
1380+
spec_default_zero!(i16);
1381+
spec_default_zero!(u16);
1382+
spec_default_zero!(i32);
1383+
spec_default_zero!(u32);
1384+
spec_default_zero!(i64);
1385+
spec_default_zero!(u64);
1386+
spec_default_zero!(i128);
1387+
spec_default_zero!(u128);
1388+
spec_default_zero!(isize);
1389+
spec_default_zero!(usize);
1390+
1391+
T::write_default(self)
1392+
}
1393+
13271394
/// Fills a slice with elements yielded by an iterator until either all elements have been
13281395
/// initialized or the iterator is empty.
13291396
///

0 commit comments

Comments
 (0)