From cc939ac345091327b23f807b7d1f6a7c75c03f36 Mon Sep 17 00:00:00 2001 From: Mike Hommey Date: Fri, 30 Mar 2018 16:10:47 +0900 Subject: [PATCH 1/2] 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. --- src/liballoc/vec.rs | 79 ++++++++++++++++++++++++++++++--------------- 1 file changed, 53 insertions(+), 26 deletions(-) diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs index 2eedb964f88ba..512c74d9d7704 100644 --- a/src/liballoc/vec.rs +++ b/src/liballoc/vec.rs @@ -1567,40 +1567,67 @@ impl SpecFromElem for u8 { } } -macro_rules! impl_spec_from_elem { +impl SpecFromElem for T { + #[inline] + fn from_elem(elem: T, n: usize) -> Vec { + if elem.is_zero() { + return Vec { + buf: RawVec::with_capacity_zeroed(n), + len: n, + } + } + let mut v = Vec::with_capacity(n); + v.extend_with(n, ExtendElement(elem)); + v + } +} + +unsafe trait IsZero { + /// Whether this value is zero + fn is_zero(&self) -> bool; +} + +macro_rules! impl_is_zero { ($t: ty, $is_zero: expr) => { - impl SpecFromElem for $t { + unsafe impl IsZero for $t { #[inline] - fn from_elem(elem: $t, n: usize) -> Vec<$t> { - if $is_zero(elem) { - return Vec { - buf: RawVec::with_capacity_zeroed(n), - len: n, - } - } - let mut v = Vec::with_capacity(n); - v.extend_with(n, ExtendElement(elem)); - v + fn is_zero(&self) -> bool { + $is_zero(*self) } } - }; + } } -impl_spec_from_elem!(i8, |x| x == 0); -impl_spec_from_elem!(i16, |x| x == 0); -impl_spec_from_elem!(i32, |x| x == 0); -impl_spec_from_elem!(i64, |x| x == 0); -impl_spec_from_elem!(i128, |x| x == 0); -impl_spec_from_elem!(isize, |x| x == 0); +impl_is_zero!(i8, |x| x == 0); +impl_is_zero!(i16, |x| x == 0); +impl_is_zero!(i32, |x| x == 0); +impl_is_zero!(i64, |x| x == 0); +impl_is_zero!(i128, |x| x == 0); +impl_is_zero!(isize, |x| x == 0); -impl_spec_from_elem!(u16, |x| x == 0); -impl_spec_from_elem!(u32, |x| x == 0); -impl_spec_from_elem!(u64, |x| x == 0); -impl_spec_from_elem!(u128, |x| x == 0); -impl_spec_from_elem!(usize, |x| x == 0); +impl_is_zero!(u16, |x| x == 0); +impl_is_zero!(u32, |x| x == 0); +impl_is_zero!(u64, |x| x == 0); +impl_is_zero!(u128, |x| x == 0); +impl_is_zero!(usize, |x| x == 0); + +impl_is_zero!(f32, |x: f32| x.to_bits() == 0); +impl_is_zero!(f64, |x: f64| x.to_bits() == 0); + +unsafe impl IsZero for *const T { + #[inline] + fn is_zero(&self) -> bool { + (*self).is_null() + } +} + +unsafe impl IsZero for *mut T { + #[inline] + fn is_zero(&self) -> bool { + (*self).is_null() + } +} -impl_spec_from_elem!(f32, |x: f32| x.to_bits() == 0); -impl_spec_from_elem!(f64, |x: f64| x.to_bits() == 0); //////////////////////////////////////////////////////////////////////////////// // Common trait implementations for Vec From 0df837f79289819f9b671b67d4e63dfe5c80d419 Mon Sep 17 00:00:00 2001 From: Mike Hommey Date: Mon, 2 Apr 2018 10:44:38 +0900 Subject: [PATCH 2/2] Add vec!['\0'; n] optimization, like vec![0; n] Similarly to vec![ptr::null{,_mut}(); n] in previous change, this adds the optimization for vec!['\0'; n]. --- src/liballoc/vec.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs index 512c74d9d7704..515b79e5acdc7 100644 --- a/src/liballoc/vec.rs +++ b/src/liballoc/vec.rs @@ -1611,6 +1611,8 @@ impl_is_zero!(u64, |x| x == 0); impl_is_zero!(u128, |x| x == 0); impl_is_zero!(usize, |x| x == 0); +impl_is_zero!(char, |x| x == '\0'); + impl_is_zero!(f32, |x: f32| x.to_bits() == 0); impl_is_zero!(f64, |x: f64| x.to_bits() == 0);