1
1
use crate :: array;
2
2
use crate :: iter:: { FusedIterator , Iterator } ;
3
- use crate :: mem;
4
- use crate :: mem:: MaybeUninit ;
5
3
use crate :: ops:: { ControlFlow , NeverShortCircuit , Try } ;
6
- use crate :: ptr;
7
4
8
5
/// An iterator over `N` elements of the iterator at a time.
9
6
///
@@ -70,37 +67,18 @@ where
70
67
F : FnMut ( B , Self :: Item ) -> R ,
71
68
R : Try < Output = B > ,
72
69
{
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 } ;
100
80
}
101
- R :: from_output ( o)
102
81
}
103
- ControlFlow :: Break ( r) => R :: from_residual ( r) ,
104
82
}
105
83
}
106
84
@@ -113,33 +91,6 @@ where
113
91
}
114
92
}
115
93
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
-
143
94
#[ unstable( feature = "iter_array_chunks" , reason = "recently added" , issue = "none" ) ]
144
95
impl < I , const N : usize > DoubleEndedIterator for ArrayChunks < I , N >
145
96
where
@@ -157,29 +108,20 @@ where
157
108
R : Try < Output = B > ,
158
109
{
159
110
// 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 ( ) ;
163
112
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 ( ) ;
167
115
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 }
183
125
}
184
126
185
127
fn rfold < B , F > ( mut self , init : B , mut f : F ) -> B
@@ -195,63 +137,26 @@ impl<I, const N: usize> ArrayChunks<I, N>
195
137
where
196
138
I : DoubleEndedIterator + ExactSizeIterator ,
197
139
{
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
+
200
148
// We use the `ExactSizeIterator` implementation of the underlying
201
149
// iterator to know how many remaining elements there are.
202
150
let rem = self . iter . len ( ) % N ;
203
- if rem == 0 {
204
- return Some ( ( ) ) ;
205
- }
206
-
207
- let mut array = MaybeUninit :: uninit_array ( ) ;
208
151
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 ( ) } ;
212
156
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) ;
255
160
}
256
161
}
257
162
0 commit comments