I have some piece of code which needs to add part of a vector to another vector.
I use extend_from_slice for that, which works fine technically, see example code at the end.
The question is: Is the code performant?
To me it looks like internally this is resolved to an iterator which does a memcpy for each element.
I was hoping it would do a memcpy for all elements at once, so instead of
self.reserve(lower.saturating_add(1)); for each element
self.reserve(lower.saturating_add(10000));
Besides doing it in multiple steps this could also result in multiple re-allocations of the memory for the vector. To me it looks I better to a capacity extension before calling extend. I was hoping the calles subroute does this for me.
I believe the elements of the vector (or array) are always stored consecutively in heap(or stack), so it would be possible to copy in one step, or not? (Clone could be different)
Best,
Gunnar
// mod.rs: Rust code which does the work
impl<T, A: Allocator> Vec<T, A> {
// leaf method to which various SpecFrom/SpecExtend implementations delegate when
// they have no further optimizations to apply
#[cfg(not(no_global_oom_handling))]
fn extend_desugared<I: Iterator<Item = T>>(&mut self, mut iterator: I) {
// This is the case for a general iterator.
//
// This function should be the moral equivalent of:
//
// for item in iterator {
// self.push(item);
// }
while let Some(element) = iterator.next() {
let len = self.len();
if len == self.capacity() {
let (lower, _) = iterator.size_hint();
self.reserve(lower.saturating_add(1));
}
unsafe {
ptr::write(self.as_mut_ptr().add(len), element);
// Since next() executes user code which can panic we have to bump the length
// after each step.
// NB can't overflow since we would have had to alloc the address space
self.set_len(len + 1);
}
}
}
// Sample code
#[derive(Debug, Clone, Copy, PartialEq)]
struct Data {
id: usize,
x: u16,
y: u16,
color: (u8, u8, u8),
}
impl Data {
fn new(id: usize) -> Self {
Self {
id,
x: id as u16,
y: id as u16,
color: (0,0,0),
}
}
}
fn main() {
let size = 10_000;
let master: Vec<Data> = (0..size).into_iter().map(|it| Data::new(it)).collect::<Vec<_>>();
let master_check = master.clone();
let mut target: Vec<Data> = Vec::new();
let start = size / 2;
target.extend_from_slice(&master[start..]);
assert_eq!(master, master_check);
assert_eq!(target, master_check[start..]);
}