1
1
use crate :: alloc:: { Allocator , Global } ;
2
2
use core:: fmt;
3
3
use core:: iter:: { FusedIterator , TrustedLen } ;
4
- use core:: mem:: { self } ;
4
+ use core:: mem:: { self , MaybeUninit } ;
5
5
use core:: ptr:: { self , NonNull } ;
6
6
use core:: slice:: { self } ;
7
7
@@ -102,16 +102,11 @@ impl<T, A: Allocator> DoubleEndedIterator for Drain<'_, T, A> {
102
102
#[ stable( feature = "drain" , since = "1.6.0" ) ]
103
103
impl < T , A : Allocator > Drop for Drain < ' _ , T , A > {
104
104
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`.
107
106
struct DropGuard < ' r , ' a , T , A : Allocator > ( & ' r mut Drain < ' a , T , A > ) ;
108
107
109
108
impl < ' r , ' a , T , A : Allocator > Drop for DropGuard < ' r , ' a , T , A > {
110
109
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
-
115
110
if self . 0 . tail_len > 0 {
116
111
unsafe {
117
112
let source_vec = self . 0 . vec . as_mut ( ) ;
@@ -129,15 +124,43 @@ impl<T, A: Allocator> Drop for Drain<'_, T, A> {
129
124
}
130
125
}
131
126
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 ;
137
154
}
138
155
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
+ }
141
164
}
142
165
}
143
166
0 commit comments