1
- use core:: fmt;
2
1
use core:: iter:: FusedIterator ;
3
2
use core:: marker:: PhantomData ;
4
- use core:: mem:: { self , MaybeUninit } ;
5
- use core:: ptr:: { self , NonNull } ;
3
+ use core:: mem:: { self , SizedTypeProperties } ;
4
+ use core:: ptr:: NonNull ;
5
+ use core:: { fmt, ptr} ;
6
6
7
7
use crate :: alloc:: { Allocator , Global } ;
8
8
9
- use super :: { count , wrap_index , VecDeque } ;
9
+ use super :: VecDeque ;
10
10
11
11
/// A draining iterator over the elements of a `VecDeque`.
12
12
///
@@ -20,38 +20,81 @@ pub struct Drain<
20
20
T : ' a ,
21
21
#[ unstable( feature = "allocator_api" , issue = "32838" ) ] A : Allocator = Global ,
22
22
> {
23
- after_tail : usize ,
24
- after_head : usize ,
25
- ring : NonNull < [ T ] > ,
26
- tail : usize ,
27
- head : usize ,
23
+ // We can't just use a &mut VecDeque<T, A>, as that would make Drain invariant over T
24
+ // and we want it to be covariant instead
28
25
deque : NonNull < VecDeque < T , A > > ,
29
- _phantom : PhantomData < & ' a T > ,
26
+ // drain_start is stored in deque.len
27
+ drain_len : usize ,
28
+ // index into the logical array, not the physical one (always lies in [0..deque.len))
29
+ idx : usize ,
30
+ // number of elements after the drain range
31
+ tail_len : usize ,
32
+ remaining : usize ,
33
+ // Needed to make Drain covariant over T
34
+ _marker : PhantomData < & ' a T > ,
30
35
}
31
36
32
37
impl < ' a , T , A : Allocator > Drain < ' a , T , A > {
33
38
pub ( super ) unsafe fn new (
34
- after_tail : usize ,
35
- after_head : usize ,
36
- ring : & ' a [ MaybeUninit < T > ] ,
37
- tail : usize ,
38
- head : usize ,
39
- deque : NonNull < VecDeque < T , A > > ,
39
+ deque : & ' a mut VecDeque < T , A > ,
40
+ drain_start : usize ,
41
+ drain_len : usize ,
40
42
) -> Self {
41
- let ring = unsafe { NonNull :: new_unchecked ( ring as * const [ MaybeUninit < T > ] as * mut _ ) } ;
42
- Drain { after_tail, after_head, ring, tail, head, deque, _phantom : PhantomData }
43
+ let orig_len = mem:: replace ( & mut deque. len , drain_start) ;
44
+ let tail_len = orig_len - drain_start - drain_len;
45
+ Drain {
46
+ deque : NonNull :: from ( deque) ,
47
+ drain_len,
48
+ idx : drain_start,
49
+ tail_len,
50
+ remaining : drain_len,
51
+ _marker : PhantomData ,
52
+ }
53
+ }
54
+
55
+ // Only returns pointers to the slices, as that's
56
+ // all we need to drop them. May only be called if `self.remaining != 0`.
57
+ unsafe fn as_slices ( & self ) -> ( * mut [ T ] , * mut [ T ] ) {
58
+ unsafe {
59
+ let deque = self . deque . as_ref ( ) ;
60
+ // FIXME: This is doing almost exactly the same thing as the else branch in `VecDeque::slice_ranges`.
61
+ // Unfortunately, we can't just call `slice_ranges` here, as the deque's `len` is currently
62
+ // just `drain_start`, so the range check would (almost) always panic. Between temporarily
63
+ // adjusting the deques `len` to call `slice_ranges`, and just copy pasting the `slice_ranges`
64
+ // implementation, this seemed like the less hacky solution, though it might be good to
65
+ // find a better one in the future.
66
+
67
+ // because `self.remaining != 0`, we know that `self.idx < deque.original_len`, so it's a valid
68
+ // logical index.
69
+ let wrapped_start = deque. to_physical_idx ( self . idx ) ;
70
+
71
+ let head_len = deque. capacity ( ) - wrapped_start;
72
+
73
+ let ( a_range, b_range) = if head_len >= self . remaining {
74
+ ( wrapped_start..wrapped_start + self . remaining , 0 ..0 )
75
+ } else {
76
+ let tail_len = self . remaining - head_len;
77
+ ( wrapped_start..deque. capacity ( ) , 0 ..tail_len)
78
+ } ;
79
+
80
+ // SAFETY: the range `self.idx..self.idx+self.remaining` lies strictly inside
81
+ // the range `0..deque.original_len`. because of this, and because of the fact
82
+ // that we acquire `a_range` and `b_range` exactly like `slice_ranges` would,
83
+ // it's guaranteed that `a_range` and `b_range` represent valid ranges into
84
+ // the deques buffer.
85
+ ( deque. buffer_range ( a_range) , deque. buffer_range ( b_range) )
86
+ }
43
87
}
44
88
}
45
89
46
90
#[ stable( feature = "collection_debug" , since = "1.17.0" ) ]
47
91
impl < T : fmt:: Debug , A : Allocator > fmt:: Debug for Drain < ' _ , T , A > {
48
92
fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
49
93
f. debug_tuple ( "Drain" )
50
- . field ( & self . after_tail )
51
- . field ( & self . after_head )
52
- . field ( & self . ring )
53
- . field ( & self . tail )
54
- . field ( & self . head )
94
+ . field ( & self . drain_len )
95
+ . field ( & self . idx )
96
+ . field ( & self . tail_len )
97
+ . field ( & self . remaining )
55
98
. finish ( )
56
99
}
57
100
}
@@ -68,57 +111,81 @@ impl<T, A: Allocator> Drop for Drain<'_, T, A> {
68
111
69
112
impl < ' r , ' a , T , A : Allocator > Drop for DropGuard < ' r , ' a , T , A > {
70
113
fn drop ( & mut self ) {
71
- self . 0 . for_each ( drop) ;
114
+ if self . 0 . remaining != 0 {
115
+ unsafe {
116
+ // SAFETY: We just checked that `self.remaining != 0`.
117
+ let ( front, back) = self . 0 . as_slices ( ) ;
118
+ ptr:: drop_in_place ( front) ;
119
+ ptr:: drop_in_place ( back) ;
120
+ }
121
+ }
72
122
73
123
let source_deque = unsafe { self . 0 . deque . as_mut ( ) } ;
74
124
75
- // T = source_deque_tail; H = source_deque_head; t = drain_tail; h = drain_head
76
- //
77
- // T t h H
78
- // [. . . o o x x o o . . .]
79
- //
80
- let orig_tail = source_deque. tail ;
81
- let drain_tail = source_deque. head ;
82
- let drain_head = self . 0 . after_tail ;
83
- let orig_head = self . 0 . after_head ;
125
+ let drain_start = source_deque. len ( ) ;
126
+ let drain_len = self . 0 . drain_len ;
127
+ let drain_end = drain_start + drain_len;
128
+
129
+ let orig_len = self . 0 . tail_len + drain_end;
84
130
85
- let tail_len = count ( orig_tail, drain_tail, source_deque. cap ( ) ) ;
86
- let head_len = count ( drain_head, orig_head, source_deque. cap ( ) ) ;
131
+ if T :: IS_ZST {
132
+ // no need to copy around any memory if T is a ZST
133
+ source_deque. len = orig_len - drain_len;
134
+ return ;
135
+ }
87
136
88
- // Restore the original head value
89
- source_deque . head = orig_head ;
137
+ let head_len = drain_start ;
138
+ let tail_len = self . 0 . tail_len ;
90
139
91
- match ( tail_len , head_len ) {
140
+ match ( head_len , tail_len ) {
92
141
( 0 , 0 ) => {
93
142
source_deque. head = 0 ;
94
- source_deque. tail = 0 ;
143
+ source_deque. len = 0 ;
95
144
}
96
145
( 0 , _) => {
97
- source_deque. tail = drain_head;
146
+ source_deque. head = source_deque. to_physical_idx ( drain_len) ;
147
+ source_deque. len = orig_len - drain_len;
98
148
}
99
149
( _, 0 ) => {
100
- source_deque. head = drain_tail ;
150
+ source_deque. len = orig_len - drain_len ;
101
151
}
102
152
_ => unsafe {
103
- if tail_len <= head_len {
104
- source_deque. tail = source_deque. wrap_sub ( drain_head, tail_len) ;
105
- source_deque. wrap_copy ( source_deque. tail , orig_tail, tail_len) ;
153
+ if head_len <= tail_len {
154
+ source_deque. wrap_copy (
155
+ source_deque. head ,
156
+ source_deque. to_physical_idx ( drain_len) ,
157
+ head_len,
158
+ ) ;
159
+ source_deque. head = source_deque. to_physical_idx ( drain_len) ;
160
+ source_deque. len = orig_len - drain_len;
106
161
} else {
107
- source_deque. head = source_deque. wrap_add ( drain_tail, head_len) ;
108
- source_deque. wrap_copy ( drain_tail, drain_head, head_len) ;
162
+ source_deque. wrap_copy (
163
+ source_deque. to_physical_idx ( head_len + drain_len) ,
164
+ source_deque. to_physical_idx ( head_len) ,
165
+ tail_len,
166
+ ) ;
167
+ source_deque. len = orig_len - drain_len;
109
168
}
110
169
} ,
111
170
}
112
171
}
113
172
}
114
173
115
- while let Some ( item) = self . next ( ) {
116
- let guard = DropGuard ( self ) ;
117
- drop ( item) ;
118
- mem:: forget ( guard) ;
174
+ let guard = DropGuard ( self ) ;
175
+ if guard. 0 . remaining != 0 {
176
+ unsafe {
177
+ // SAFETY: We just checked that `self.remaining != 0`.
178
+ let ( front, back) = guard. 0 . as_slices ( ) ;
179
+ // since idx is a logical index, we don't need to worry about wrapping.
180
+ guard. 0 . idx += front. len ( ) ;
181
+ guard. 0 . remaining -= front. len ( ) ;
182
+ ptr:: drop_in_place ( front) ;
183
+ guard. 0 . remaining = 0 ;
184
+ ptr:: drop_in_place ( back) ;
185
+ }
119
186
}
120
187
121
- DropGuard ( self ) ;
188
+ // Dropping `guard` handles moving the remaining elements into place.
122
189
}
123
190
}
124
191
@@ -128,20 +195,18 @@ impl<T, A: Allocator> Iterator for Drain<'_, T, A> {
128
195
129
196
#[ inline]
130
197
fn next ( & mut self ) -> Option < T > {
131
- if self . tail == self . head {
198
+ if self . remaining == 0 {
132
199
return None ;
133
200
}
134
- let tail = self . tail ;
135
- self . tail = wrap_index ( self . tail . wrapping_add ( 1 ) , self . ring . len ( ) ) ;
136
- // Safety:
137
- // - `self.tail` in a ring buffer is always a valid index.
138
- // - `self.head` and `self.tail` equality is checked above.
139
- unsafe { Some ( ptr:: read ( self . ring . as_ptr ( ) . get_unchecked_mut ( tail) ) ) }
201
+ let wrapped_idx = unsafe { self . deque . as_ref ( ) . to_physical_idx ( self . idx ) } ;
202
+ self . idx += 1 ;
203
+ self . remaining -= 1 ;
204
+ Some ( unsafe { self . deque . as_mut ( ) . buffer_read ( wrapped_idx) } )
140
205
}
141
206
142
207
#[ inline]
143
208
fn size_hint ( & self ) -> ( usize , Option < usize > ) {
144
- let len = count ( self . tail , self . head , self . ring . len ( ) ) ;
209
+ let len = self . remaining ;
145
210
( len, Some ( len) )
146
211
}
147
212
}
@@ -150,14 +215,12 @@ impl<T, A: Allocator> Iterator for Drain<'_, T, A> {
150
215
impl < T , A : Allocator > DoubleEndedIterator for Drain < ' _ , T , A > {
151
216
#[ inline]
152
217
fn next_back ( & mut self ) -> Option < T > {
153
- if self . tail == self . head {
218
+ if self . remaining == 0 {
154
219
return None ;
155
220
}
156
- self . head = wrap_index ( self . head . wrapping_sub ( 1 ) , self . ring . len ( ) ) ;
157
- // Safety:
158
- // - `self.head` in a ring buffer is always a valid index.
159
- // - `self.head` and `self.tail` equality is checked above.
160
- unsafe { Some ( ptr:: read ( self . ring . as_ptr ( ) . get_unchecked_mut ( self . head ) ) ) }
221
+ self . remaining -= 1 ;
222
+ let wrapped_idx = unsafe { self . deque . as_ref ( ) . to_physical_idx ( self . idx + self . remaining ) } ;
223
+ Some ( unsafe { self . deque . as_mut ( ) . buffer_read ( wrapped_idx) } )
161
224
}
162
225
}
163
226
0 commit comments