use ndarray::prelude::*; use std::sync::atomic::{AtomicUsize, Ordering}; #[test] fn assign() { let mut a = arr2(&[[1., 2.], [3., 4.]]); let b = arr2(&[[1., 3.], [2., 4.]]); a.assign(&b); assert_eq!(a, b); /* Test broadcasting */ a.assign(&ArcArray::zeros(1)); assert_eq!(a, ArcArray::zeros((2, 2))); /* Test other type */ a.assign(&Array::from_elem((2, 2), 3.)); assert_eq!(a, ArcArray::from_elem((2, 2), 3.)); /* Test mut view */ let mut a = arr2(&[[1, 2], [3, 4]]); { let mut v = a.view_mut(); v.slice_collapse(s![..1, ..]); v.fill(0); } assert_eq!(a, arr2(&[[0, 0], [3, 4]])); } #[test] fn assign_to() { let mut a = arr2(&[[1., 2.], [3., 4.]]); let b = arr2(&[[0., 3.], [2., 0.]]); b.assign_to(&mut a); assert_eq!(a, b); } #[test] fn move_into_copy() { let a = arr2(&[[1., 2.], [3., 4.]]); let acopy = a.clone(); let mut b = Array::uninit(a.dim()); a.move_into_uninit(b.view_mut()); let b = unsafe { b.assume_init() }; assert_eq!(acopy, b); let a = arr2(&[[1., 2.], [3., 4.]]).reversed_axes(); let acopy = a.clone(); let mut b = Array::uninit(a.dim()); a.move_into_uninit(b.view_mut()); let b = unsafe { b.assume_init() }; assert_eq!(acopy, b); } #[test] fn move_into_owned() { // Test various memory layouts and holes while moving String elements. for &use_f_order in &[false, true] { for &invert_axis in &[0b00, 0b01, 0b10, 0b11] { // bitmask for axis to invert for &slice in &[false, true] { let mut a = Array::from_shape_fn((5, 4).set_f(use_f_order), |idx| format!("{:?}", idx)); if slice { a.slice_collapse(s![1..-1, ..;2]); } if invert_axis & 0b01 != 0 { a.invert_axis(Axis(0)); } if invert_axis & 0b10 != 0 { a.invert_axis(Axis(1)); } let acopy = a.clone(); let mut b = Array::uninit(a.dim()); a.move_into_uninit(b.view_mut()); let b = unsafe { b.assume_init() }; assert_eq!(acopy, b); } } } } #[test] fn move_into_slicing() { // Count correct number of drops when using move_into_uninit and discontiguous arrays (with holes). for &use_f_order in &[false, true] { for &invert_axis in &[0b00, 0b01, 0b10, 0b11] { // bitmask for axis to invert let counter = DropCounter::default(); { let (m, n) = (5, 4); let mut a = Array::from_shape_fn((m, n).set_f(use_f_order), |_idx| counter.element()); a.slice_collapse(s![1..-1, ..;2]); if invert_axis & 0b01 != 0 { a.invert_axis(Axis(0)); } if invert_axis & 0b10 != 0 { a.invert_axis(Axis(1)); } let mut b = Array::uninit(a.dim()); a.move_into_uninit(b.view_mut()); let b = unsafe { b.assume_init() }; let total = m * n; let dropped_1 = total - (m - 2) * (n - 2); assert_eq!(counter.created(), total); assert_eq!(counter.dropped(), dropped_1); drop(b); } counter.assert_drop_count(); } } } #[test] fn move_into_diag() { // Count correct number of drops when using move_into_uninit and discontiguous arrays (with holes). for &use_f_order in &[false, true] { let counter = DropCounter::default(); { let (m, n) = (5, 4); let a = Array::from_shape_fn((m, n).set_f(use_f_order), |_idx| counter.element()); let a = a.into_diag(); let mut b = Array::uninit(a.dim()); a.move_into_uninit(b.view_mut()); let b = unsafe { b.assume_init() }; let total = m * n; let dropped_1 = total - Ord::min(m, n); assert_eq!(counter.created(), total); assert_eq!(counter.dropped(), dropped_1); drop(b); } counter.assert_drop_count(); } } #[test] fn move_into_0dim() { // Count correct number of drops when using move_into_uninit and discontiguous arrays (with holes). for &use_f_order in &[false, true] { let counter = DropCounter::default(); { let (m, n) = (5, 4); // slice into a 0-dim array let a = Array::from_shape_fn((m, n).set_f(use_f_order), |_idx| counter.element()); let a = a.slice_move(s![2, 2]); assert_eq!(a.ndim(), 0); let mut b = Array::uninit(a.dim()); a.move_into_uninit(b.view_mut()); let b = unsafe { b.assume_init() }; let total = m * n; let dropped_1 = total - 1; assert_eq!(counter.created(), total); assert_eq!(counter.dropped(), dropped_1); drop(b); } counter.assert_drop_count(); } } #[test] fn move_into_empty() { // Count correct number of drops when using move_into_uninit and discontiguous arrays (with holes). for &use_f_order in &[false, true] { let counter = DropCounter::default(); { let (m, n) = (5, 4); // slice into an empty array; let a = Array::from_shape_fn((m, n).set_f(use_f_order), |_idx| counter.element()); let a = a.slice_move(s![..0, 1..1]); assert!(a.is_empty()); let mut b = Array::uninit(a.dim()); a.move_into_uninit(b.view_mut()); let b = unsafe { b.assume_init() }; let total = m * n; let dropped_1 = total; assert_eq!(counter.created(), total); assert_eq!(counter.dropped(), dropped_1); drop(b); } counter.assert_drop_count(); } } #[test] fn move_into() { // Test various memory layouts and holes while moving String elements with move_into for &use_f_order in &[false, true] { for &invert_axis in &[0b00, 0b01, 0b10, 0b11] { // bitmask for axis to invert for &slice in &[false, true] { let mut a = Array::from_shape_fn((5, 4).set_f(use_f_order), |idx| format!("{:?}", idx)); if slice { a.slice_collapse(s![1..-1, ..;2]); } if invert_axis & 0b01 != 0 { a.invert_axis(Axis(0)); } if invert_axis & 0b10 != 0 { a.invert_axis(Axis(1)); } let acopy = a.clone(); let mut b = Array::default(a.dim().set_f(!use_f_order ^ !slice)); a.move_into(&mut b); assert_eq!(acopy, b); } } } } /// This counter can create elements, and then count and verify /// the number of which have actually been dropped again. #[derive(Default)] struct DropCounter { created: AtomicUsize, dropped: AtomicUsize, } struct Element<'a>(&'a AtomicUsize); impl DropCounter { fn created(&self) -> usize { self.created.load(Ordering::Relaxed) } fn dropped(&self) -> usize { self.dropped.load(Ordering::Relaxed) } fn element(&self) -> Element<'_> { self.created.fetch_add(1, Ordering::Relaxed); Element(&self.dropped) } fn assert_drop_count(&self) { assert_eq!( self.created(), self.dropped(), "Expected {} dropped elements, but found {}", self.created(), self.dropped() ); } } impl<'a> Drop for Element<'a> { fn drop(&mut self) { self.0.fetch_add(1, Ordering::Relaxed); } }