@@ -17,6 +17,7 @@ use std::mem::{size_of, ManuallyDrop};
17
17
use crate :: imp_prelude:: * ;
18
18
19
19
use crate :: argument_traits:: AssignElem ;
20
+ use crate :: data_traits:: RawDataSubst ;
20
21
use crate :: dimension;
21
22
use crate :: dimension:: broadcast:: co_broadcast;
22
23
use crate :: dimension:: reshape_dim;
@@ -2814,15 +2815,59 @@ where
2814
2815
/// map is performed as in [`mapv`].
2815
2816
///
2816
2817
/// 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
+ ///
2818
2854
/// [`mapv_into`]: ArrayBase::mapv_into
2819
2855
/// [`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 >
2821
2857
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.
2823
2863
F : FnMut ( A ) -> B ,
2864
+ // Need 'static lifetime bounds for TypeId to work.
2865
+ // mapv() requires that A be Clone.
2824
2866
A : Clone + ' static ,
2825
2867
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 > > ,
2826
2871
{
2827
2872
if core:: any:: TypeId :: of :: < A > ( ) == core:: any:: TypeId :: of :: < B > ( ) {
2828
2873
// A and B are the same type.
@@ -2832,16 +2877,20 @@ where
2832
2877
// Safe because A and B are the same type.
2833
2878
unsafe { unlimited_transmute :: < B , A > ( b) }
2834
2879
} ;
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
+ debug_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) }
2841
2890
} else {
2842
2891
// A and B are not the same type.
2843
2892
// Fallback to mapv().
2844
- self . mapv ( f)
2893
+ self . mapv ( f) . into ( )
2845
2894
}
2846
2895
}
2847
2896
0 commit comments