@@ -425,103 +425,62 @@ impl<T, const N: usize> [T; N] {
425425 /// assert_eq!(y, [6, 9, 3, 3]);
426426 /// ```
427427 #[ 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 ]
429429 where
430430 F : FnMut ( T ) -> U ,
431431 {
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.
481449 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 ;
484452 }
485- guard. initialized += 1 ;
486453 }
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) } ;
492454 }
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 > {
500456 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.
507460 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) ;
509464 }
510465 }
511466 }
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) ;
518477 }
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 ) }
525484 }
526485
527486 /// Returns a slice containing the entire array. Equivalent to `&s[..]`.
0 commit comments