1- use core:: fmt;
21use core:: iter:: FusedIterator ;
32use 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} ;
66
77use crate :: alloc:: { Allocator , Global } ;
88
9- use super :: { count , wrap_index , VecDeque } ;
9+ use super :: VecDeque ;
1010
1111/// A draining iterator over the elements of a `VecDeque`.
1212///
@@ -20,38 +20,81 @@ pub struct Drain<
2020 T : ' a ,
2121 #[ unstable( feature = "allocator_api" , issue = "32838" ) ] A : Allocator = Global ,
2222> {
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
2825 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 > ,
3035}
3136
3237impl < ' a , T , A : Allocator > Drain < ' a , T , A > {
3338 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 ,
4042 ) -> 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+ }
4387 }
4488}
4589
4690#[ stable( feature = "collection_debug" , since = "1.17.0" ) ]
4791impl < T : fmt:: Debug , A : Allocator > fmt:: Debug for Drain < ' _ , T , A > {
4892 fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
4993 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 )
5598 . finish ( )
5699 }
57100}
@@ -68,57 +111,81 @@ impl<T, A: Allocator> Drop for Drain<'_, T, A> {
68111
69112 impl < ' r , ' a , T , A : Allocator > Drop for DropGuard < ' r , ' a , T , A > {
70113 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+ }
72122
73123 let source_deque = unsafe { self . 0 . deque . as_mut ( ) } ;
74124
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;
84130
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+ }
87136
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 ;
90139
91- match ( tail_len , head_len ) {
140+ match ( head_len , tail_len ) {
92141 ( 0 , 0 ) => {
93142 source_deque. head = 0 ;
94- source_deque. tail = 0 ;
143+ source_deque. len = 0 ;
95144 }
96145 ( 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;
98148 }
99149 ( _, 0 ) => {
100- source_deque. head = drain_tail ;
150+ source_deque. len = orig_len - drain_len ;
101151 }
102152 _ => 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;
106161 } 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;
109168 }
110169 } ,
111170 }
112171 }
113172 }
114173
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+ }
119186 }
120187
121- DropGuard ( self ) ;
188+ // Dropping `guard` handles moving the remaining elements into place.
122189 }
123190}
124191
@@ -128,20 +195,18 @@ impl<T, A: Allocator> Iterator for Drain<'_, T, A> {
128195
129196 #[ inline]
130197 fn next ( & mut self ) -> Option < T > {
131- if self . tail == self . head {
198+ if self . remaining == 0 {
132199 return None ;
133200 }
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) } )
140205 }
141206
142207 #[ inline]
143208 fn size_hint ( & self ) -> ( usize , Option < usize > ) {
144- let len = count ( self . tail , self . head , self . ring . len ( ) ) ;
209+ let len = self . remaining ;
145210 ( len, Some ( len) )
146211 }
147212}
@@ -150,14 +215,12 @@ impl<T, A: Allocator> Iterator for Drain<'_, T, A> {
150215impl < T , A : Allocator > DoubleEndedIterator for Drain < ' _ , T , A > {
151216 #[ inline]
152217 fn next_back ( & mut self ) -> Option < T > {
153- if self . tail == self . head {
218+ if self . remaining == 0 {
154219 return None ;
155220 }
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) } )
161224 }
162225}
163226
0 commit comments