Skip to content

Commit 032fa35

Browse files
committed
replace vec::Drain drop loops with drop_in_place
1 parent 544d124 commit 032fa35

File tree

1 file changed

+37
-14
lines changed

1 file changed

+37
-14
lines changed

library/alloc/src/vec/drain.rs

+37-14
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::alloc::{Allocator, Global};
22
use core::fmt;
33
use core::iter::{FusedIterator, TrustedLen};
4-
use core::mem::{self};
4+
use core::mem::{self, MaybeUninit};
55
use core::ptr::{self, NonNull};
66
use core::slice::{self};
77

@@ -102,16 +102,11 @@ impl<T, A: Allocator> DoubleEndedIterator for Drain<'_, T, A> {
102102
#[stable(feature = "drain", since = "1.6.0")]
103103
impl<T, A: Allocator> Drop for Drain<'_, T, A> {
104104
fn drop(&mut self) {
105-
/// Continues dropping the remaining elements in the `Drain`, then moves back the
106-
/// un-`Drain`ed elements to restore the original `Vec`.
105+
/// Moves back the un-`Drain`ed elements to restore the original `Vec`.
107106
struct DropGuard<'r, 'a, T, A: Allocator>(&'r mut Drain<'a, T, A>);
108107

109108
impl<'r, 'a, T, A: Allocator> Drop for DropGuard<'r, 'a, T, A> {
110109
fn drop(&mut self) {
111-
// Continue the same loop we have below. If the loop already finished, this does
112-
// nothing.
113-
self.0.for_each(drop);
114-
115110
if self.0.tail_len > 0 {
116111
unsafe {
117112
let source_vec = self.0.vec.as_mut();
@@ -129,15 +124,43 @@ impl<T, A: Allocator> Drop for Drain<'_, T, A> {
129124
}
130125
}
131126

132-
// exhaust self first
133-
while let Some(item) = self.next() {
134-
let guard = DropGuard(self);
135-
drop(item);
136-
mem::forget(guard);
127+
let iter = mem::replace(&mut self.iter, (&mut []).iter());
128+
let drop_len = iter.len();
129+
let drop_ptr = iter.as_slice().as_ptr();
130+
131+
// forget iter so there's no aliasing reference
132+
drop(iter);
133+
134+
let mut vec = self.vec;
135+
136+
if mem::size_of::<T>() == 0 {
137+
// ZSTs have no identity, so we don't need to move them around, we only need to drop the correct amount.
138+
// this can be achieved by manipulating the Vec length instead of moving values out from `iter`.
139+
unsafe {
140+
let vec = vec.as_mut();
141+
let old_len = vec.len();
142+
vec.set_len(old_len + drop_len + self.tail_len);
143+
vec.truncate(old_len + self.tail_len);
144+
}
145+
146+
return;
147+
}
148+
149+
// ensure elements are moved back into their appropriate places, even when drop_in_place panics
150+
let _guard = DropGuard(self);
151+
152+
if drop_len == 0 {
153+
return;
137154
}
138155

139-
// Drop a `DropGuard` to move back the non-drained tail of `self`.
140-
DropGuard(self);
156+
unsafe {
157+
let vec = vec.as_mut();
158+
let spare_capacity = vec.spare_capacity_mut();
159+
let drop_offset = drop_ptr.offset_from(spare_capacity.as_ptr() as *const _) as usize;
160+
let drop_range = drop_offset..(drop_offset + drop_len);
161+
let to_drop = &mut spare_capacity[drop_range];
162+
ptr::drop_in_place(MaybeUninit::slice_assume_init_mut(to_drop));
163+
}
141164
}
142165
}
143166

0 commit comments

Comments
 (0)