Skip to content

Commit 10ba041

Browse files
committed
Make mapv_into_any() work for ArcArray, resolves #1280
1 parent 492b274 commit 10ba041

File tree

2 files changed

+95
-12
lines changed

2 files changed

+95
-12
lines changed

src/impl_methods.rs

Lines changed: 59 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ use std::mem::{size_of, ManuallyDrop};
1717
use crate::imp_prelude::*;
1818

1919
use crate::argument_traits::AssignElem;
20+
use crate::data_traits::RawDataSubst;
2021
use crate::dimension;
2122
use crate::dimension::broadcast::co_broadcast;
2223
use 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+
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) }
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

tests/array.rs

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1054,15 +1054,49 @@ fn mapv_into_any_same_type()
10541054
{
10551055
let a: Array<f64, _> = array![[1., 2., 3.], [4., 5., 6.]];
10561056
let a_plus_one: Array<f64, _> = array![[2., 3., 4.], [5., 6., 7.]];
1057-
assert_eq!(a.mapv_into_any(|a| a + 1.), a_plus_one);
1057+
let b = a.mapv_into_any(|a| a + 1.);
1058+
assert_eq!(b, a_plus_one);
10581059
}
10591060

10601061
#[test]
10611062
fn mapv_into_any_diff_types()
10621063
{
10631064
let a: Array<f64, _> = array![[1., 2., 3.], [4., 5., 6.]];
10641065
let a_even: Array<bool, _> = array![[false, true, false], [true, false, true]];
1065-
assert_eq!(a.mapv_into_any(|a| a.round() as i32 % 2 == 0), a_even);
1066+
let b = a.mapv_into_any(|a| a.round() as i32 % 2 == 0);
1067+
assert_eq!(b, a_even);
1068+
}
1069+
1070+
#[test]
1071+
fn mapv_into_any_arcarray_same_type() {
1072+
let a: ArcArray<f64, _> = array![[1., 2., 3.], [4., 5., 6.]].into_shared();
1073+
let a_plus_one: Array<f64, _> = array![[2., 3., 4.], [5., 6., 7.]];
1074+
let b = a.mapv_into_any(|a| a + 1.);
1075+
assert_eq!(b, a_plus_one);
1076+
}
1077+
1078+
#[test]
1079+
fn mapv_into_any_arcarray_diff_types() {
1080+
let a: ArcArray<f64, _> = array![[1., 2., 3.], [4., 5., 6.]].into_shared();
1081+
let a_even: Array<bool, _> = array![[false, true, false], [true, false, true]];
1082+
let b = a.mapv_into_any(|a| a.round() as i32 % 2 == 0);
1083+
assert_eq!(b, a_even);
1084+
}
1085+
1086+
#[test]
1087+
fn mapv_into_any_cowarray_same_type() {
1088+
let a: CowArray<f64, _> = array![[1., 2., 3.], [4., 5., 6.]].into();
1089+
let a_plus_one: Array<f64, _> = array![[2., 3., 4.], [5., 6., 7.]];
1090+
let b = a.mapv_into_any(|a| a + 1.);
1091+
assert_eq!(b, a_plus_one);
1092+
}
1093+
1094+
#[test]
1095+
fn mapv_into_any_cowarray_diff_types() {
1096+
let a: CowArray<f64, _> = array![[1., 2., 3.], [4., 5., 6.]].into();
1097+
let a_even: Array<bool, _> = array![[false, true, false], [true, false, true]];
1098+
let b = a.mapv_into_any(|a| a.round() as i32 % 2 == 0);
1099+
assert_eq!(b, a_even);
10661100
}
10671101

10681102
#[test]

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy