From a4e385a0d0c1966870a18db5e138a55b8ebc7b04 Mon Sep 17 00:00:00 2001 From: The8472 Date: Sun, 17 Nov 2019 14:50:48 +0100 Subject: [PATCH] use memmove instead of generic in-place iteration for IntoIter source this is the original SpecExtend<_, IntoIter> logic except generalizing the fast-path to include a memmove --- library/alloc/src/vec.rs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/library/alloc/src/vec.rs b/library/alloc/src/vec.rs index 29878851da5c..ce7ea2058b5b 100644 --- a/library/alloc/src/vec.rs +++ b/library/alloc/src/vec.rs @@ -2216,14 +2216,22 @@ impl SpecFrom> for Vec { // A common case is passing a vector into a function which immediately // re-collects into a vector. We can short circuit this if the IntoIter // has not been advanced at all. - if iterator.buf.as_ptr() as *const _ == iterator.ptr { + // We can also reuse the memory and move the data to the front if + // allocating a new vector and moving to it would result in the same capacity + let non_zero_offset = iterator.buf.as_ptr() as *const _ != iterator.ptr; + if !non_zero_offset || iterator.len() >= iterator.cap / 2 { unsafe { let it = ManuallyDrop::new(iterator); + if non_zero_offset { + ptr::copy(it.ptr, it.buf.as_ptr(), it.len()); + } return Vec::from_raw_parts(it.buf.as_ptr(), it.len(), it.cap); } } - from_into_iter_source(iterator) + let mut vec = Vec::new(); + vec.extend(iterator); + vec } }