When combining Vec
s, I find myself flipping between Vec::append
and Extend::extend
without any clear motivated preference for one or the other.
If we look at Vec
's implementation of Extend
, we see:
fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
<Self as SpecExtend<T, I::IntoIter>>::spec_extend(self, iter.into_iter())
}
where this leads is a bit tricky to follow, but it's somewhere in this file in std
. Either way, because this operates over an Iterator
, is it adding the new elements one-by-one, memory layout be damned?
append
on the other hand is straight-forward:
pub fn append(&mut self, other: &mut Self) {
unsafe {
self.append_elements(other.as_slice() as _);
other.set_len(0);
}
}
/// Appends elements to `Self` from other buffer.
unsafe fn append_elements(&mut self, other: *const [T]) {
let count = unsafe { (*other).len() };
self.reserve(count);
let len = self.len();
unsafe { ptr::copy_nonoverlapping(other as *const T, self.as_mut_ptr().add(len), count) };
self.len += count;
}
This looks to me like it's physically moving the memory from the other
to the self
. And if the self
had been preallocated with extra room via with_capacity
, then this would be more efficient, no?
Thanks for any wisdom you can offer.