1
1
//! Defines the `IntoIter` owned iterator for arrays.
2
2
3
3
use crate :: intrinsics:: transmute_unchecked;
4
- use crate :: iter:: { self , FusedIterator , TrustedLen , TrustedRandomAccessNoCoerce } ;
4
+ use crate :: iter:: { FusedIterator , TrustedLen , TrustedRandomAccessNoCoerce } ;
5
5
use crate :: mem:: MaybeUninit ;
6
6
use crate :: num:: NonZero ;
7
- use crate :: ops:: { IndexRange , Range } ;
7
+ use crate :: ops:: { IndexRange , Range , Try } ;
8
8
use crate :: { fmt, ptr} ;
9
9
10
+ mod iter_inner;
11
+
12
+ type InnerSized < T , const N : usize > = iter_inner:: PolymorphicIter < [ MaybeUninit < T > ; N ] > ;
13
+ type InnerUnsized < T > = iter_inner:: PolymorphicIter < [ MaybeUninit < T > ] > ;
14
+
10
15
/// A by-value [array] iterator.
11
16
#[ stable( feature = "array_value_iter" , since = "1.51.0" ) ]
12
17
#[ rustc_insignificant_dtor]
13
18
#[ rustc_diagnostic_item = "ArrayIntoIter" ]
19
+ #[ derive( Clone ) ]
14
20
pub struct IntoIter < T , const N : usize > {
15
- /// This is the array we are iterating over.
16
- ///
17
- /// Elements with index `i` where `alive.start <= i < alive.end` have not
18
- /// been yielded yet and are valid array entries. Elements with indices `i
19
- /// < alive.start` or `i >= alive.end` have been yielded already and must
20
- /// not be accessed anymore! Those dead elements might even be in a
21
- /// completely uninitialized state!
22
- ///
23
- /// So the invariants are:
24
- /// - `data[alive]` is alive (i.e. contains valid elements)
25
- /// - `data[..alive.start]` and `data[alive.end..]` are dead (i.e. the
26
- /// elements were already read and must not be touched anymore!)
27
- data : [ MaybeUninit < T > ; N ] ,
21
+ inner : InnerSized < T , N > ,
22
+ }
28
23
29
- /// The elements in `data` that have not been yielded yet.
30
- ///
31
- /// Invariants:
32
- /// - `alive.end <= N`
33
- ///
34
- /// (And the `IndexRange` type requires `alive.start <= alive.end`.)
35
- alive : IndexRange ,
24
+ impl < T , const N : usize > IntoIter < T , N > {
25
+ #[ inline]
26
+ fn unsize ( & self ) -> & InnerUnsized < T > {
27
+ & self . inner
28
+ }
29
+ #[ inline]
30
+ fn unsize_mut ( & mut self ) -> & mut InnerUnsized < T > {
31
+ & mut self . inner
32
+ }
36
33
}
37
34
38
35
// Note: the `#[rustc_skip_during_method_dispatch(array)]` on `trait IntoIterator`
@@ -53,6 +50,7 @@ impl<T, const N: usize> IntoIterator for [T; N] {
53
50
/// 2021 edition -- see the [array] Editions section for more information.
54
51
///
55
52
/// [array]: prim@array
53
+ #[ inline]
56
54
fn into_iter ( self ) -> Self :: IntoIter {
57
55
// SAFETY: The transmute here is actually safe. The docs of `MaybeUninit`
58
56
// promise:
@@ -68,7 +66,10 @@ impl<T, const N: usize> IntoIterator for [T; N] {
68
66
// FIXME: If normal `transmute` ever gets smart enough to allow this
69
67
// directly, use it instead of `transmute_unchecked`.
70
68
let data: [ MaybeUninit < T > ; N ] = unsafe { transmute_unchecked ( self ) } ;
71
- IntoIter { data, alive : IndexRange :: zero_to ( N ) }
69
+ // SAFETY: The original array was entirely initialized and the the alive
70
+ // range we're passing here represents that fact.
71
+ let inner = unsafe { InnerSized :: new_unchecked ( IndexRange :: zero_to ( N ) , data) } ;
72
+ IntoIter { inner }
72
73
}
73
74
}
74
75
@@ -136,13 +137,16 @@ impl<T, const N: usize> IntoIter<T, N> {
136
137
/// assert_eq!(r.collect::<Vec<_>>(), vec![10, 11, 12, 13, 14, 15]);
137
138
/// ```
138
139
#[ unstable( feature = "array_into_iter_constructors" , issue = "91583" ) ]
140
+ #[ inline]
139
141
pub const unsafe fn new_unchecked (
140
142
buffer : [ MaybeUninit < T > ; N ] ,
141
143
initialized : Range < usize > ,
142
144
) -> Self {
143
145
// SAFETY: one of our safety conditions is that the range is canonical.
144
146
let alive = unsafe { IndexRange :: new_unchecked ( initialized. start , initialized. end ) } ;
145
- Self { data : buffer, alive }
147
+ // SAFETY: one of our safety condition is that these items are initialized.
148
+ let inner = unsafe { InnerSized :: new_unchecked ( alive, buffer) } ;
149
+ IntoIter { inner }
146
150
}
147
151
148
152
/// Creates an iterator over `T` which returns no elements.
@@ -198,172 +202,134 @@ impl<T, const N: usize> IntoIter<T, N> {
198
202
/// assert_eq!(get_bytes(false).collect::<Vec<_>>(), vec![]);
199
203
/// ```
200
204
#[ unstable( feature = "array_into_iter_constructors" , issue = "91583" ) ]
205
+ #[ inline]
201
206
pub const fn empty ( ) -> Self {
202
- let buffer = [ const { MaybeUninit :: uninit ( ) } ; N ] ;
203
- let initialized = 0 ..0 ;
204
-
205
- // SAFETY: We're telling it that none of the elements are initialized,
206
- // which is trivially true. And ∀N: usize, 0 <= N.
207
- unsafe { Self :: new_unchecked ( buffer, initialized) }
207
+ let inner = InnerSized :: empty ( ) ;
208
+ IntoIter { inner }
208
209
}
209
210
210
211
/// Returns an immutable slice of all elements that have not been yielded
211
212
/// yet.
212
213
#[ stable( feature = "array_value_iter" , since = "1.51.0" ) ]
214
+ #[ inline]
213
215
pub fn as_slice ( & self ) -> & [ T ] {
214
- // SAFETY: We know that all elements within `alive` are properly initialized.
215
- unsafe {
216
- let slice = self . data . get_unchecked ( self . alive . clone ( ) ) ;
217
- slice. assume_init_ref ( )
218
- }
216
+ self . unsize ( ) . as_slice ( )
219
217
}
220
218
221
219
/// Returns a mutable slice of all elements that have not been yielded yet.
222
220
#[ stable( feature = "array_value_iter" , since = "1.51.0" ) ]
221
+ #[ inline]
223
222
pub fn as_mut_slice ( & mut self ) -> & mut [ T ] {
224
- // SAFETY: We know that all elements within `alive` are properly initialized.
225
- unsafe {
226
- let slice = self . data . get_unchecked_mut ( self . alive . clone ( ) ) ;
227
- slice. assume_init_mut ( )
228
- }
223
+ self . unsize_mut ( ) . as_mut_slice ( )
229
224
}
230
225
}
231
226
232
227
#[ stable( feature = "array_value_iter_impls" , since = "1.40.0" ) ]
233
228
impl < T , const N : usize > Iterator for IntoIter < T , N > {
234
229
type Item = T ;
230
+
231
+ #[ inline]
235
232
fn next ( & mut self ) -> Option < Self :: Item > {
236
- // Get the next index from the front.
237
- //
238
- // Increasing `alive.start` by 1 maintains the invariant regarding
239
- // `alive`. However, due to this change, for a short time, the alive
240
- // zone is not `data[alive]` anymore, but `data[idx..alive.end]`.
241
- self . alive . next ( ) . map ( |idx| {
242
- // Read the element from the array.
243
- // SAFETY: `idx` is an index into the former "alive" region of the
244
- // array. Reading this element means that `data[idx]` is regarded as
245
- // dead now (i.e. do not touch). As `idx` was the start of the
246
- // alive-zone, the alive zone is now `data[alive]` again, restoring
247
- // all invariants.
248
- unsafe { self . data . get_unchecked ( idx) . assume_init_read ( ) }
249
- } )
233
+ self . unsize_mut ( ) . next ( )
250
234
}
251
235
236
+ #[ inline]
252
237
fn size_hint ( & self ) -> ( usize , Option < usize > ) {
253
- let len = self . len ( ) ;
254
- ( len, Some ( len) )
238
+ self . unsize ( ) . size_hint ( )
255
239
}
256
240
257
241
#[ inline]
258
- fn fold < Acc , Fold > ( mut self , init : Acc , mut fold : Fold ) -> Acc
242
+ fn fold < Acc , Fold > ( mut self , init : Acc , fold : Fold ) -> Acc
259
243
where
260
244
Fold : FnMut ( Acc , Self :: Item ) -> Acc ,
261
245
{
262
- let data = & mut self . data ;
263
- iter:: ByRefSized ( & mut self . alive ) . fold ( init, |acc, idx| {
264
- // SAFETY: idx is obtained by folding over the `alive` range, which implies the
265
- // value is currently considered alive but as the range is being consumed each value
266
- // we read here will only be read once and then considered dead.
267
- fold ( acc, unsafe { data. get_unchecked ( idx) . assume_init_read ( ) } )
268
- } )
246
+ self . unsize_mut ( ) . fold ( init, fold)
269
247
}
270
248
249
+ #[ inline]
250
+ fn try_fold < B , F , R > ( & mut self , init : B , f : F ) -> R
251
+ where
252
+ Self : Sized ,
253
+ F : FnMut ( B , Self :: Item ) -> R ,
254
+ R : Try < Output = B > ,
255
+ {
256
+ self . unsize_mut ( ) . try_fold ( init, f)
257
+ }
258
+
259
+ #[ inline]
271
260
fn count ( self ) -> usize {
272
261
self . len ( )
273
262
}
274
263
264
+ #[ inline]
275
265
fn last ( mut self ) -> Option < Self :: Item > {
276
266
self . next_back ( )
277
267
}
278
268
269
+ #[ inline]
279
270
fn advance_by ( & mut self , n : usize ) -> Result < ( ) , NonZero < usize > > {
280
- // This also moves the start, which marks them as conceptually "dropped",
281
- // so if anything goes bad then our drop impl won't double-free them.
282
- let range_to_drop = self . alive . take_prefix ( n) ;
283
- let remaining = n - range_to_drop. len ( ) ;
284
-
285
- // SAFETY: These elements are currently initialized, so it's fine to drop them.
286
- unsafe {
287
- let slice = self . data . get_unchecked_mut ( range_to_drop) ;
288
- slice. assume_init_drop ( ) ;
289
- }
290
-
291
- NonZero :: new ( remaining) . map_or ( Ok ( ( ) ) , Err )
271
+ self . unsize_mut ( ) . advance_by ( n)
292
272
}
293
273
294
274
#[ inline]
295
275
unsafe fn __iterator_get_unchecked ( & mut self , idx : usize ) -> Self :: Item {
296
276
// SAFETY: The caller must provide an idx that is in bound of the remainder.
297
- unsafe { self . data . as_ptr ( ) . add ( self . alive . start ( ) ) . add ( idx) . cast :: < T > ( ) . read ( ) }
277
+ let elem_ref = unsafe { self . as_mut_slice ( ) . get_unchecked_mut ( idx) } ;
278
+ // SAFETY: We only implement `TrustedRandomAccessNoCoerce` for types
279
+ // which are actually `Copy`, so cannot have multiple-drop issues.
280
+ unsafe { ptr:: read ( elem_ref) }
298
281
}
299
282
}
300
283
301
284
#[ stable( feature = "array_value_iter_impls" , since = "1.40.0" ) ]
302
285
impl < T , const N : usize > DoubleEndedIterator for IntoIter < T , N > {
286
+ #[ inline]
303
287
fn next_back ( & mut self ) -> Option < Self :: Item > {
304
- // Get the next index from the back.
305
- //
306
- // Decreasing `alive.end` by 1 maintains the invariant regarding
307
- // `alive`. However, due to this change, for a short time, the alive
308
- // zone is not `data[alive]` anymore, but `data[alive.start..=idx]`.
309
- self . alive . next_back ( ) . map ( |idx| {
310
- // Read the element from the array.
311
- // SAFETY: `idx` is an index into the former "alive" region of the
312
- // array. Reading this element means that `data[idx]` is regarded as
313
- // dead now (i.e. do not touch). As `idx` was the end of the
314
- // alive-zone, the alive zone is now `data[alive]` again, restoring
315
- // all invariants.
316
- unsafe { self . data . get_unchecked ( idx) . assume_init_read ( ) }
317
- } )
288
+ self . unsize_mut ( ) . next_back ( )
318
289
}
319
290
320
291
#[ inline]
321
- fn rfold < Acc , Fold > ( mut self , init : Acc , mut rfold : Fold ) -> Acc
292
+ fn rfold < Acc , Fold > ( mut self , init : Acc , rfold : Fold ) -> Acc
322
293
where
323
294
Fold : FnMut ( Acc , Self :: Item ) -> Acc ,
324
295
{
325
- let data = & mut self . data ;
326
- iter:: ByRefSized ( & mut self . alive ) . rfold ( init, |acc, idx| {
327
- // SAFETY: idx is obtained by folding over the `alive` range, which implies the
328
- // value is currently considered alive but as the range is being consumed each value
329
- // we read here will only be read once and then considered dead.
330
- rfold ( acc, unsafe { data. get_unchecked ( idx) . assume_init_read ( ) } )
331
- } )
296
+ self . unsize_mut ( ) . rfold ( init, rfold)
297
+ }
298
+
299
+ #[ inline]
300
+ fn try_rfold < B , F , R > ( & mut self , init : B , f : F ) -> R
301
+ where
302
+ Self : Sized ,
303
+ F : FnMut ( B , Self :: Item ) -> R ,
304
+ R : Try < Output = B > ,
305
+ {
306
+ self . unsize_mut ( ) . try_rfold ( init, f)
332
307
}
333
308
309
+ #[ inline]
334
310
fn advance_back_by ( & mut self , n : usize ) -> Result < ( ) , NonZero < usize > > {
335
- // This also moves the end, which marks them as conceptually "dropped",
336
- // so if anything goes bad then our drop impl won't double-free them.
337
- let range_to_drop = self . alive . take_suffix ( n) ;
338
- let remaining = n - range_to_drop. len ( ) ;
339
-
340
- // SAFETY: These elements are currently initialized, so it's fine to drop them.
341
- unsafe {
342
- let slice = self . data . get_unchecked_mut ( range_to_drop) ;
343
- slice. assume_init_drop ( ) ;
344
- }
345
-
346
- NonZero :: new ( remaining) . map_or ( Ok ( ( ) ) , Err )
311
+ self . unsize_mut ( ) . advance_back_by ( n)
347
312
}
348
313
}
349
314
350
315
#[ stable( feature = "array_value_iter_impls" , since = "1.40.0" ) ]
351
316
impl < T , const N : usize > Drop for IntoIter < T , N > {
317
+ #[ inline]
352
318
fn drop ( & mut self ) {
353
- // SAFETY: This is safe: `as_mut_slice` returns exactly the sub-slice
354
- // of elements that have not been moved out yet and that remain
355
- // to be dropped.
356
- unsafe { ptr:: drop_in_place ( self . as_mut_slice ( ) ) }
319
+ // `inner` now handles this, but it'd technically be a breaking change
320
+ // to remove this `impl`, even though it's useless.
357
321
}
358
322
}
359
323
360
324
#[ stable( feature = "array_value_iter_impls" , since = "1.40.0" ) ]
361
325
impl < T , const N : usize > ExactSizeIterator for IntoIter < T , N > {
326
+ #[ inline]
362
327
fn len ( & self ) -> usize {
363
- self . alive . len ( )
328
+ self . inner . len ( )
364
329
}
330
+ #[ inline]
365
331
fn is_empty ( & self ) -> bool {
366
- self . alive . is_empty ( )
332
+ self . inner . len ( ) == 0
367
333
}
368
334
}
369
335
@@ -396,32 +362,9 @@ where
396
362
const MAY_HAVE_SIDE_EFFECT : bool = false ;
397
363
}
398
364
399
- #[ stable( feature = "array_value_iter_impls" , since = "1.40.0" ) ]
400
- impl < T : Clone , const N : usize > Clone for IntoIter < T , N > {
401
- fn clone ( & self ) -> Self {
402
- // Note, we don't really need to match the exact same alive range, so
403
- // we can just clone into offset 0 regardless of where `self` is.
404
- let mut new =
405
- Self { data : [ const { MaybeUninit :: uninit ( ) } ; N ] , alive : IndexRange :: zero_to ( 0 ) } ;
406
-
407
- // Clone all alive elements.
408
- for ( src, dst) in iter:: zip ( self . as_slice ( ) , & mut new. data ) {
409
- // Write a clone into the new array, then update its alive range.
410
- // If cloning panics, we'll correctly drop the previous items.
411
- dst. write ( src. clone ( ) ) ;
412
- // This addition cannot overflow as we're iterating a slice
413
- new. alive = IndexRange :: zero_to ( new. alive . end ( ) + 1 ) ;
414
- }
415
-
416
- new
417
- }
418
- }
419
-
420
365
#[ stable( feature = "array_value_iter_impls" , since = "1.40.0" ) ]
421
366
impl < T : fmt:: Debug , const N : usize > fmt:: Debug for IntoIter < T , N > {
422
367
fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
423
- // Only print the elements that were not yielded yet: we cannot
424
- // access the yielded elements anymore.
425
- f. debug_tuple ( "IntoIter" ) . field ( & self . as_slice ( ) ) . finish ( )
368
+ self . unsize ( ) . fmt ( f)
426
369
}
427
370
}
0 commit comments