@@ -53,27 +53,36 @@ impl<'a, T, A: Allocator> Drain<'a, T, A> {
53
53
}
54
54
55
55
// Only returns pointers to the slices, as that's
56
- // all we need to drop them
57
- fn as_slices ( & self ) -> ( * mut [ T ] , * mut [ T ] ) {
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
58
unsafe {
59
59
let deque = self . deque . as_ref ( ) ;
60
- let wrapped_start = deque. wrap_idx ( self . idx ) ;
61
-
62
- if self . remaining <= deque. capacity ( ) - wrapped_start {
63
- // there's only one contigous slice
64
- (
65
- ptr:: slice_from_raw_parts_mut ( deque. ptr ( ) . add ( wrapped_start) , self . remaining ) ,
66
- & mut [ ] as * mut [ T ] ,
67
- )
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 )
68
75
} else {
69
- let head_len = deque. capacity ( ) - wrapped_start;
70
- // this will never overflow due to the if condition
71
76
let tail_len = self . remaining - head_len;
72
- (
73
- ptr:: slice_from_raw_parts_mut ( deque. ptr ( ) . add ( wrapped_start) , head_len) ,
74
- ptr:: slice_from_raw_parts_mut ( deque. ptr ( ) , tail_len) ,
75
- )
76
- }
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) )
77
86
}
78
87
}
79
88
}
@@ -103,8 +112,9 @@ impl<T, A: Allocator> Drop for Drain<'_, T, A> {
103
112
impl < ' r , ' a , T , A : Allocator > Drop for DropGuard < ' r , ' a , T , A > {
104
113
fn drop ( & mut self ) {
105
114
if self . 0 . remaining != 0 {
106
- let ( front, back) = self . 0 . as_slices ( ) ;
107
115
unsafe {
116
+ // SAFETY: We just checked that `self.remaining != 0`.
117
+ let ( front, back) = self . 0 . as_slices ( ) ;
108
118
ptr:: drop_in_place ( front) ;
109
119
ptr:: drop_in_place ( back) ;
110
120
}
@@ -133,7 +143,7 @@ impl<T, A: Allocator> Drop for Drain<'_, T, A> {
133
143
source_deque. len = 0 ;
134
144
}
135
145
( 0 , _) => {
136
- source_deque. head = source_deque. wrap_idx ( drain_len) ;
146
+ source_deque. head = source_deque. to_physical_idx ( drain_len) ;
137
147
source_deque. len = orig_len - drain_len;
138
148
}
139
149
( _, 0 ) => {
@@ -143,15 +153,15 @@ impl<T, A: Allocator> Drop for Drain<'_, T, A> {
143
153
if head_len <= tail_len {
144
154
source_deque. wrap_copy (
145
155
source_deque. head ,
146
- source_deque. wrap_idx ( drain_len) ,
156
+ source_deque. to_physical_idx ( drain_len) ,
147
157
head_len,
148
158
) ;
149
- source_deque. head = source_deque. wrap_idx ( drain_len) ;
159
+ source_deque. head = source_deque. to_physical_idx ( drain_len) ;
150
160
source_deque. len = orig_len - drain_len;
151
161
} else {
152
162
source_deque. wrap_copy (
153
- source_deque. wrap_idx ( head_len + drain_len) ,
154
- source_deque. wrap_idx ( head_len) ,
163
+ source_deque. to_physical_idx ( head_len + drain_len) ,
164
+ source_deque. to_physical_idx ( head_len) ,
155
165
tail_len,
156
166
) ;
157
167
source_deque. len = orig_len - drain_len;
@@ -162,14 +172,17 @@ impl<T, A: Allocator> Drop for Drain<'_, T, A> {
162
172
}
163
173
164
174
let guard = DropGuard ( self ) ;
165
- let ( front, back) = guard. 0 . as_slices ( ) ;
166
- unsafe {
167
- // since idx is a logical index, we don't need to worry about wrapping.
168
- guard. 0 . idx += front. len ( ) ;
169
- guard. 0 . remaining -= front. len ( ) ;
170
- ptr:: drop_in_place ( front) ;
171
- guard. 0 . remaining = 0 ;
172
- ptr:: drop_in_place ( back) ;
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
+ }
173
186
}
174
187
175
188
// Dropping `guard` handles moving the remaining elements into place.
@@ -185,7 +198,7 @@ impl<T, A: Allocator> Iterator for Drain<'_, T, A> {
185
198
if self . remaining == 0 {
186
199
return None ;
187
200
}
188
- let wrapped_idx = unsafe { self . deque . as_ref ( ) . wrap_idx ( self . idx ) } ;
201
+ let wrapped_idx = unsafe { self . deque . as_ref ( ) . to_physical_idx ( self . idx ) } ;
189
202
self . idx += 1 ;
190
203
self . remaining -= 1 ;
191
204
Some ( unsafe { self . deque . as_mut ( ) . buffer_read ( wrapped_idx) } )
@@ -206,7 +219,7 @@ impl<T, A: Allocator> DoubleEndedIterator for Drain<'_, T, A> {
206
219
return None ;
207
220
}
208
221
self . remaining -= 1 ;
209
- let wrapped_idx = unsafe { self . deque . as_ref ( ) . wrap_idx ( self . idx + self . remaining ) } ;
222
+ let wrapped_idx = unsafe { self . deque . as_ref ( ) . to_physical_idx ( self . idx + self . remaining ) } ;
210
223
Some ( unsafe { self . deque . as_mut ( ) . buffer_read ( wrapped_idx) } )
211
224
}
212
225
}
0 commit comments