diff --git a/src/dimension/mod.rs b/src/dimension/mod.rs index 7db7fc88c..6b86af653 100644 --- a/src/dimension/mod.rs +++ b/src/dimension/mod.rs @@ -545,7 +545,7 @@ fn slice_min_max(axis_len: usize, slice: Slice) -> Option<(usize, usize)> { } /// Returns `true` iff the slices intersect. -#[doc(hidden)] +#[allow(dead_code)] pub fn slices_intersect( dim: &D, indices1: &D::SliceArg, diff --git a/src/lib.rs b/src/lib.rs index 2c5b0f742..18d0938cc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -118,18 +118,13 @@ use std::marker::PhantomData; use std::sync::Arc; pub use crate::dimension::dim::*; -pub use crate::dimension::{ - slices_intersect, Axis, AxisDescription, Dimension, IntoDimension, RemoveAxis, -}; +pub use crate::dimension::{Axis, AxisDescription, Dimension, IntoDimension, RemoveAxis}; pub use crate::dimension::IxDynImpl; pub use crate::dimension::NdIndex; pub use crate::error::{ErrorKind, ShapeError}; pub use crate::indexes::{indices, indices_of}; -pub use crate::slice::{ - deref_raw_view_mut_into_view_mut_with_life, deref_raw_view_mut_into_view_with_life, - life_of_view_mut, Slice, SliceInfo, SliceNextDim, SliceOrIndex, -}; +pub use crate::slice::{Slice, SliceInfo, SliceNextDim, SliceOrIndex}; use crate::iterators::Baseiter; use crate::iterators::{ElementsBase, ElementsBaseMut, Iter, IterMut, Lanes, LanesMut}; @@ -478,13 +473,10 @@ pub type Ixs = isize; /// [`.slice_move()`]: #method.slice_move /// [`.slice_collapse()`]: #method.slice_collapse /// -/// It's possible to take multiple simultaneous *mutable* slices with the -/// [`multislice!()`](macro.multislice!.html) macro. -/// /// ``` /// extern crate ndarray; /// -/// use ndarray::{arr2, arr3, multislice, s}; +/// use ndarray::{arr2, arr3, s}; /// /// fn main() { /// @@ -531,20 +523,6 @@ pub type Ixs = isize; /// [12, 11, 10]]); /// assert_eq!(f, g); /// assert_eq!(f.shape(), &[2, 3]); -/// -/// // Let's take two disjoint, mutable slices of a matrix with -/// // -/// // - One containing all the even-index columns in the matrix -/// // - One containing all the odd-index columns in the matrix -/// let mut h = arr2(&[[0, 1, 2, 3], -/// [4, 5, 6, 7]]); -/// let (s0, s1) = multislice!(h, mut [.., ..;2], mut [.., 1..;2]); -/// let i = arr2(&[[0, 2], -/// [4, 6]]); -/// let j = arr2(&[[1, 3], -/// [5, 7]]); -/// assert_eq!(s0, i); -/// assert_eq!(s1, j); /// } /// ``` /// diff --git a/src/slice.rs b/src/slice.rs index 349e1fa85..1d0dfa2b0 100644 --- a/src/slice.rs +++ b/src/slice.rs @@ -6,7 +6,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. use crate::error::{ErrorKind, ShapeError}; -use crate::{ArrayView, ArrayViewMut, Dimension, RawArrayViewMut}; +use crate::Dimension; use std::fmt; use std::marker::PhantomData; use std::ops::{Deref, Range, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive}; @@ -629,377 +629,3 @@ macro_rules! s( &*&$crate::s![@parse ::std::marker::PhantomData::<$crate::Ix0>, [] $($t)*] }; ); - -/// Returns a ZST representing the lifetime of the mutable view. -#[doc(hidden)] -pub fn life_of_view_mut<'a, A, D: Dimension>( - _view: &ArrayViewMut<'a, A, D>, -) -> PhantomData<&'a mut A> { - PhantomData -} - -/// Derefs the raw mutable view into a view, using the given lifetime. -#[doc(hidden)] -pub unsafe fn deref_raw_view_mut_into_view_with_life<'a, A, D: Dimension>( - raw: RawArrayViewMut, - _life: PhantomData<&'a mut A>, -) -> ArrayView<'a, A, D> { - raw.deref_into_view() -} - -/// Derefs the raw mutable view into a mutable view, using the given lifetime. -#[doc(hidden)] -pub unsafe fn deref_raw_view_mut_into_view_mut_with_life<'a, A, D: Dimension>( - raw: RawArrayViewMut, - _life: PhantomData<&'a mut A>, -) -> ArrayViewMut<'a, A, D> { - raw.deref_into_view_mut() -} - -/// Take multiple slices simultaneously. -/// -/// This macro makes it possible to take multiple slices of the same array, as -/// long as Rust's aliasing rules are followed for *elements* in the slices. -/// For example, it's possible to take two disjoint, mutable slices of an -/// array, with one referencing the even-index elements and the other -/// referencing the odd-index elements. If you tried to achieve this by calling -/// `.slice_mut()` twice, the borrow checker would complain about mutably -/// borrowing the array twice (even though it's safe as long as the slices are -/// disjoint). -/// -/// The syntax is `multislice!(` *expression, pattern [, pattern [, …]]* `)`, -/// where *expression* evaluates to a mutable array, and each *pattern* is -/// either -/// -/// * `mut` *s-args-or-expr*: creates an `ArrayViewMut` or -/// * *s-args-or-expr*: creates an `ArrayView` -/// -/// where *s-args-or-expr* is either (1) arguments enclosed in `[]` to pass to -/// the [`s!`] macro to create a `&SliceInfo` instance or (2) an expression -/// that evaluates to a `&SliceInfo` instance. -/// -/// **Note** that this macro always mutably borrows the array even if there are -/// no `mut` patterns. If all you want to do is take read-only slices, you -/// don't need `multislice!()`; just call -/// [`.slice()`](struct.ArrayBase.html#method.slice) multiple times instead. -/// -/// `multislice!()` evaluates to a tuple of `ArrayView` and/or `ArrayViewMut` -/// instances. It checks Rust's aliasing rules: -/// -/// * An `ArrayViewMut` and `ArrayView` cannot reference the same element. -/// * Two `ArrayViewMut` cannot reference the same element. -/// * Two `ArrayView` can reference the same element. -/// -/// **Panics** at runtime if any of the aliasing rules is violated. -/// -/// See also [*Slicing*](struct.ArrayBase.html#slicing). -/// -/// # Examples -/// -/// In this example, there are two overlapping read-only slices, and two -/// disjoint mutable slices. Neither of the mutable slices intersects any of -/// the other slices. -/// -/// ``` -/// extern crate ndarray; -/// -/// use ndarray::multislice; -/// use ndarray::prelude::*; -/// -/// # fn main() { -/// let mut arr: Array1<_> = (0..12).collect(); -/// let (a, b, c, d) = multislice!(arr, [0..5], mut [6..;2], [1..6], mut [7..;2]); -/// assert_eq!(a, array![0, 1, 2, 3, 4]); -/// assert_eq!(b, array![6, 8, 10]); -/// assert_eq!(c, array![1, 2, 3, 4, 5]); -/// assert_eq!(d, array![7, 9, 11]); -/// # } -/// ``` -/// -/// These examples panic because they don't follow the aliasing rules: -/// -/// * `ArrayViewMut` and `ArrayView` cannot reference the same element. -/// -/// ```should_panic -/// # extern crate ndarray; -/// # use ndarray::multislice; -/// # use ndarray::prelude::*; -/// # fn main() { -/// let mut arr: Array1<_> = (0..12).collect(); -/// multislice!(arr, [0..5], mut [1..;2]); // panic! -/// # } -/// ``` -/// -/// * Two `ArrayViewMut` cannot reference the same element. -/// -/// ```should_panic -/// # extern crate ndarray; -/// # use ndarray::multislice; -/// # use ndarray::prelude::*; -/// # fn main() { -/// let mut arr: Array1<_> = (0..12).collect(); -/// multislice!(arr, mut [0..5], mut [1..;2]); // panic! -/// # } -/// ``` -#[macro_export] -macro_rules! multislice( - (@check $view:expr, $info:expr, ()) => {}; - // Check that $info doesn't intersect $other. - (@check $view:expr, $info:expr, ($other:expr,)) => { - assert!( - !$crate::slices_intersect(&$view.raw_dim(), $info, $other), - "Slice {:?} must not intersect slice {:?}", $info, $other - ) - }; - // Check that $info doesn't intersect any of the other info in the tuple. - (@check $view:expr, $info:expr, ($other:expr, $($more:tt)*)) => { - { - $crate::multislice!(@check $view, $info, ($other,)); - $crate::multislice!(@check $view, $info, ($($more)*)); - } - }; - // Create the (mutable) slice. - (@slice $view:expr, $life:expr, mut $info:expr) => { - #[allow(unsafe_code)] - unsafe { - $crate::deref_raw_view_mut_into_view_mut_with_life( - $view.clone().slice_move($info), - $life, - ) - } - }; - // Create the (read-only) slice. - (@slice $view:expr, $life:expr, $info:expr) => { - #[allow(unsafe_code)] - unsafe { - $crate::deref_raw_view_mut_into_view_with_life( - $view.clone().slice_move($info), - $life, - ) - } - }; - // Parse last slice (mutable), no trailing comma, applying `s![]` macro. - ( - @parse $view:expr, $life:expr, - ($($sliced:tt)*), - ($($mut_info:tt)*), - ($($immut_info:tt)*), - (mut [$($info:tt)*]) - ) => { - // Apply `s![]` macro to info. - $crate::multislice!( - @parse $view, $life, - ($($sliced)*), - ($($mut_info)*), - ($($immut_info)*), - (mut $crate::s![$($info)*],) - ) - }; - // Parse last slice (read-only), no trailing comma, applying `s![]` macro. - ( - @parse $view:expr, $life:expr, - ($($sliced:tt)*), - ($($mut_info:tt)*), - ($($immut_info:tt)*), - ([$($info:tt)*]) - ) => { - // Apply `s![]` macro to info. - $crate::multislice!( - @parse $view, $life, - ($($sliced)*), - ($($mut_info)*), - ($($immut_info)*), - ($crate::s![$($info)*],) - ) - }; - // Parse last slice (mutable), with trailing comma, applying `s![]` macro. - ( - @parse $view:expr, $life:expr, - ($($sliced:tt)*), - ($($mut_info:tt)*), - ($($immut_info:tt)*), - (mut [$($info:tt)*],) - ) => { - // Apply `s![]` macro to info. - $crate::multislice!( - @parse $view, $life, - ($($sliced)*), - ($($mut_info)*), - ($($immut_info)*), - (mut $crate::s![$($info)*],) - ) - }; - // Parse last slice (read-only), with trailing comma, applying `s![]` macro. - ( - @parse $view:expr, $life:expr, - ($($sliced:tt)*), - ($($mut_info:tt)*), - ($($immut_info:tt)*), - ([$($info:tt)*],) - ) => { - // Apply `s![]` macro to info. - $crate::multislice!( - @parse $view, $life, - ($($sliced)*), - ($($mut_info)*), - ($($immut_info)*), - ($crate::s![$($info)*],) - ) - }; - // Parse a mutable slice, applying `s![]` macro. - ( - @parse $view:expr, $life:expr, - ($($sliced:tt)*), - ($($mut_info:tt)*), - ($($immut_info:tt)*), - (mut [$($info:tt)*], $($t:tt)*) - ) => { - // Apply `s![]` macro to info. - $crate::multislice!( - @parse $view, $life, - ($($sliced)*), - ($($mut_info)*), - ($($immut_info)*), - (mut $crate::s![$($info)*], $($t)*) - ) - }; - // Parse a read-only slice, applying `s![]` macro. - ( - @parse $view:expr, $life:expr, - ($($sliced:tt)*), - ($($mut_info:tt)*), - ($($immut_info:tt)*), - ([$($info:tt)*], $($t:tt)*) - ) => { - // Apply `s![]` macro to info. - $crate::multislice!( - @parse $view, $life, - ($($sliced)*), - ($($mut_info)*), - ($($immut_info)*), - ($crate::s![$($info)*], $($t)*) - ) - }; - // Parse last slice (mutable), no trailing comma. - ( - @parse $view:expr, $life:expr, - ($($sliced:tt)*), - ($($mut_info:tt)*), - ($($immut_info:tt)*), - (mut $info:expr) - ) => { - // Add trailing comma. - $crate::multislice!( - @parse $view, $life, - ($($sliced)*), - ($($mut_info)*), - ($($immut_info)*), - (mut $info,) - ) - }; - // Parse last slice (read-only), no trailing comma. - ( - @parse $view:expr, $life:expr, - ($($sliced:tt)*), - ($($mut_info:tt)*), - ($($immut_info:tt)*), - ($info:expr) - ) => { - // Add trailing comma. - $crate::multislice!( - @parse $view, $life, - ($($sliced)*), - ($($mut_info)*), - ($($immut_info)*), - ($info,) - ) - }; - // Parse last slice (mutable), with trailing comma. - ( - @parse $view:expr, $life:expr, - ($($sliced:tt)*), - ($($mut_info:tt)*), - ($($immut_info:tt)*), - (mut $info:expr,) - ) => { - match $info { - info => { - // Check for overlap with all previous mutable and immutable slices. - $crate::multislice!(@check $view, info, ($($mut_info)*)); - $crate::multislice!(@check $view, info, ($($immut_info)*)); - ($($sliced)* $crate::multislice!(@slice $view, $life, mut info),) - } - } - }; - // Parse last slice (read-only), with trailing comma. - ( - @parse $view:expr, $life:expr, - ($($sliced:tt)*), - ($($mut_info:tt)*), - ($($immut_info:tt)*), - ($info:expr,) - ) => { - match $info { - info => { - // Check for overlap with all previous mutable slices. - $crate::multislice!(@check $view, info, ($($mut_info)*)); - ($($sliced)* $crate::multislice!(@slice $view, $life, info),) - } - } - }; - // Parse a mutable slice. - ( - @parse $view:expr, $life:expr, - ($($sliced:tt)*), - ($($mut_info:tt)*), - ($($immut_info:tt)*), - (mut $info:expr, $($t:tt)*) - ) => { - match $info { - info => { - // Check for overlap with all previous mutable and immutable slices. - $crate::multislice!(@check $view, info, ($($mut_info)*)); - $crate::multislice!(@check $view, info, ($($immut_info)*)); - $crate::multislice!( - @parse $view, $life, - ($($sliced)* $crate::multislice!(@slice $view, $life, mut info),), - ($($mut_info)* info,), - ($($immut_info)*), - ($($t)*) - ) - } - } - }; - // Parse a read-only slice. - ( - @parse $view:expr, $life:expr, - ($($sliced:tt)*), - ($($mut_info:tt)*), - ($($immut_info:tt)*), - ($info:expr, $($t:tt)*) - ) => { - match $info { - info => { - // Check for overlap with all previous mutable slices. - $crate::multislice!(@check $view, info, ($($mut_info)*)); - $crate::multislice!( - @parse $view, $life, - ($($sliced)* $crate::multislice!(@slice $view, $life, info),), - ($($mut_info)*), - ($($immut_info)* info,), - ($($t)*) - ) - } - } - }; - // Entry point. - ($arr:expr, $($t:tt)*) => { - { - let (life, raw_view) = { - let mut view = $crate::ArrayBase::view_mut(&mut $arr); - ($crate::life_of_view_mut(&view), view.raw_view_mut()) - }; - $crate::multislice!(@parse raw_view, life, (), (), (), ($($t)*)) - } - }; -); diff --git a/tests/array.rs b/tests/array.rs index 692dd744b..ea374bc7c 100644 --- a/tests/array.rs +++ b/tests/array.rs @@ -11,24 +11,10 @@ use defmac::defmac; use itertools::{enumerate, zip, Itertools}; use ndarray::indices; use ndarray::prelude::*; -use ndarray::{arr3, multislice, rcarr2}; +use ndarray::{arr3, rcarr2}; use ndarray::{Slice, SliceInfo, SliceOrIndex}; use std::iter::FromIterator; -macro_rules! assert_panics { - ($body:expr) => { - if let Ok(v) = ::std::panic::catch_unwind(|| $body) { - panic!("assertion failed: should_panic; \ - non-panicking result: {:?}", v); - } - }; - ($body:expr, $($arg:tt)*) => { - if let Ok(_) = ::std::panic::catch_unwind(|| $body) { - panic!($($arg)*); - } - }; -} - #[test] fn test_matmul_arcarray() { let mut A = ArcArray::::zeros((2, 3)); @@ -342,139 +328,6 @@ fn test_slice_collapse_with_indices() { assert_eq!(vi, Array3::from_elem((1, 1, 1), elem)); } -#[test] -#[allow(clippy::cognitive_complexity)] -fn test_multislice() { - defmac!(test_multislice mut arr, s1, s2 => { - { - let copy = arr.clone(); - assert_eq!( - multislice!(arr, mut s1, mut s2,), - (copy.clone().slice_mut(s1), copy.clone().slice_mut(s2)) - ); - } - { - let copy = arr.clone(); - assert_eq!( - multislice!(arr, mut s1, s2,), - (copy.clone().slice_mut(s1), copy.clone().slice(s2)) - ); - } - { - let copy = arr.clone(); - assert_eq!( - multislice!(arr, s1, mut s2), - (copy.clone().slice(s1), copy.clone().slice_mut(s2)) - ); - } - { - let copy = arr.clone(); - assert_eq!( - multislice!(arr, s1, s2), - (copy.clone().slice(s1), copy.clone().slice(s2)) - ); - } - }); - let mut arr = Array1::from_iter(0..48).into_shape((8, 6)).unwrap(); - - assert_eq!((arr.clone().view(),), multislice!(arr, [.., ..])); - test_multislice!(&mut arr, s![0, ..], s![1, ..]); - test_multislice!(&mut arr, s![0, ..], s![-1, ..]); - test_multislice!(&mut arr, s![0, ..], s![1.., ..]); - test_multislice!(&mut arr, s![1, ..], s![..;2, ..]); - test_multislice!(&mut arr, s![..2, ..], s![2.., ..]); - test_multislice!(&mut arr, s![1..;2, ..], s![..;2, ..]); - test_multislice!(&mut arr, s![..;-2, ..], s![..;2, ..]); - test_multislice!(&mut arr, s![..;12, ..], s![3..;3, ..]); -} - -#[test] -fn test_multislice_intersecting() { - assert_panics!({ - let mut arr = Array2::::zeros((8, 6)); - multislice!(arr, mut [3, ..], [3, ..]); - }); - assert_panics!({ - let mut arr = Array2::::zeros((8, 6)); - multislice!(arr, mut [3, ..], [3.., ..]); - }); - assert_panics!({ - let mut arr = Array2::::zeros((8, 6)); - multislice!(arr, mut [3, ..], [..;3, ..]); - }); - assert_panics!({ - let mut arr = Array2::::zeros((8, 6)); - multislice!(arr, mut [..;6, ..], [3..;3, ..]); - }); - assert_panics!({ - let mut arr = Array2::::zeros((8, 6)); - multislice!(arr, mut [2, ..], mut [..-1;-2, ..]); - }); - { - let mut arr = Array2::::zeros((8, 6)); - multislice!(arr, [3, ..], [-1..;-2, ..]); - } -} - -#[test] -fn test_multislice_eval_args_only_once() { - let mut arr = Array1::::zeros(10); - let mut eval_count = 0; - { - let mut slice = || { - eval_count += 1; - *s![1..2] - }; - multislice!(arr, mut &slice(), [3..4], [5..6]); - } - assert_eq!(eval_count, 1); - let mut eval_count = 0; - { - let mut slice = || { - eval_count += 1; - *s![1..2] - }; - multislice!(arr, [3..4], mut &slice(), [5..6]); - } - assert_eq!(eval_count, 1); - let mut eval_count = 0; - { - let mut slice = || { - eval_count += 1; - *s![1..2] - }; - multislice!(arr, [3..4], [5..6], mut &slice()); - } - assert_eq!(eval_count, 1); - let mut eval_count = 0; - { - let mut slice = || { - eval_count += 1; - *s![1..2] - }; - multislice!(arr, &slice(), mut [3..4], [5..6]); - } - assert_eq!(eval_count, 1); - let mut eval_count = 0; - { - let mut slice = || { - eval_count += 1; - *s![1..2] - }; - multislice!(arr, mut [3..4], &slice(), [5..6]); - } - assert_eq!(eval_count, 1); - let mut eval_count = 0; - { - let mut slice = || { - eval_count += 1; - *s![1..2] - }; - multislice!(arr, mut [3..4], [5..6], &slice()); - } - assert_eq!(eval_count, 1); -} - #[should_panic] #[test] fn index_out_of_bounds() {