@@ -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:: DataMappable ;
2021use crate :: dimension;
2122use crate :: dimension:: broadcast:: co_broadcast;
2223use crate :: dimension:: reshape_dim;
@@ -2803,48 +2804,6 @@ where
28032804 self
28042805 }
28052806
2806- /// Consume the array, call `f` by **v**alue on each element, and return an
2807- /// owned array with the new values. Works for **any** `F: FnMut(A)->B`.
2808- ///
2809- /// If `A` and `B` are the same type then the map is performed by delegating
2810- /// to [`mapv_into`] and then converting into an owned array. This avoids
2811- /// unnecessary memory allocations in [`mapv`].
2812- ///
2813- /// If `A` and `B` are different types then a new array is allocated and the
2814- /// map is performed as in [`mapv`].
2815- ///
2816- /// Elements are visited in arbitrary order.
2817- ///
2818- /// [`mapv_into`]: ArrayBase::mapv_into
2819- /// [`mapv`]: ArrayBase::mapv
2820- pub fn mapv_into_any < B , F > ( self , mut f : F ) -> Array < B , D >
2821- where
2822- S : DataMut ,
2823- F : FnMut ( A ) -> B ,
2824- A : Clone + ' static ,
2825- B : ' static ,
2826- {
2827- if core:: any:: TypeId :: of :: < A > ( ) == core:: any:: TypeId :: of :: < B > ( ) {
2828- // A and B are the same type.
2829- // Wrap f in a closure of type FnMut(A) -> A .
2830- let f = |a| {
2831- let b = f ( a) ;
2832- // Safe because A and B are the same type.
2833- unsafe { unlimited_transmute :: < B , A > ( b) }
2834- } ;
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) }
2841- } else {
2842- // A and B are not the same type.
2843- // Fallback to mapv().
2844- self . mapv ( f)
2845- }
2846- }
2847-
28482807 /// Modify the array in place by calling `f` by mutable reference on each element.
28492808 ///
28502809 /// Elements are visited in arbitrary order.
@@ -3059,6 +3018,111 @@ where
30593018 }
30603019}
30613020
3021+ /// # Additional Mapping Methods
3022+ impl < ' a , A , S , D > ArrayBase < S , D >
3023+ where
3024+ D : Dimension ,
3025+ // Need 'static lifetime bounds for TypeId to work.
3026+ // mapv() requires that A be Clone.
3027+ A : Clone + ' a + ' static ,
3028+ // Output is same memory representation as input, substituting B for A.
3029+ S : Data < Elem = A > + DataMappable < ' a > ,
3030+ {
3031+ /// Consume the array, call `f` by **v**alue on each element, and return an
3032+ /// owned array with the new values. Works for **any** `F: FnMut(A)->B`.
3033+ ///
3034+ /// If `A` and `B` are the same type then the map is performed by delegating
3035+ /// to [`mapv_into`](`ArrayBase::mapv_into`) and then converting into an
3036+ /// owned array. This avoids unnecessary memory allocations in
3037+ /// [`mapv`](`ArrayBase::mapv`).
3038+ ///
3039+ /// If `A` and `B` are different types then a new array is allocated and the
3040+ /// map is performed as in [`mapv`](`ArrayBase::mapv`).
3041+ ///
3042+ /// Elements are visited in arbitrary order.
3043+ ///
3044+ /// Example:
3045+ ///
3046+ /// ```rust
3047+ /// # use ndarray::{array, Array};
3048+ /// let a: Array<f32, _> = array![[1., 2., 3.]];
3049+ /// let b = a.clone();
3050+ /// // Same type, no new memory allocation.
3051+ /// let a_plus_one = a.mapv_into_any(|a| a + 1.);
3052+ /// // Different types, allocates new memory.
3053+ /// let rounded = b.mapv_into_any(|a| a.round() as i32);
3054+ /// ```
3055+ ///
3056+ /// The return data representation/type depends on the input type and is the
3057+ /// same as the input type in most cases. See [`DataMappable`] for details.
3058+ ///
3059+ /// - [`OwnedRepr`](`crate::OwnedRepr`)/[`Array`] -> [`OwnedRepr`](`crate::OwnedRepr`)/[`Array`]
3060+ /// - [`OwnedArcRepr`](`crate::OwnedArcRepr`)/[`ArcArray`] -> [`OwnedArcRepr`](`crate::OwnedArcRepr`)/[`ArcArray`]
3061+ /// - [`CowRepr`](`crate::CowRepr`)/[`CowArray`] -> [`CowRepr`](`crate::CowRepr`)/[`CowArray`]
3062+ /// - [`ViewRepr`](`crate::ViewRepr`)/[`ArrayView`] or [`ArrayViewMut`] -> [`OwnedRepr`](`crate::OwnedRepr`)/[`Array`]
3063+ ///
3064+ /// Mapping from `A` to a different type `B` will always require new memory
3065+ /// to be allocated. Mapping when `A` and `B` are the same type may not need
3066+ /// a new memory allocation depending on the input data representation/type.
3067+ ///
3068+ /// - [`OwnedRepr`](`crate::OwnedRepr`)/[`Array`]: No new memory allocation.
3069+ /// - [`OwnedArcRepr`](`crate::OwnedArcRepr`)/[`ArcArray`]: No new memory allocated if data is uniquely owned.
3070+ /// - [`CowRepr`](`crate::CowRepr`)/[`CowArray`]: No new memory allocated if data is uniquely owned.
3071+ /// - [`ViewRepr`](`crate::ViewRepr`)/[`ArrayView`] or [`ArrayViewMut`]: Always requires new memory allocation.
3072+ /// Consider using [`map_inplace`](`ArrayBase::map_inplace`) instead.
3073+ ///
3074+ /// Example:
3075+ ///
3076+ /// ```rust
3077+ /// # use ndarray::{array, ArcArray};
3078+ /// // Uniquely owned data, no new memory allocation.
3079+ /// let a: ArcArray<f32, _> = array![[1., 2., 3.]].into_shared();
3080+ /// let a_plus_one = a.mapv_into_any(|a| a + 1.);
3081+ /// // Shared data, requires new memory allocation.
3082+ /// let a: ArcArray<f32, _> = array![[1., 2., 3.]].into_shared();
3083+ /// let b = a.clone(); // `a` is shared here
3084+ /// let a_plus_one = a.mapv_into_any(|a| a + 1.); // new allocation
3085+ /// ```
3086+ ///
3087+ /// See also:
3088+ ///
3089+ /// - [`map_inplace`](`ArrayBase::map_inplace`)
3090+ /// - [`mapv_into`](`ArrayBase::mapv_into`)
3091+ /// - [`mapv`](`ArrayBase::mapv`)
3092+ pub fn mapv_into_any < B , F > ( self , mut f : F ) -> ArrayBase < <S as DataMappable < ' a > >:: Subst < B > , D >
3093+ where
3094+ // Need 'static lifetime bounds for TypeId to work.
3095+ B : ' static ,
3096+ // Mapping function maps from A to B.
3097+ F : FnMut ( A ) -> B ,
3098+ {
3099+ if core:: any:: TypeId :: of :: < A > ( ) == core:: any:: TypeId :: of :: < B > ( ) {
3100+ // A and B are the same type.
3101+ // Wrap f in a closure of type FnMut(A) -> A .
3102+ let f = |a| {
3103+ let b = f ( a) ;
3104+ // Safe because A and B are the same type.
3105+ unsafe { unlimited_transmute :: < B , A > ( b) }
3106+ } ;
3107+ // Convert to a uniquely-owned data representation: Array<A, D>
3108+ // This will require cloning the data if it is not uniquely owned.
3109+ let input = self . into_owned ( ) ;
3110+ // Delegate to mapv_into() to map from element type A to type A.
3111+ let output = input. mapv_into ( f) ;
3112+ // Convert to the output data representation, but still with data A.
3113+ let output = <S as DataMappable >:: from_owned :: < A , D > ( output) ;
3114+ // Transmute to the output representation to data B.
3115+ // Safe because A and B are the same type,
3116+ // and we are not changing the data representation.
3117+ unsafe { unlimited_transmute :: < ArrayBase < <S as DataMappable >:: Subst < A > , D > , ArrayBase < <S as DataMappable >:: Subst < B > , D > > ( output) }
3118+ } else {
3119+ // A and B are not the same type.
3120+ // Fallback to mapv().
3121+ <S as DataMappable >:: from_owned :: < B , D > ( self . mapv ( f) )
3122+ }
3123+ }
3124+ }
3125+
30623126/// Transmute from A to B.
30633127///
30643128/// Like transmute, but does not have the compile-time size check which blocks
0 commit comments