replace vec::Drain drop loops with drop_in_place
This commit is contained in:
parent
18fa4342fc
commit
ce994027fe
1 changed files with 37 additions and 14 deletions
|
@ -1,7 +1,7 @@
|
||||||
use crate::alloc::{Allocator, Global};
|
use crate::alloc::{Allocator, Global};
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
use core::iter::{FusedIterator, TrustedLen};
|
use core::iter::{FusedIterator, TrustedLen};
|
||||||
use core::mem::{self};
|
use core::mem::{self, MaybeUninit};
|
||||||
use core::ptr::{self, NonNull};
|
use core::ptr::{self, NonNull};
|
||||||
use core::slice::{self};
|
use core::slice::{self};
|
||||||
|
|
||||||
|
@ -104,16 +104,11 @@ impl<T, A: Allocator> DoubleEndedIterator for Drain<'_, T, A> {
|
||||||
#[stable(feature = "drain", since = "1.6.0")]
|
#[stable(feature = "drain", since = "1.6.0")]
|
||||||
impl<T, A: Allocator> Drop for Drain<'_, T, A> {
|
impl<T, A: Allocator> Drop for Drain<'_, T, A> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
/// Continues dropping the remaining elements in the `Drain`, then moves back the
|
/// Moves back the un-`Drain`ed elements to restore the original `Vec`.
|
||||||
/// un-`Drain`ed elements to restore the original `Vec`.
|
|
||||||
struct DropGuard<'r, 'a, T, A: Allocator>(&'r mut Drain<'a, T, A>);
|
struct DropGuard<'r, 'a, T, A: Allocator>(&'r mut Drain<'a, T, A>);
|
||||||
|
|
||||||
impl<'r, 'a, T, A: Allocator> Drop for DropGuard<'r, 'a, T, A> {
|
impl<'r, 'a, T, A: Allocator> Drop for DropGuard<'r, 'a, T, A> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
// Continue the same loop we have below. If the loop already finished, this does
|
|
||||||
// nothing.
|
|
||||||
self.0.for_each(drop);
|
|
||||||
|
|
||||||
if self.0.tail_len > 0 {
|
if self.0.tail_len > 0 {
|
||||||
unsafe {
|
unsafe {
|
||||||
let source_vec = self.0.vec.as_mut();
|
let source_vec = self.0.vec.as_mut();
|
||||||
|
@ -131,15 +126,43 @@ impl<T, A: Allocator> Drop for Drain<'_, T, A> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// exhaust self first
|
let iter = mem::replace(&mut self.iter, (&mut []).iter());
|
||||||
while let Some(item) = self.next() {
|
let drop_len = iter.len();
|
||||||
let guard = DropGuard(self);
|
let drop_ptr = iter.as_slice().as_ptr();
|
||||||
drop(item);
|
|
||||||
mem::forget(guard);
|
// forget iter so there's no aliasing reference
|
||||||
|
drop(iter);
|
||||||
|
|
||||||
|
let mut vec = self.vec;
|
||||||
|
|
||||||
|
if mem::size_of::<T>() == 0 {
|
||||||
|
// ZSTs have no identity, so we don't need to move them around, we only need to drop the correct amount.
|
||||||
|
// this can be achieved by manipulating the Vec length instead of moving values out from `iter`.
|
||||||
|
unsafe {
|
||||||
|
let vec = vec.as_mut();
|
||||||
|
let old_len = vec.len();
|
||||||
|
vec.set_len(old_len + drop_len + self.tail_len);
|
||||||
|
vec.truncate(old_len + self.tail_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Drop a `DropGuard` to move back the non-drained tail of `self`.
|
// ensure elements are moved back into their appropriate places, even when drop_in_place panics
|
||||||
DropGuard(self);
|
let _guard = DropGuard(self);
|
||||||
|
|
||||||
|
if drop_len == 0 {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
let vec = vec.as_mut();
|
||||||
|
let spare_capacity = vec.spare_capacity_mut();
|
||||||
|
let drop_offset = drop_ptr.offset_from(spare_capacity.as_ptr() as *const _) as usize;
|
||||||
|
let drop_range = drop_offset..(drop_offset + drop_len);
|
||||||
|
let to_drop = &mut spare_capacity[drop_range];
|
||||||
|
ptr::drop_in_place(MaybeUninit::slice_assume_init_mut(to_drop));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue