From 295768ae8fd07ec129142668bdd8030f9c3856ac Mon Sep 17 00:00:00 2001 From: Orson Peters Date: Mon, 9 Jul 2018 05:01:39 +0200 Subject: [PATCH 1/3] Performance improvement of Vec's swap_remove. --- src/liballoc/vec.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs index fbbaced540e70..36be21de33a6b 100644 --- a/src/liballoc/vec.rs +++ b/src/liballoc/vec.rs @@ -809,9 +809,13 @@ impl Vec { #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn swap_remove(&mut self, index: usize) -> T { - let length = self.len(); - self.swap(index, length - 1); - self.pop().unwrap() + unsafe { + // We replace self[index] with the last element. Note that this is + // safe even when index == self.len() - 1, as pop() only uses + // ptr::read and leaves the memory at self[index] untouched. + let hole: *mut T = &mut self[index]; + ptr::replace(hole, self.pop().unwrap()) + } } /// Inserts an element at position `index` within the vector, shifting all From 6faa295cecc7940526dc467e39ce20e652851cfb Mon Sep 17 00:00:00 2001 From: Orson Peters Date: Mon, 9 Jul 2018 06:13:58 +0200 Subject: [PATCH 2/3] Reimplemented Vec's swap_remove to not rely on pop. --- src/liballoc/vec.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs index 36be21de33a6b..98660fe415dc7 100644 --- a/src/liballoc/vec.rs +++ b/src/liballoc/vec.rs @@ -810,11 +810,13 @@ impl Vec { #[stable(feature = "rust1", since = "1.0.0")] pub fn swap_remove(&mut self, index: usize) -> T { unsafe { - // We replace self[index] with the last element. Note that this is - // safe even when index == self.len() - 1, as pop() only uses - // ptr::read and leaves the memory at self[index] untouched. + // We replace self[index] with the last element. Note that if the + // bounds check on hole succeeds there must be a last element (which + // can be self[index] itself). let hole: *mut T = &mut self[index]; - ptr::replace(hole, self.pop().unwrap()) + let last = ptr::read(self.get_unchecked(self.len - 1)); + self.len -= 1; + ptr::replace(hole, last) } } From e529dfd590e6c7e0c19bbf0f3c72e34f25c0cfb8 Mon Sep 17 00:00:00 2001 From: Orson Peters Date: Mon, 9 Jul 2018 06:31:24 +0200 Subject: [PATCH 3/3] Removed a single trailing space. Oops. --- src/liballoc/vec.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs index 98660fe415dc7..5efe1e23309a7 100644 --- a/src/liballoc/vec.rs +++ b/src/liballoc/vec.rs @@ -810,7 +810,7 @@ impl Vec { #[stable(feature = "rust1", since = "1.0.0")] pub fn swap_remove(&mut self, index: usize) -> T { unsafe { - // We replace self[index] with the last element. Note that if the + // We replace self[index] with the last element. Note that if the // bounds check on hole succeeds there must be a last element (which // can be self[index] itself). let hole: *mut T = &mut self[index];