about summary refs log tree commit diff
path: root/src/liballoc/collections
diff options
context:
space:
mode:
authorCharles Gleason <charles_gleason@alumni.brown.edu>2019-10-28 17:53:03 -0400
committerCharles Gleason <charles_gleason@alumni.brown.edu>2019-10-29 10:01:42 -0400
commitaa893535c4232176c0c05e4e8fb8c85a2a855a1f (patch)
tree6f848af8f133a1758b4e28710ac54ea8ff6dd587 /src/liballoc/collections
parent18c5f4e7f27aa3180d2b21f8383f3b0ba4f2bc73 (diff)
downloadrust-aa893535c4232176c0c05e4e8fb8c85a2a855a1f.tar.gz
rust-aa893535c4232176c0c05e4e8fb8c85a2a855a1f.zip
Use ptr::drop_in_place in VecDeque truncate
Diffstat (limited to 'src/liballoc/collections')
-rw-r--r--src/liballoc/collections/vec_deque.rs27
1 files changed, 25 insertions, 2 deletions
diff --git a/src/liballoc/collections/vec_deque.rs b/src/liballoc/collections/vec_deque.rs
index 61a2f620d29..fffd3a9deda 100644
--- a/src/liballoc/collections/vec_deque.rs
+++ b/src/liballoc/collections/vec_deque.rs
@@ -856,8 +856,31 @@ impl<T> VecDeque<T> {
     /// ```
     #[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);
+            }
         }
     }