Skip to content

Commit

Permalink
Implement Vec::from_elem specialization for all Copy types
Browse files Browse the repository at this point in the history
If the input element is zero, `Vec::from_elem` can just invoke
`calloc` for any `Copy` type.

If the input is non-zero, but its size is 1, it can allocate and then
`memset` the buffer.
  • Loading branch information
ranma42 committed Apr 17, 2017
1 parent 5997806 commit 55e52f3
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 46 deletions.
1 change: 0 additions & 1 deletion src/libcollections/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@
#![feature(box_patterns)]
#![feature(box_syntax)]
#![cfg_attr(not(test), feature(char_escape_debug))]
#![cfg_attr(not(test), feature(core_float))]
#![feature(core_intrinsics)]
#![feature(dropck_eyepatch)]
#![feature(exact_size_is_empty)]
Expand Down
77 changes: 32 additions & 45 deletions src/libcollections/vec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,6 @@ use core::hash::{self, Hash};
use core::intrinsics::{arith_offset, assume};
use core::iter::{FromIterator, FusedIterator, TrustedLen};
use core::mem;
#[cfg(not(test))]
use core::num::Float;
use core::ops::{InPlace, Index, IndexMut, Place, Placer};
use core::ops;
use core::ptr;
Expand Down Expand Up @@ -1388,59 +1386,48 @@ impl<T: Clone> SpecFromElem for T {
}
}

impl SpecFromElem for u8 {
#[inline]
fn from_elem(elem: u8, n: usize) -> Vec<u8> {
if elem == 0 {
unsafe fn chunked_or<T, U: ops::BitOr<Output = U> + Copy>(x: T) -> U {
let p = &x as *const T as *const U;
let len = mem::size_of::<T>() / mem::size_of::<U>();
slice::from_raw_parts(p, len).iter().fold(mem::zeroed(), |state, &x| state | x)
}

fn is_zero<T: Copy>(x: T) -> bool {
unsafe {
match mem::align_of::<T>() {
n if n % 16 == 0 => 0u128 == chunked_or(x),
n if n % 8 == 0 => 0u64 == chunked_or(x),
n if n % 4 == 0 => 0u32 == chunked_or(x),
n if n % 2 == 0 => 0u16 == chunked_or(x),
_ => 0u8 == chunked_or(x),
}
}
}

impl<T: Copy> SpecFromElem for T {
default fn from_elem(elem: Self, n: usize) -> Vec<Self> {
if is_zero(elem) {
return Vec {
buf: RawVec::with_capacity_zeroed(n),
len: n,
}
}
unsafe {
let mut v = Vec::with_capacity(n);
ptr::write_bytes(v.as_mut_ptr(), elem, n);
v.set_len(n);
v
}
}
}

macro_rules! impl_spec_from_elem {
($t: ty, $is_zero: expr) => {
impl SpecFromElem 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_element(n, elem);
v
let mut v = Vec::with_capacity(n);
if mem::size_of::<T>() == 1 {
unsafe {
// let elem: u8 = mem::transmute(elem);
let elem: u8 = *(&elem as *const T as *const u8);
ptr::write_bytes(v.as_mut_ptr(), elem, n);
v.set_len(n);
}
} else {
v.extend_with_element(n, elem);
}
};
v
}
}

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_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_spec_from_elem!(f32, |x: f32| x == 0. && x.is_sign_positive());
impl_spec_from_elem!(f64, |x: f64| x == 0. && x.is_sign_positive());

////////////////////////////////////////////////////////////////////////////////
// Common trait implementations for Vec
////////////////////////////////////////////////////////////////////////////////
Expand Down

0 comments on commit 55e52f3

Please sign in to comment.