11use crate :: array;
22use crate :: iter:: { FusedIterator , Iterator } ;
3- use crate :: mem;
4- use crate :: mem:: MaybeUninit ;
53use crate :: ops:: { ControlFlow , NeverShortCircuit , Try } ;
6- use crate :: ptr;
74
85/// An iterator over `N` elements of the iterator at a time.
96///
@@ -70,37 +67,18 @@ where
7067 F : FnMut ( B , Self :: Item ) -> R ,
7168 R : Try < Output = B > ,
7269 {
73- let mut array = MaybeUninit :: uninit_array ( ) ;
74- // SAFETY: `array` will still be valid if `guard` is dropped.
75- let mut guard = unsafe { FrontGuard :: new ( & mut array) } ;
76-
77- let result = self . iter . try_fold ( init, |mut acc, item| {
78- // SAFETY: `init` starts at 0, increases by one each iteration and
79- // is reset to 0 once it reaches N.
80- unsafe { array. get_unchecked_mut ( guard. init ) } . write ( item) ;
81- guard. init += 1 ;
82- if guard. init == N {
83- guard. init = 0 ;
84- let array = mem:: replace ( & mut array, MaybeUninit :: uninit_array ( ) ) ;
85- // SAFETY: the condition above asserts that all elements are
86- // initialized.
87- let item = unsafe { MaybeUninit :: array_assume_init ( array) } ;
88- acc = f ( acc, item) ?;
89- }
90- R :: from_output ( acc)
91- } ) ;
92- match result. branch ( ) {
93- ControlFlow :: Continue ( o) => {
94- if guard. init > 0 {
95- let init = guard. init ;
96- mem:: forget ( guard) ;
97- // SAFETY: `array` was initialized with `init` elements.
98- self . remainder =
99- Some ( unsafe { array:: IntoIter :: new_unchecked ( array, 0 ..init) } ) ;
70+ let mut acc = init;
71+ loop {
72+ match self . iter . next_chunk ( ) {
73+ Ok ( chunk) => acc = f ( acc, chunk) ?,
74+ Err ( remainder) => {
75+ // Make sure to not override `self.remainder` with an empty array
76+ // when `next` is called after `ArrayChunks` exhaustion.
77+ self . remainder . get_or_insert ( remainder) ;
78+
79+ break try { acc } ;
10080 }
101- R :: from_output ( o)
10281 }
103- ControlFlow :: Break ( r) => R :: from_residual ( r) ,
10482 }
10583 }
10684
@@ -113,33 +91,6 @@ where
11391 }
11492}
11593
116- /// A guard for an array where elements are filled from the left.
117- struct FrontGuard < T , const N : usize > {
118- /// A pointer to the array that is being filled. We need to use a raw
119- /// pointer here because of the lifetime issues in the fold implementations.
120- ptr : * mut T ,
121- /// The number of *initialized* elements.
122- init : usize ,
123- }
124-
125- impl < T , const N : usize > FrontGuard < T , N > {
126- unsafe fn new ( array : & mut [ MaybeUninit < T > ; N ] ) -> Self {
127- Self { ptr : MaybeUninit :: slice_as_mut_ptr ( array) , init : 0 }
128- }
129- }
130-
131- impl < T , const N : usize > Drop for FrontGuard < T , N > {
132- fn drop ( & mut self ) {
133- debug_assert ! ( self . init <= N ) ;
134- // SAFETY: This raw slice will only contain the initialized objects
135- // within the buffer.
136- unsafe {
137- let slice = ptr:: slice_from_raw_parts_mut ( self . ptr , self . init ) ;
138- ptr:: drop_in_place ( slice) ;
139- }
140- }
141- }
142-
14394#[ unstable( feature = "iter_array_chunks" , reason = "recently added" , issue = "none" ) ]
14495impl < I , const N : usize > DoubleEndedIterator for ArrayChunks < I , N >
14596where
@@ -157,29 +108,20 @@ where
157108 R : Try < Output = B > ,
158109 {
159110 // We are iterating from the back we need to first handle the remainder.
160- if self . next_back_remainder ( ) . is_none ( ) {
161- return R :: from_output ( init) ;
162- }
111+ self . next_back_remainder ( ) ;
163112
164- let mut array = MaybeUninit :: uninit_array ( ) ;
165- // SAFETY: `array` will still be valid if `guard` is dropped.
166- let mut guard = unsafe { BackGuard :: new ( & mut array) } ;
113+ let mut acc = init;
114+ let mut iter = self . iter . by_ref ( ) . rev ( ) ;
167115
168- self . iter . try_rfold ( init, |mut acc, item| {
169- guard. uninit -= 1 ;
170- // SAFETY: `uninit` starts at N, decreases by one each iteration and
171- // is reset to N once it reaches 0.
172- unsafe { array. get_unchecked_mut ( guard. uninit ) } . write ( item) ;
173- if guard. uninit == 0 {
174- guard. uninit = N ;
175- let array = mem:: replace ( & mut array, MaybeUninit :: uninit_array ( ) ) ;
176- // SAFETY: the condition above asserts that all elements are
177- // initialized.
178- let item = unsafe { MaybeUninit :: array_assume_init ( array) } ;
179- acc = f ( acc, item) ?;
180- }
181- R :: from_output ( acc)
182- } )
116+ // NB remainder is handled by `next_back_remainder`, so
117+ // `next_chunk` can't return `Err` with non-empty remainder
118+ // (assuming correct `I as ExactSizeIterator` impl).
119+ while let Ok ( mut chunk) = iter. next_chunk ( ) {
120+ chunk. reverse ( ) ;
121+ acc = f ( acc, chunk) ?
122+ }
123+
124+ try { acc }
183125 }
184126
185127 fn rfold < B , F > ( mut self , init : B , mut f : F ) -> B
@@ -195,63 +137,26 @@ impl<I, const N: usize> ArrayChunks<I, N>
195137where
196138 I : DoubleEndedIterator + ExactSizeIterator ,
197139{
198- #[ inline]
199- fn next_back_remainder ( & mut self ) -> Option < ( ) > {
140+ /// Updates `self.remainder` such that `self.iter.len` is divisible by `N`.
141+ fn next_back_remainder ( & mut self ) {
142+ // Make sure to not override `self.remainder` with an empty array
143+ // when `next_back` is called after `ArrayChunks` exhaustion.
144+ if self . remainder . is_some ( ) {
145+ return ;
146+ }
147+
200148 // We use the `ExactSizeIterator` implementation of the underlying
201149 // iterator to know how many remaining elements there are.
202150 let rem = self . iter . len ( ) % N ;
203- if rem == 0 {
204- return Some ( ( ) ) ;
205- }
206-
207- let mut array = MaybeUninit :: uninit_array ( ) ;
208151
209- // SAFETY: The array will still be valid if `guard` is dropped and
210- // it is forgotten otherwise.
211- let mut guard = unsafe { FrontGuard :: new ( & mut array) } ;
152+ // Take the last `rem` elements out of `self.iter`.
153+ let mut remainder =
154+ // SAFETY: `unwrap_err` always succeeds because x % N < N for all x.
155+ unsafe { self . iter . by_ref ( ) . rev ( ) . take ( rem) . next_chunk ( ) . unwrap_err_unchecked ( ) } ;
212156
213- // SAFETY: `rem` is in the range 1..N based on how it is calculated.
214- for slot in unsafe { array. get_unchecked_mut ( ..rem) } . iter_mut ( ) {
215- slot. write ( self . iter . next_back ( ) ?) ;
216- guard. init += 1 ;
217- }
218-
219- let init = guard. init ;
220- mem:: forget ( guard) ;
221- // SAFETY: `array` was initialized with exactly `init` elements.
222- self . remainder = unsafe {
223- array. get_unchecked_mut ( ..init) . reverse ( ) ;
224- Some ( array:: IntoIter :: new_unchecked ( array, 0 ..init) )
225- } ;
226- Some ( ( ) )
227- }
228- }
229-
230- /// A guard for an array where elements are filled from the right.
231- struct BackGuard < T , const N : usize > {
232- /// A pointer to the array that is being filled. We need to use a raw
233- /// pointer here because of the lifetime issues in the rfold implementations.
234- ptr : * mut T ,
235- /// The number of *uninitialized* elements.
236- uninit : usize ,
237- }
238-
239- impl < T , const N : usize > BackGuard < T , N > {
240- unsafe fn new ( array : & mut [ MaybeUninit < T > ; N ] ) -> Self {
241- Self { ptr : MaybeUninit :: slice_as_mut_ptr ( array) , uninit : N }
242- }
243- }
244-
245- impl < T , const N : usize > Drop for BackGuard < T , N > {
246- fn drop ( & mut self ) {
247- debug_assert ! ( self . uninit <= N ) ;
248- // SAFETY: This raw slice will only contain the initialized objects
249- // within the buffer.
250- unsafe {
251- let ptr = self . ptr . offset ( self . uninit as isize ) ;
252- let slice = ptr:: slice_from_raw_parts_mut ( ptr, N - self . uninit ) ;
253- ptr:: drop_in_place ( slice) ;
254- }
157+ // We used `.rev()` above, so we need to re-reverse the reminder
158+ remainder. as_mut_slice ( ) . reverse ( ) ;
159+ self . remainder = Some ( remainder) ;
255160 }
256161}
257162
0 commit comments