Skip to content

Commit aa89353

Browse files
committed
Use ptr::drop_in_place in VecDeque truncate
1 parent 18c5f4e commit aa89353

File tree

1 file changed

+25
-2
lines changed

1 file changed

+25
-2
lines changed

src/liballoc/collections/vec_deque.rs

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -856,8 +856,31 @@ impl<T> VecDeque<T> {
856856
/// ```
857857
#[stable(feature = "deque_extras", since = "1.16.0")]
858858
pub fn truncate(&mut self, len: usize) {
859-
for _ in len..self.len() {
860-
self.pop_back();
859+
// Safe because:
860+
//
861+
// * Any slice passed to `drop_in_place` is valid; the second case has
862+
// `len <= front.len()` and returning on `len > self.len()` ensures
863+
// `begin <= back.len()` in the first case
864+
// * The head of the VecDeque is moved before calling `drop_in_place`,
865+
// so no value is dropped twice if `drop_in_place` panics
866+
unsafe {
867+
if len > self.len() {
868+
return;
869+
}
870+
let num_dropped = self.len() - len;
871+
let (front, back) = self.as_mut_slices();
872+
if len > front.len() {
873+
let begin = len - front.len();
874+
let drop_back = back.get_unchecked_mut(begin..) as *mut _;
875+
self.head = self.wrap_sub(self.head, num_dropped);
876+
ptr::drop_in_place(drop_back);
877+
} else {
878+
let drop_back = back as *mut _;
879+
let drop_front = front.get_unchecked_mut(len..) as *mut _;
880+
self.head = self.wrap_sub(self.head, num_dropped);
881+
ptr::drop_in_place(drop_front);
882+
ptr::drop_in_place(drop_back);
883+
}
861884
}
862885
}
863886

0 commit comments

Comments
 (0)