diff options
| author | The8472 <git@infinite-source.de> | 2019-11-17 14:50:48 +0100 |
|---|---|---|
| committer | The8472 <git@infinite-source.de> | 2020-09-03 20:59:11 +0200 |
| commit | a4e385a0d0c1966870a18db5e138a55b8ebc7b04 (patch) | |
| tree | 20159d1fc00d1a15d4c77becbba0639e25d638b6 | |
| parent | 631543dcb4e79d3c134a7dfc8e87b62287e96796 (diff) | |
| download | rust-a4e385a0d0c1966870a18db5e138a55b8ebc7b04.tar.gz rust-a4e385a0d0c1966870a18db5e138a55b8ebc7b04.zip | |
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
| -rw-r--r-- | library/alloc/src/vec.rs | 12 |
1 files changed, 10 insertions, 2 deletions
diff --git a/library/alloc/src/vec.rs b/library/alloc/src/vec.rs index 29878851da5..ce7ea2058b5 100644 --- a/library/alloc/src/vec.rs +++ b/library/alloc/src/vec.rs @@ -2216,14 +2216,22 @@ impl<T> SpecFrom<T, IntoIter<T>> for Vec<T> { // 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 } } |
