@@ -425,103 +425,62 @@ impl<T, const N: usize> [T; N] {
425
425
/// assert_eq!(y, [6, 9, 3, 3]);
426
426
/// ```
427
427
#[ unstable( feature = "array_map" , issue = "75243" ) ]
428
- pub fn map < F , U > ( self , mut f : F ) -> [ U ; N ]
428
+ pub fn map < F , U > ( self , f : F ) -> [ U ; N ]
429
429
where
430
430
F : FnMut ( T ) -> U ,
431
431
{
432
- use crate :: mem:: { align_of, forget, size_of, transmute_copy, ManuallyDrop , MaybeUninit } ;
433
-
434
- if align_of :: < T > ( ) == align_of :: < U > ( ) && size_of :: < T > ( ) == size_of :: < U > ( ) {
435
- // this branch allows reuse of the original array as a backing store
436
- // kind of. As written with no compiler optimizations, transmute copy will
437
- // still require 2 copies of the original array, but when it can be converted to
438
- // transmute, this will require 0 copies.
439
- union Translated < T , U > {
440
- src : MaybeUninit < T > ,
441
- dst : ManuallyDrop < U > ,
442
- } ;
443
- struct Guard < T , U , const N : usize > {
444
- data : * mut [ Translated < T , U > ; N ] ,
445
- initialized : usize ,
446
- }
447
- impl < T , U , const N : usize > Drop for Guard < T , U , N > {
448
- fn drop ( & mut self ) {
449
- debug_assert ! ( self . initialized < N ) ;
450
- let initialized_part =
451
- crate :: ptr:: slice_from_raw_parts_mut ( self . data as * mut U , self . initialized ) ;
452
- // SAFETY:
453
- // since we read from the element at initialized then panicked,
454
- // we have to skip over it to not double drop.
455
- let todo_ptr = unsafe { self . data . add ( self . initialized + 1 ) as * mut T } ;
456
- let todo_part =
457
- crate :: ptr:: slice_from_raw_parts_mut ( todo_ptr, N - self . initialized - 1 ) ;
458
- // SAFETY:
459
- // Have to remove both the initialized and not yet reached items.
460
- unsafe {
461
- crate :: ptr:: drop_in_place ( initialized_part) ;
462
- crate :: ptr:: drop_in_place ( todo_part) ;
463
- }
464
- }
465
- }
466
- // SAFETY:
467
- // Since we know that T & U have the same size and alignment we can safely transmute
468
- // between them here
469
- let mut src_dst = unsafe { transmute_copy :: < _ , [ Translated < T , U > ; N ] > ( & self ) } ;
470
-
471
- let mut guard: Guard < T , U , N > = Guard { data : & mut src_dst, initialized : 0 } ;
472
- // Need to forget self now because the guard is responsible for dropping the items
473
- forget ( self ) ;
474
- for i in 0 ..N {
475
- // SAFETY:
476
- // All items prior to `i` are the `dst` variant.
477
- // In order to convert `i` from src to dst, we take it from `MaybeUninit`,
478
- // leaving uninitialized in its place, and set the destination as
479
- // ManuallyDrop::new(..), and implicitly know that it will be a `dst` variant
480
- // from where
432
+ use crate :: mem:: { forget, ManuallyDrop , MaybeUninit } ;
433
+ use crate :: ptr;
434
+
435
+ union MaybeUninitArray < T , const N : usize > {
436
+ none : ( ) ,
437
+ partial : ManuallyDrop < [ MaybeUninit < T > ; N ] > ,
438
+ complete : ManuallyDrop < [ T ; N ] > ,
439
+ }
440
+ struct MapGuard < ' a , T , const N : usize > {
441
+ arr : & ' a mut MaybeUninitArray < T , N > ,
442
+ len : usize ,
443
+ }
444
+ impl < ' a , T , const N : usize > MapGuard < ' a , T , N > {
445
+ fn push ( & mut self , value : T ) {
446
+ // SAFETY: Since we know the input size is N, and the output is N,
447
+ // this will never exceed the capacity, and MaybeUninit is always in the
448
+ // structure of an array.
481
449
unsafe {
482
- let v = f ( src_dst [ i ] . src . assume_init_read ( ) ) ;
483
- src_dst [ i ] . dst = ManuallyDrop :: new ( v ) ;
450
+ self . arr . partial [ self . len ] . write ( value ) ;
451
+ self . len += 1 ;
484
452
}
485
- guard. initialized += 1 ;
486
453
}
487
- forget ( guard) ;
488
- // SAFETY:
489
- // At this point all the items have been initialized and are in `dst` discriminant.
490
- // We can switch them over to being of type `U`.
491
- return unsafe { transmute_copy :: < _ , [ U ; N ] > ( & src_dst) } ;
492
454
}
493
-
494
- struct Guard < T , const N : usize > {
495
- dst : * mut T ,
496
- initialized : usize ,
497
- }
498
-
499
- impl < T , const N : usize > Drop for Guard < T , N > {
455
+ impl < ' a , T , const N : usize > Drop for MapGuard < ' a , T , N > {
500
456
fn drop ( & mut self ) {
501
- debug_assert ! ( self . initialized <= N ) ;
502
-
503
- let initialized_part =
504
- crate :: ptr:: slice_from_raw_parts_mut ( self . dst , self . initialized ) ;
505
- // SAFETY: this raw slice will contain only initialized objects
506
- // that's why, it is allowed to drop it.
457
+ //debug_assert!(self.len <= N);
458
+ // SAFETY: already pushed `len` elements, but need to drop them now that
459
+ // `f` panicked.
507
460
unsafe {
508
- crate :: ptr:: drop_in_place ( initialized_part) ;
461
+ let p: * mut MaybeUninit < T > = self . arr . partial . as_mut_ptr ( ) ;
462
+ let slice: * mut [ T ] = ptr:: slice_from_raw_parts_mut ( p. cast ( ) , self . len ) ;
463
+ ptr:: drop_in_place ( slice) ;
509
464
}
510
465
}
511
466
}
512
- let mut dst = MaybeUninit :: uninit_array :: < N > ( ) ;
513
- let mut guard: Guard < U , N > =
514
- Guard { dst : MaybeUninit :: slice_as_mut_ptr ( & mut dst) , initialized : 0 } ;
515
- for ( src, dst) in IntoIter :: new ( self ) . zip ( & mut dst) {
516
- dst. write ( f ( src) ) ;
517
- guard. initialized += 1 ;
467
+
468
+ fn map_guard_fn < T , const N : usize > (
469
+ buffer : & mut MaybeUninitArray < T , N > ,
470
+ iter : impl Iterator < Item = T > ,
471
+ ) {
472
+ let mut guard = MapGuard { arr : buffer, len : 0 } ;
473
+ for v in iter {
474
+ guard. push ( v) ;
475
+ }
476
+ forget ( guard) ;
518
477
}
519
- // FIXME: Convert to crate::mem::transmute once it works with generics.
520
- // unsafe { crate::mem::transmute::<[MaybeUninit<U>; N], [U; N]>(dst ) }
521
- forget ( guard ) ;
522
- // SAFETY: At this point we've properly initialized the whole array
523
- // and we just need to cast it to the correct type .
524
- unsafe { transmute_copy :: < _ , [ U ; N ] > ( & dst ) }
478
+
479
+ let mut buffer = MaybeUninitArray :: < U , N > { none : ( ) } ;
480
+ map_guard_fn ( & mut buffer , IntoIter :: new ( self ) . map ( f ) ) ;
481
+ // SAFETY: all elements have successfully initialized, don't run guard's drop code
482
+ // and take completed buffer out of MaybeUninitArray .
483
+ unsafe { ManuallyDrop :: into_inner ( buffer . complete ) }
525
484
}
526
485
527
486
/// Returns a slice containing the entire array. Equivalent to `&s[..]`.
0 commit comments