arrayvec icon indicating copy to clipboard operation
arrayvec copied to clipboard

Missing ArrayVec::resize

Open ghost opened this issue 8 years ago • 10 comments

I'm missing the resize functionality (similar to the std::vec::Vec::resize):

fn resize(&mut self, new_len: usize, value: T)

I have to fill some items in a random order, so first the array have to be resized with some default values before indexing can start. I could use plain arrays, but I'd like to use ArrayVec for it's "virtual dynamic" size.

Is there a function for this I've missed?

Edit: This is my workaround:

(0..count).for_each(|_| self.attributes.push(Attribute::new()));

ghost avatar Sep 29 '17 14:09 ghost

Using extend or FromIterator would be idiomatic here too, so think the existing functionality is already quite good for the use case

bluss avatar Sep 29 '17 15:09 bluss

@bluss I tried using extend for this, but the code is not ergonomic either:

arrv.extend([0u8; 100].iter().map(|&x| x));

Also it might be a slow operation inserting bytes one by one instead of memset.

pftbest avatar Oct 07 '17 14:10 pftbest

Nothing blocks adding resize to arrayvec. Extend and FromIterator are the answer to the question of missed methods, though.

bluss avatar Oct 07 '17 14:10 bluss

Fwiw, this benchmark shows that the extend loop is pretty good but it's running into that "SetLenOnDrop problem", where the alias analysis is not good enough. It's not managing to merge the adjacent byte writes into bigger writes, because it's also writing to the array length field in the same loop.

Benchmark used:


extern crate arrayvec;
#[macro_use] extern crate bencher;

use arrayvec::ArrayVec;

use bencher::Bencher;

fn extend(b: &mut Bencher) {
    let mut v = ArrayVec::<[u8; 1 << 16]>::new();
    let cap = v.capacity();
    b.iter(|| {
        v.clear();
        v.extend((0..cap).map(|_| 1));
        v[0]
    });
    b.bytes = v.capacity() as u64;
}


benchmark_group!(benches, extend);
benchmark_main!(benches);

Which means that it's the kind of sad mutable no alias issue?

Inner loop is this:

       │ 60:   mov    BYTE PTR [rsp+rbx*1+0x10021],0x1
 17,16 │       lea    edx,[rbx+0x10001]              
       │       mov    DWORD PTR [rsp+0x10024],edx   
       │       mov    BYTE PTR [rsp+rbx*1+0x10022],0x1
 15,09 │       lea    edx,[rbx+0x10002]              
       │       mov    DWORD PTR [rsp+0x10024],edx   
 11,32 │       mov    BYTE PTR [rsp+rbx*1+0x10023],0x1
 16,62 │       lea    edx,[rbx+0x10003]              
       │       mov    DWORD PTR [rsp+0x10024],edx   
  7,37 │       mov    BYTE PTR [rsp+rbx*1+0x10024],0x1
 13,84 │       lea    edx,[rbx+0x10004]              
       │       mov    DWORD PTR [rsp+0x10024],edx   
 18,60 │       add    rbx,0x4                      
       │     ↑ jne    60                          

bluss avatar Oct 07 '17 14:10 bluss

Sorry for off-topic, but there is also one other method I miss, extend_from_slice. I know that there is a write method that does exactly that, but it's not available on no_std targets, so I had to copy-paste it in my codebase.

pftbest avatar Oct 07 '17 14:10 pftbest

Fwiw, -Zmutable-noalias does not help with that problem. Will post a PR to improve .extend()

bluss avatar Oct 08 '17 15:10 bluss

@pftbest Is it the interface of the method or the performance? #74 shows that the performance of extend seems good enough for the use case.

bluss avatar Oct 26 '17 17:10 bluss

@bluss, sorry I didn't test #74 yet. Yes, I was concerned about the performance because I'm working with a microcontroller target that is not very fast. I will come back when I'll have some measurements.

pftbest avatar Oct 26 '17 17:10 pftbest

Is this method still desired? If not, an alternative might be spare_capacity_mut like rust-lang/rust#75017.

clarfonthey avatar May 02 '21 22:05 clarfonthey

What is the current status?

kekeimiku avatar Mar 08 '23 11:03 kekeimiku