@@ -17,6 +17,7 @@ use std::mem::{size_of, ManuallyDrop};
1717use crate :: imp_prelude:: * ;
1818
1919use crate :: argument_traits:: AssignElem ;
20+ use crate :: data_traits:: RawDataSubst ;
2021use crate :: dimension;
2122use crate :: dimension:: broadcast:: co_broadcast;
2223use crate :: dimension:: reshape_dim;
@@ -2814,15 +2815,59 @@ where
28142815 /// map is performed as in [`mapv`].
28152816 ///
28162817 /// Elements are visited in arbitrary order.
2817- ///
2818+ ///
2819+ /// Example:
2820+ ///
2821+ /// ```rust
2822+ /// # use ndarray::{array, Array};
2823+ /// let a: Array<f32, _> = array![[1., 2., 3.]];
2824+ /// let b = a.clone();
2825+ /// // Same type, no new memory allocation.
2826+ /// let a_plus_one = a.mapv_into_any(|a| a + 1.);
2827+ /// // Different types, allocates new memory.
2828+ /// let rounded = b.mapv_into_any(|a| a.round() as i32);
2829+ /// ```
2830+ ///
2831+ /// Note that this method works on arrays with different memory
2832+ /// representations (e.g. [`OwnedRepr`](crate::OwnedRepr) vs
2833+ /// [`OwnedArcRepr`](crate::OwnedArcRepr)) but it does *not* convert between
2834+ /// different memory representations.
2835+ ///
2836+ /// This compiles:
2837+ /// ```rust
2838+ /// # use ndarray::{array, ArcArray};
2839+ /// let a: ArcArray<f32, _> = array![[1., 2., 3.]].into();
2840+ /// // OwnedArcRepr --> OwnedArcRepr.
2841+ /// let a_plus_one = a.mapv_into_any(|a| a + 1.);
2842+ /// // We can convert to OwnedRepr if we want.
2843+ /// let a_plus_one = a_plus_one.into_owned();
2844+ /// ```
2845+ ///
2846+ /// This fails to compile:
2847+ /// ```compile_fail,E0308
2848+ /// # use ndarray::{array, Array, ArcArray};
2849+ /// let a: ArcArray<f32, _> = array![[1., 2., 3.]].into();
2850+ /// // OwnedArcRepr --> OwnedRepr
2851+ /// let a_plus_one: Array<_, _> = a.mapv_into_any(|a| a + 1.);
2852+ /// ```
2853+ ///
28182854 /// [`mapv_into`]: ArrayBase::mapv_into
28192855 /// [`mapv`]: ArrayBase::mapv
2820- pub fn mapv_into_any < B , F > ( self , mut f : F ) -> Array < B , D >
2856+ pub fn mapv_into_any < B , F > ( self , mut f : F ) -> ArrayBase < < S as RawDataSubst < B > > :: Output , D >
28212857 where
2822- S : DataMut ,
2858+ // Output is same memory representation as input,
2859+ // Substituting B for A.
2860+ // Need 'static lifetime bounds for TypeId to work.
2861+ S : DataMut < Elem = A > + RawDataSubst < B > + ' static ,
2862+ // Mapping function maps from A to B.
28232863 F : FnMut ( A ) -> B ,
2864+ // Need 'static lifetime bounds for TypeId to work.
2865+ // mapv() requires that A be Clone.
28242866 A : Clone + ' static ,
28252867 B : ' static ,
2868+ // mapv() always returns ArrayBase<OwnedRepr<_>,_>
2869+ // This bound ensures we can convert from OwnedRepr to the output repr.
2870+ ArrayBase < <S as RawDataSubst < B > >:: Output , D > : From < Array < B , D > > ,
28262871 {
28272872 if core:: any:: TypeId :: of :: < A > ( ) == core:: any:: TypeId :: of :: < B > ( ) {
28282873 // A and B are the same type.
@@ -2832,16 +2877,20 @@ where
28322877 // Safe because A and B are the same type.
28332878 unsafe { unlimited_transmute :: < B , A > ( b) }
28342879 } ;
2835- // Delegate to mapv_into() using the wrapped closure.
2836- // Convert output to a uniquely owned array of type Array<A, D>.
2837- let output = self . mapv_into ( f) . into_owned ( ) ;
2838- // Change the return type from Array<A, D> to Array<B, D>.
2839- // Again, safe because A and B are the same type.
2840- unsafe { unlimited_transmute :: < Array < A , D > , Array < B , D > > ( output) }
2880+ // Delegate to mapv_into() to map from element type A to type A.
2881+ let output = self . mapv_into ( f) ;
2882+ // If A and B are the same type, and if the input and output arrays
2883+ // have the same kind of memory representation (OwnedRepr vs
2884+ // OwnedArcRepr), then their memory representations should be the
2885+ // same type, e.g. OwnedRepr<A> == OwnedRepr<B>
2886+ assert ! ( core:: any:: TypeId :: of:: <S >( ) == core:: any:: TypeId :: of:: <<S as RawDataSubst <B >>:: Output >( ) ) ;
2887+ // Now we can safely transmute the element type from A to the
2888+ // identical type B, keeping the same memory representation.
2889+ unsafe { unlimited_transmute :: < ArrayBase < S , D > , ArrayBase < <S as RawDataSubst < B > >:: Output , D > > ( output) }
28412890 } else {
28422891 // A and B are not the same type.
28432892 // Fallback to mapv().
2844- self . mapv ( f)
2893+ self . mapv ( f) . into ( )
28452894 }
28462895 }
28472896
0 commit comments