Skip to content

Commit c5af975

Browse files
committed
reuse RHS allocation in vec.extend() when the LHS is empty
1 parent 8876ffc commit c5af975

File tree

1 file changed

+24
-14
lines changed

1 file changed

+24
-14
lines changed

library/alloc/src/vec.rs

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2199,19 +2199,11 @@ impl<T> SpecFromIter<T, IntoIter<T>> for Vec<T> {
21992199
// But it is a conservative choice.
22002200
let has_advanced = iterator.buf.as_ptr() as *const _ != iterator.ptr;
22012201
if !has_advanced || iterator.len() >= iterator.cap / 2 {
2202-
unsafe {
2203-
let it = ManuallyDrop::new(iterator);
2204-
if has_advanced {
2205-
ptr::copy(it.ptr, it.buf.as_ptr(), it.len());
2206-
}
2207-
return Vec::from_raw_parts(it.buf.as_ptr(), it.len(), it.cap);
2208-
}
2202+
return iterator.into_vec();
22092203
}
22102204

22112205
let mut vec = Vec::new();
2212-
// must delegate to spec_extend() since extend() itself delegates
2213-
// to spec_from for empty Vecs
2214-
vec.spec_extend(iterator);
2206+
iterator.move_to(&mut vec);
22152207
vec
22162208
}
22172209
}
@@ -2391,11 +2383,12 @@ where
23912383
}
23922384

23932385
impl<T> SpecExtend<T, IntoIter<T>> for Vec<T> {
2394-
fn spec_extend(&mut self, mut iterator: IntoIter<T>) {
2395-
unsafe {
2396-
self.append_elements(iterator.as_slice() as _);
2386+
fn spec_extend(&mut self, iterator: IntoIter<T>) {
2387+
if mem::size_of::<T>() > 0 && self.len == 0 && self.capacity() < iterator.len() {
2388+
*self = iterator.into_vec();
2389+
return;
23972390
}
2398-
iterator.ptr = iterator.end;
2391+
iterator.move_to(self);
23992392
}
24002393
}
24012394

@@ -2928,6 +2921,23 @@ impl<T> IntoIter<T> {
29282921
self.ptr = self.buf.as_ptr();
29292922
self.end = self.buf.as_ptr();
29302923
}
2924+
2925+
/// Shifts the remaining elements to the front and then converts the whole allocation to a Vec
2926+
fn into_vec(self) -> Vec<T> {
2927+
if self.ptr != self.buf.as_ptr() as *const _ {
2928+
unsafe { ptr::copy(self.ptr, self.buf.as_ptr(), self.len()) }
2929+
}
2930+
2931+
let iter = ManuallyDrop::new(self);
2932+
unsafe { Vec::from_raw_parts(iter.buf.as_ptr(), iter.len(), iter.cap) }
2933+
}
2934+
2935+
fn move_to(mut self, dest: &mut Vec<T>) {
2936+
unsafe {
2937+
dest.append_elements(self.as_slice() as _);
2938+
}
2939+
self.ptr = self.end;
2940+
}
29312941
}
29322942

29332943
#[stable(feature = "vec_intoiter_as_ref", since = "1.46.0")]

0 commit comments

Comments
 (0)