Skip to content

Commit

Permalink
add mapv_into_any(), resolved #1031
Browse files Browse the repository at this point in the history
  • Loading branch information
benkay86 committed Jul 9, 2021
1 parent 307234e commit 94ffa0f
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 0 deletions.
39 changes: 39 additions & 0 deletions src/impl_methods.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2473,6 +2473,45 @@ where
self
}

/// Consume the array, call `f` by **v**alue on each element, and return an
/// owned array with the new values. Works for **any** `F: FnMut(A)->B`.
///
/// If `A` and `B` are the same type then the map is performed by delegating
/// to [`mapv_into()`] and then converting into an owned array. This avoids
/// unnecessary memory allocations in [`mapv()`].
///
/// If `A` and `B` are different types then a new array is allocated and the
/// map is performed as in [`mapv()`].
///
/// Elements are visited in arbitrary order.
pub fn mapv_into_any<B, F>(self, mut f: F) -> Array<B, D>
where
S: DataMut,
F: FnMut(A) -> B,
A: Clone + 'static,
B: 'static,
{
if core::any::TypeId::of::<A>() == core::any::TypeId::of::<B>() {
// A and B are the same type.
// Wrap f in a closure of type FnMut(A) -> A .
let f = |a| {
let b = f(a);
// Safe because A and B are the same type.
unsafe { unlimited_transmute::<B, A>(b) }
};
// Delegate to mapv_into() using the wrapped closure.
// Convert output to a uniquely owned array of type Array<A, D>.
let output = self.mapv_into(f).into_owned();
// Change the return type from Array<A, D> to Array<B, D>.
// Again, safe because A and B are the same type.
unsafe { unlimited_transmute::<Array<A, D>, Array<B, D>>(output) }
} else {
// A and B are not the same type.
// Fallback to mapv().
self.mapv(f)
}
}

/// Modify the array in place by calling `f` by mutable reference on each element.
///
/// Elements are visited in arbitrary order.
Expand Down
14 changes: 14 additions & 0 deletions tests/array.rs
Original file line number Diff line number Diff line change
Expand Up @@ -989,6 +989,20 @@ fn map1() {
assert_eq!(a[(0, 0)], *c[(0, 0)]);
}

#[test]
fn mapv_into_any_same_type() {
let a: Array<f64, _> = array![[1., 2., 3.], [4., 5., 6.]];
let a_plus_one: Array<f64, _> = array![[2., 3., 4.], [5., 6., 7.]];
assert_eq!(a.mapv_into_any(|a| a + 1.), a_plus_one);
}

#[test]
fn mapv_into_any_diff_types() {
let a: Array<f64, _> = array![[1., 2., 3.], [4., 5., 6.]];
let a_even: Array<bool, _> = array![[false, true, false], [true, false, true]];
assert_eq!(a.mapv_into_any(|a| a.round() as i32 % 2 == 0), a_even);
}

#[test]
fn as_slice_memory_order_mut_arcarray() {
// Test that mutation breaks sharing for `ArcArray`.
Expand Down

0 comments on commit 94ffa0f

Please sign in to comment.