Fast vec initialization

I need to initialize a vector for a prime sieve. I did this play to see if the iterator way was fast.

use std::ptr;

const VEC_LEN: usize = 10;

#[inline(never)]
fn init1() -> Vec<usize> {
    std::iter::repeat(0).take(VEC_LEN).collect::<Vec<_>>()
}

#[inline(never)]
fn init2() -> Vec<usize> {
    let mut v = Vec::with_capacity(VEC_LEN);
    unsafe {
        let mut p = v.as_mut_ptr();
        for _ in 0..VEC_LEN {
            ptr::write(p, 0);
            p = p.offset(1);
        }
        v.set_len(VEC_LEN);
    }
    v
}

fn main() {
    println!("{:?}", init1());
    println!("{:?}", init2());
}

There seems to be some significant differences between the asm for the 2 methods. Does this mean that my unsafe way is quicker? Is it possible for the compiler to optimize the iterator way to match the unsafe way?

vec![0; VEC_LEN] will do what you want. It is able to use calloc so it can be faster than either of the two versions above depending on how the allocator behaves.

3 Likes

Would it be possible for the compiler to spot the pattern repeate -> take -> collect and replace it with a calloc call (for the 0 case)? Or is this too complicated?

Coincidentally, it’s being looked at:
https://github.com/rust-lang/rust/pull/47944

Heh, coincidence :slight_smile: