From 84637e666f6846928c83cd44d70a0abb1805cdbc Mon Sep 17 00:00:00 2001 From: The8472 Date: Sat, 3 Oct 2020 17:31:06 +0200 Subject: [PATCH 1/2] vec::append: swap vecs instead of moving elements when the LHS is empty --- library/alloc/src/vec.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/library/alloc/src/vec.rs b/library/alloc/src/vec.rs index b20ccd388d1f1..ee1d515592504 100644 --- a/library/alloc/src/vec.rs +++ b/library/alloc/src/vec.rs @@ -1257,6 +1257,14 @@ impl Vec { #[inline] #[stable(feature = "append", since = "1.4.0")] pub fn append(&mut self, other: &mut Self) { + // Reuses other if doing so allows us to turn a certain reallocation within self + // into a potential, future reallocation in other. + // The capacity limit ensures that we are not stealing a large preallocation from `other` + // that is not commensurate with the avoided reallocation in self. + if self.len == 0 && self.capacity() < other.len && other.capacity() / 2 <= other.len { + mem::swap(self, other); + return; + } unsafe { self.append_elements(other.as_slice() as _); other.set_len(0); From 4cdbb8ca6a37ca7d98159bca44fa81a2bbc9de89 Mon Sep 17 00:00:00 2001 From: The8472 Date: Sun, 4 Oct 2020 19:37:44 +0200 Subject: [PATCH 2/2] reword guarantee section to leave wiggle room for non-(de)allocating shrinks --- library/alloc/src/vec.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/alloc/src/vec.rs b/library/alloc/src/vec.rs index ee1d515592504..85ca8ea4738e7 100644 --- a/library/alloc/src/vec.rs +++ b/library/alloc/src/vec.rs @@ -243,8 +243,8 @@ use crate::raw_vec::RawVec; /// * It would penalize the general case, incurring an additional branch /// on every access. /// -/// `Vec` will never automatically shrink itself, even if completely empty. This -/// ensures no unnecessary allocations or deallocations occur. Emptying a `Vec` +/// `Vec` will not automatically shrink itself, even if completely empty, when doing so +/// would cause unnecessary allocations or deallocations to occur. Emptying a `Vec` /// and then filling it back up to the same [`len`] should incur no calls to /// the allocator. If you wish to free up unused memory, use /// [`shrink_to_fit`].