From 18c5f4e7f27aa3180d2b21f8383f3b0ba4f2bc73 Mon Sep 17 00:00:00 2001 From: Charles Gleason Date: Mon, 28 Oct 2019 17:52:50 -0400 Subject: [PATCH 1/4] Match docs for VecDeque truncate to Vec truncate --- src/liballoc/collections/vec_deque.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/liballoc/collections/vec_deque.rs b/src/liballoc/collections/vec_deque.rs index 8f3dfabd8886d..61a2f620d295c 100644 --- a/src/liballoc/collections/vec_deque.rs +++ b/src/liballoc/collections/vec_deque.rs @@ -835,7 +835,8 @@ impl VecDeque { } } - /// Shortens the `VecDeque`, dropping excess elements from the back. + /// Shortens the `VecDeque`, keeping the first `len` elements and dropping + /// the rest. /// /// If `len` is greater than the `VecDeque`'s current length, this has no /// effect. From aa893535c4232176c0c05e4e8fb8c85a2a855a1f Mon Sep 17 00:00:00 2001 From: Charles Gleason Date: Mon, 28 Oct 2019 17:53:03 -0400 Subject: [PATCH 2/4] Use ptr::drop_in_place in VecDeque truncate --- src/liballoc/collections/vec_deque.rs | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/src/liballoc/collections/vec_deque.rs b/src/liballoc/collections/vec_deque.rs index 61a2f620d295c..fffd3a9dedae9 100644 --- a/src/liballoc/collections/vec_deque.rs +++ b/src/liballoc/collections/vec_deque.rs @@ -856,8 +856,31 @@ impl VecDeque { /// ``` #[stable(feature = "deque_extras", since = "1.16.0")] pub fn truncate(&mut self, len: usize) { - for _ in len..self.len() { - self.pop_back(); + // Safe because: + // + // * Any slice passed to `drop_in_place` is valid; the second case has + // `len <= front.len()` and returning on `len > self.len()` ensures + // `begin <= back.len()` in the first case + // * The head of the VecDeque is moved before calling `drop_in_place`, + // so no value is dropped twice if `drop_in_place` panics + unsafe { + if len > self.len() { + return; + } + let num_dropped = self.len() - len; + let (front, back) = self.as_mut_slices(); + if len > front.len() { + let begin = len - front.len(); + let drop_back = back.get_unchecked_mut(begin..) as *mut _; + self.head = self.wrap_sub(self.head, num_dropped); + ptr::drop_in_place(drop_back); + } else { + let drop_back = back as *mut _; + let drop_front = front.get_unchecked_mut(len..) as *mut _; + self.head = self.wrap_sub(self.head, num_dropped); + ptr::drop_in_place(drop_front); + ptr::drop_in_place(drop_back); + } } } From 71191bc3e9c592e6f52a646414fd9e337e3f3407 Mon Sep 17 00:00:00 2001 From: Charles Gleason Date: Mon, 28 Oct 2019 18:50:07 -0400 Subject: [PATCH 3/4] Add test for VecDeque truncate --- src/liballoc/collections/vec_deque/tests.rs | 35 +++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/src/liballoc/collections/vec_deque/tests.rs b/src/liballoc/collections/vec_deque/tests.rs index d578ee0dac493..09009ff516ac8 100644 --- a/src/liballoc/collections/vec_deque/tests.rs +++ b/src/liballoc/collections/vec_deque/tests.rs @@ -384,6 +384,41 @@ fn test_clone_from() { } } +#[test] +fn test_vec_deque_truncate_drop() { + static mut DROPS: u32 = 0; + #[derive(Clone)] + struct Elem(i32); + impl Drop for Elem { + fn drop(&mut self) { + unsafe { + DROPS += 1; + } + } + } + + let v = vec![Elem(1), Elem(2), Elem(3), Elem(4), Elem(5)]; + for push_front in 0..=v.len() { + let v = v.clone(); + let mut tester = VecDeque::with_capacity(5); + for (index, elem) in v.into_iter().enumerate() { + if index < push_front { + tester.push_front(elem); + } else { + tester.push_back(elem); + } + } + assert_eq!(unsafe { DROPS }, 0); + tester.truncate(3); + assert_eq!(unsafe { DROPS }, 2); + tester.truncate(0); + assert_eq!(unsafe { DROPS }, 5); + unsafe { + DROPS = 0; + } + } +} + #[test] fn issue_53529() { use crate::boxed::Box; From 27e0ab578cc0fc4c72da54bbeb42c0c44d848207 Mon Sep 17 00:00:00 2001 From: Charles Gleason Date: Tue, 29 Oct 2019 10:45:54 -0400 Subject: [PATCH 4/4] Use truncate(0) in VecDeque clear --- src/liballoc/collections/vec_deque.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/liballoc/collections/vec_deque.rs b/src/liballoc/collections/vec_deque.rs index fffd3a9dedae9..7795083e0580c 100644 --- a/src/liballoc/collections/vec_deque.rs +++ b/src/liballoc/collections/vec_deque.rs @@ -1141,7 +1141,7 @@ impl VecDeque { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn clear(&mut self) { - self.drain(..); + self.truncate(0); } /// Returns `true` if the `VecDeque` contains an element equal to the