Skip to content

Commit cc939ac

Browse files
committed
Add vec![ptr::null{,_mut}(); n] optimization, like vec![0; n]
vec![0; n], via implementations of SpecFromElem, has an optimization that uses with_capacity_zeroed instead of with_capacity, which will use calloc instead of malloc, and avoid an extra memset. This adds the same optimization for vec![ptr::null(); n] and vec![ptr::null_mut(); n], assuming their bit value is 0 (which is true on all currently supported platforms). This does so by adding an intermediate trait IsZero, which looks very much like nonzero::Zeroable, but that one is on the way out, and doesn't apply to pointers anyways. Adding such a trait allows to avoid repeating the logic using with_capacity_zeroed or with_capacity, or making the macro more complex to support generics.
1 parent 06fa27d commit cc939ac

File tree

1 file changed

+53
-26
lines changed

1 file changed

+53
-26
lines changed

src/liballoc/vec.rs

+53-26
Original file line numberDiff line numberDiff line change
@@ -1567,40 +1567,67 @@ impl SpecFromElem for u8 {
15671567
}
15681568
}
15691569

1570-
macro_rules! impl_spec_from_elem {
1570+
impl<T: Clone + IsZero> SpecFromElem for T {
1571+
#[inline]
1572+
fn from_elem(elem: T, n: usize) -> Vec<T> {
1573+
if elem.is_zero() {
1574+
return Vec {
1575+
buf: RawVec::with_capacity_zeroed(n),
1576+
len: n,
1577+
}
1578+
}
1579+
let mut v = Vec::with_capacity(n);
1580+
v.extend_with(n, ExtendElement(elem));
1581+
v
1582+
}
1583+
}
1584+
1585+
unsafe trait IsZero {
1586+
/// Whether this value is zero
1587+
fn is_zero(&self) -> bool;
1588+
}
1589+
1590+
macro_rules! impl_is_zero {
15711591
($t: ty, $is_zero: expr) => {
1572-
impl SpecFromElem for $t {
1592+
unsafe impl IsZero for $t {
15731593
#[inline]
1574-
fn from_elem(elem: $t, n: usize) -> Vec<$t> {
1575-
if $is_zero(elem) {
1576-
return Vec {
1577-
buf: RawVec::with_capacity_zeroed(n),
1578-
len: n,
1579-
}
1580-
}
1581-
let mut v = Vec::with_capacity(n);
1582-
v.extend_with(n, ExtendElement(elem));
1583-
v
1594+
fn is_zero(&self) -> bool {
1595+
$is_zero(*self)
15841596
}
15851597
}
1586-
};
1598+
}
15871599
}
15881600

1589-
impl_spec_from_elem!(i8, |x| x == 0);
1590-
impl_spec_from_elem!(i16, |x| x == 0);
1591-
impl_spec_from_elem!(i32, |x| x == 0);
1592-
impl_spec_from_elem!(i64, |x| x == 0);
1593-
impl_spec_from_elem!(i128, |x| x == 0);
1594-
impl_spec_from_elem!(isize, |x| x == 0);
1601+
impl_is_zero!(i8, |x| x == 0);
1602+
impl_is_zero!(i16, |x| x == 0);
1603+
impl_is_zero!(i32, |x| x == 0);
1604+
impl_is_zero!(i64, |x| x == 0);
1605+
impl_is_zero!(i128, |x| x == 0);
1606+
impl_is_zero!(isize, |x| x == 0);
15951607

1596-
impl_spec_from_elem!(u16, |x| x == 0);
1597-
impl_spec_from_elem!(u32, |x| x == 0);
1598-
impl_spec_from_elem!(u64, |x| x == 0);
1599-
impl_spec_from_elem!(u128, |x| x == 0);
1600-
impl_spec_from_elem!(usize, |x| x == 0);
1608+
impl_is_zero!(u16, |x| x == 0);
1609+
impl_is_zero!(u32, |x| x == 0);
1610+
impl_is_zero!(u64, |x| x == 0);
1611+
impl_is_zero!(u128, |x| x == 0);
1612+
impl_is_zero!(usize, |x| x == 0);
1613+
1614+
impl_is_zero!(f32, |x: f32| x.to_bits() == 0);
1615+
impl_is_zero!(f64, |x: f64| x.to_bits() == 0);
1616+
1617+
unsafe impl<T: ?Sized> IsZero for *const T {
1618+
#[inline]
1619+
fn is_zero(&self) -> bool {
1620+
(*self).is_null()
1621+
}
1622+
}
1623+
1624+
unsafe impl<T: ?Sized> IsZero for *mut T {
1625+
#[inline]
1626+
fn is_zero(&self) -> bool {
1627+
(*self).is_null()
1628+
}
1629+
}
16011630

1602-
impl_spec_from_elem!(f32, |x: f32| x.to_bits() == 0);
1603-
impl_spec_from_elem!(f64, |x: f64| x.to_bits() == 0);
16041631

16051632
////////////////////////////////////////////////////////////////////////////////
16061633
// Common trait implementations for Vec

0 commit comments

Comments
 (0)