From 03a34a901a17687768041705ecc27809a86d2250 Mon Sep 17 00:00:00 2001 From: Jim Turner Date: Wed, 18 Oct 2017 20:22:22 -0400 Subject: [PATCH 01/30] Add slicing with subviews --- src/dimension/dimension_trait.rs | 173 +++++++++++++---------- src/dimension/mod.rs | 2 +- src/impl_methods.rs | 131 +++++++++++++++--- src/lib.rs | 24 +++- src/si.rs | 228 ++++++++++++++++++++++++++++--- tests/array.rs | 84 ++++++++++-- tests/iterators.rs | 14 +- tests/oper.rs | 4 +- 8 files changed, 527 insertions(+), 133 deletions(-) diff --git a/src/dimension/dimension_trait.rs b/src/dimension/dimension_trait.rs index bc288e178..eba879354 100644 --- a/src/dimension/dimension_trait.rs +++ b/src/dimension/dimension_trait.rs @@ -7,13 +7,14 @@ // except according to those terms. +use std::borrow::Borrow; use std::fmt::Debug; use std::ops::{Index, IndexMut}; use std::ops::{Add, Sub, Mul, AddAssign, SubAssign, MulAssign}; use itertools::{enumerate, zip}; -use {Ix, Ixs, Ix0, Ix1, Ix2, Ix3, Ix4, Ix5, Ix6, IxDyn, Dim, Si, IxDynImpl}; +use {Ix, Ixs, Ix0, Ix1, Ix2, Ix3, Ix4, Ix5, Ix6, IxDyn, Dim, Si, SliceOrIndex, IxDynImpl}; use IntoDimension; use RemoveAxis; use {ArrayView1, ArrayViewMut1}; @@ -45,17 +46,16 @@ pub trait Dimension : Clone + Eq + Debug + Send + Sync + Default + /// dimension. /// /// For the fixed size dimensions it is a fixed size array of the correct - /// size, which you pass by reference. For the dynamic dimension it is - /// a slice. + /// size. For the dynamic dimension it is a slice. /// - /// - For `Ix1`: `[Si; 1]` - /// - For `Ix2`: `[Si; 2]` + /// - For `Ix1`: `[SliceOrIndex; 1]` + /// - For `Ix2`: `[SliceOrIndex; 2]` /// - and so on.. - /// - For `IxDyn`: `[Si]` + /// - For `IxDyn`: `[SliceOrIndex]` /// - /// The easiest way to create a `&SliceArg` is using the macro + /// The easiest way to create a `SliceArg` is using the macro /// [`s![]`](macro.s!.html). - type SliceArg: ?Sized + AsRef<[Si]>; + type SliceArg: ?Sized + Borrow<[SliceOrIndex]>; /// Pattern matching friendly form of the dimension value. /// /// - For `Ix1`: `usize`, @@ -152,6 +152,15 @@ pub trait Dimension : Clone + Eq + Debug + Send + Sync + Default + Self::default() } + #[doc(hidden)] + /// Return an index of same type and with the specified dimensionality. + /// + /// This method is useful for generalizing over fixed-size and + /// variable-size dimension representations. + /// + /// **Panics** if `Self` has a fixed size that is not `ndim`. + fn zero_index_with_ndim(ndim: usize) -> Self; + #[doc(hidden)] #[inline] fn first_index(&self) -> Option { @@ -240,65 +249,60 @@ pub trait Dimension : Clone + Eq + Debug + Send + Sync + Default + } #[doc(hidden)] - /// Modify dimension, strides and return data pointer offset + /// Modify dimension, stride and return data pointer offset /// - /// **Panics** if `slices` does not correspond to the number of axes, - /// if any stride is 0, or if any index is out of bounds. - fn do_slices(dim: &mut Self, strides: &mut Self, slices: &Self::SliceArg) -> isize { - let slices = slices.as_ref(); + /// **Panics** if any stride is 0 or if any index is out of bounds. + fn do_slice(dim: &mut Ix, stride: &mut Ix, slice: &Si) -> isize { let mut offset = 0; - ndassert!(slices.len() == dim.slice().len(), - "SliceArg {:?}'s length does not match dimension {:?}", - slices, dim); - for (dr, sr, &slc) in izip!(dim.slice_mut(), strides.slice_mut(), slices) { - let m = *dr; - let mi = m as Ixs; - let Si(b1, opt_e1, s1) = slc; - let e1 = opt_e1.unwrap_or(mi); - - let b1 = abs_index(mi, b1); - let mut e1 = abs_index(mi, e1); - if e1 < b1 { e1 = b1; } - - ndassert!(b1 <= m, - concat!("Slice begin {} is past end of axis of length {}", - " (for SliceArg {:?})"), - b1, m, slices); - ndassert!(e1 <= m, - concat!("Slice end {} is past end of axis of length {}", - " (for SliceArg {:?})"), - e1, m, slices); - - let m = e1 - b1; - // stride - let s = (*sr) as Ixs; - - // Data pointer offset - offset += stride_offset(b1, *sr); - // Adjust for strides - ndassert!(s1 != 0, - concat!("Slice stride must not be none", - "(for SliceArg {:?})"), - slices); - // How to implement negative strides: - // - // Increase start pointer by - // old stride * (old dim - 1) - // to put the pointer completely in the other end - if s1 < 0 { - offset += stride_offset(m - 1, *sr); - } + let dr = dim; + let sr = stride; + let slc = *slice; + + let m = *dr; + let mi = m as Ixs; + let Si(b1, opt_e1, s1) = slc; + let e1 = opt_e1.unwrap_or(mi); + + let b1 = abs_index(mi, b1); + let mut e1 = abs_index(mi, e1); + if e1 < b1 { e1 = b1; } + + ndassert!(b1 <= m, + "Slice begin {} is past end of axis of length {} (for Si {:?})", + b1, m, slice); + ndassert!(e1 <= m, + "Slice end {} is past end of axis of length {} (for Si {:?})", + e1, m, slice); + + let m = e1 - b1; + // stride + let s = (*sr) as Ixs; + + // Data pointer offset + offset += stride_offset(b1, *sr); + // Adjust for strides + ndassert!(s1 != 0, + "Slice stride must not be none (for Si {:?})", + slice); + // How to implement negative strides: + // + // Increase start pointer by + // old stride * (old dim - 1) + // to put the pointer completely in the other end + if s1 < 0 { + offset += stride_offset(m - 1, *sr); + } - let s_prim = s * s1; + let s_prim = s * s1; - let d = m / s1.abs() as Ix; - let r = m % s1.abs() as Ix; - let m_prim = d + if r > 0 { 1 } else { 0 }; + let d = m / s1.abs() as Ix; + let r = m % s1.abs() as Ix; + let m_prim = d + if r > 0 { 1 } else { 0 }; + + // Update dimension and stride coordinate + *dr = m_prim; + *sr = s_prim as Ix; - // Update dimension and stride coordinate - *dr = m_prim; - *sr = s_prim as Ix; - } offset } @@ -401,7 +405,7 @@ pub trait Dimension : Clone + Eq + Debug + Send + Sync + Default + // utility functions #[inline] -fn abs_index(len: Ixs, index: Ixs) -> Ix { +pub fn abs_index(len: Ixs, index: Ixs) -> Ix { if index < 0 { (len + index) as Ix } else { @@ -425,7 +429,7 @@ macro_rules! impl_insert_axis_array( ); impl Dimension for Dim<[Ix; 0]> { - type SliceArg = [Si; 0]; + type SliceArg = [SliceOrIndex; 0]; type Pattern = (); type Smaller = Self; type Larger = Ix1; @@ -441,6 +445,11 @@ impl Dimension for Dim<[Ix; 0]> { #[inline] fn into_pattern(self) -> Self::Pattern { } #[inline] + fn zero_index_with_ndim(ndim: usize) -> Self { + assert_eq!(ndim, 0); + Self::default() + } + #[inline] fn next_for(&self, _index: Self) -> Option { None } @@ -456,7 +465,7 @@ impl Dimension for Dim<[Ix; 0]> { impl Dimension for Dim<[Ix; 1]> { - type SliceArg = [Si; 1]; + type SliceArg = [SliceOrIndex; 1]; type Pattern = Ix; type Smaller = Ix0; type Larger = Ix2; @@ -471,6 +480,11 @@ impl Dimension for Dim<[Ix; 1]> { get!(&self, 0) } #[inline] + fn zero_index_with_ndim(ndim: usize) -> Self { + assert_eq!(ndim, 1); + Self::default() + } + #[inline] fn next_for(&self, mut index: Self) -> Option { getm!(index, 0) += 1; if get!(&index, 0) < get!(self, 0) { @@ -544,7 +558,7 @@ impl Dimension for Dim<[Ix; 1]> { } impl Dimension for Dim<[Ix; 2]> { - type SliceArg = [Si; 2]; + type SliceArg = [SliceOrIndex; 2]; type Pattern = (Ix, Ix); type Smaller = Ix1; type Larger = Ix3; @@ -559,6 +573,11 @@ impl Dimension for Dim<[Ix; 2]> { #[inline] fn slice_mut(&mut self) -> &mut [Ix] { self.ixm() } #[inline] + fn zero_index_with_ndim(ndim: usize) -> Self { + assert_eq!(ndim, 2); + Self::default() + } + #[inline] fn next_for(&self, index: Self) -> Option { let mut i = get!(&index, 0); let mut j = get!(&index, 1); @@ -674,7 +693,7 @@ impl Dimension for Dim<[Ix; 2]> { } impl Dimension for Dim<[Ix; 3]> { - type SliceArg = [Si; 3]; + type SliceArg = [SliceOrIndex; 3]; type Pattern = (Ix, Ix, Ix); type Smaller = Ix2; type Larger = Ix4; @@ -697,6 +716,12 @@ impl Dimension for Dim<[Ix; 3]> { m as usize * n as usize * o as usize } + #[inline] + fn zero_index_with_ndim(ndim: usize) -> Self { + assert_eq!(ndim, 3); + Self::default() + } + #[inline] fn next_for(&self, index: Self) -> Option { let mut i = get!(&index, 0); @@ -785,7 +810,7 @@ impl Dimension for Dim<[Ix; 3]> { macro_rules! large_dim { ($n:expr, $name:ident, $pattern:ty, $larger:ty, { $($insert_axis:tt)* }) => ( impl Dimension for Dim<[Ix; $n]> { - type SliceArg = [Si; $n]; + type SliceArg = [SliceOrIndex; $n]; type Pattern = $pattern; type Smaller = Dim<[Ix; $n - 1]>; type Larger = $larger; @@ -800,6 +825,11 @@ macro_rules! large_dim { #[inline] fn slice_mut(&mut self) -> &mut [Ix] { self.ixm() } #[inline] + fn zero_index_with_ndim(ndim: usize) -> Self { + assert_eq!(ndim, $n); + Self::default() + } + #[inline] $($insert_axis)* #[inline] fn try_remove_axis(&self, axis: Axis) -> Self::Smaller { @@ -831,7 +861,7 @@ large_dim!(6, Ix6, (Ix, Ix, Ix, Ix, Ix, Ix), IxDyn, { /// and memory wasteful, but it allows an arbitrary and dynamic number of axes. impl Dimension for IxDyn { - type SliceArg = [Si]; + type SliceArg = [SliceOrIndex]; type Pattern = Self; type Smaller = Self; type Larger = Self; @@ -851,6 +881,11 @@ impl Dimension for IxDyn IxDyn::zeros(self.ndim()) } + #[inline] + fn zero_index_with_ndim(ndim: usize) -> Self { + IxDyn::zeros(ndim) + } + #[inline] fn insert_axis(&self, axis: Axis) -> Self::Larger { debug_assert!(axis.index() <= self.ndim()); diff --git a/src/dimension/mod.rs b/src/dimension/mod.rs index 541f96429..41e192f24 100644 --- a/src/dimension/mod.rs +++ b/src/dimension/mod.rs @@ -12,7 +12,7 @@ use error::{from_kind, ErrorKind, ShapeError}; pub use self::dim::*; pub use self::axis::Axis; pub use self::conversion::IntoDimension; -pub use self::dimension_trait::Dimension; +pub use self::dimension_trait::{abs_index, Dimension}; pub use self::ndindex::NdIndex; pub use self::remove_axis::RemoveAxis; pub use self::axes::{axes_of, Axes, AxisDescription}; diff --git a/src/impl_methods.rs b/src/impl_methods.rs index 052c31cec..be27ea8fb 100644 --- a/src/impl_methods.rs +++ b/src/impl_methods.rs @@ -6,6 +6,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use std::borrow::Borrow; use std::cmp; use std::ptr as std_ptr; use std::slice; @@ -19,7 +20,7 @@ use dimension; use iterators; use error::{self, ShapeError, ErrorKind}; use dimension::IntoDimension; -use dimension::{axes_of, Axes, merge_axes, stride_offset}; +use dimension::{abs_index, axes_of, Axes, merge_axes, stride_offset}; use iterators::{ new_lanes, new_lanes_mut, @@ -31,6 +32,9 @@ use zip::Zip; use { NdIndex, + Si, + SliceInfo, + SliceOrIndex }; use iter::{ AxisChunksIter, @@ -214,11 +218,14 @@ impl ArrayBase where S: Data, D: Dimension /// [`D::SliceArg`]: trait.Dimension.html#associatedtype.SliceArg /// /// **Panics** if an index is out of bounds or stride is zero.
- /// (**Panics** if `D` is `IxDyn` and `indexes` does not match the number of array axes.) - pub fn slice(&self, indexes: &D::SliceArg) -> ArrayView { - let mut arr = self.view(); - arr.islice(indexes); - arr + /// (**Panics** if `D` is `IxDyn` and `info` does not match the number of array axes.) + pub fn slice(&self, info: I) -> ArrayView + where + I: Borrow>, + T: Borrow, + Do: Dimension, + { + self.view().slice_into(info) } /// Return a sliced read-write view of the array. @@ -228,25 +235,117 @@ impl ArrayBase where S: Data, D: Dimension /// [`D::SliceArg`]: trait.Dimension.html#associatedtype.SliceArg /// /// **Panics** if an index is out of bounds or stride is zero.
- /// (**Panics** if `D` is `IxDyn` and `indexes` does not match the number of array axes.) - pub fn slice_mut(&mut self, indexes: &D::SliceArg) -> ArrayViewMut - where S: DataMut + /// (**Panics** if `D` is `IxDyn` and `info` does not match the number of array axes.) + pub fn slice_mut(&mut self, info: I) -> ArrayViewMut + where + I: Borrow>, + T: Borrow, + Do: Dimension, + S: DataMut, { - let mut arr = self.view_mut(); - arr.islice(indexes); - arr + self.view_mut().slice_into(info) } - /// Slice the array’s view in place. + /// Slice the array’s view, possibly changing the number of dimensions. /// /// See also [`D::SliceArg`]. /// /// [`D::SliceArg`]: trait.Dimension.html#associatedtype.SliceArg /// /// **Panics** if an index is out of bounds or stride is zero.
- /// (**Panics** if `D` is `IxDyn` and `indexes` does not match the number of array axes.) - pub fn islice(&mut self, indexes: &D::SliceArg) { - let offset = D::do_slices(&mut self.dim, &mut self.strides, indexes); + /// (**Panics** if `D` is `IxDyn` and `info` does not match the number of array axes.) + pub fn slice_into(mut self, info: I) -> ArrayBase + where + I: Borrow>, + T: Borrow, + Do: Dimension, + { + let info: &SliceInfo<_, _> = info.borrow(); + let indices: &[SliceOrIndex] = info.indices().borrow().borrow(); + assert_eq!(indices.len(), self.ndim()); + + // Slice and subview in-place without changing the number of dimensions. + self.islice(indices); + + // Copy the dim and strides that remain after removing the subview axes. + let mut new_dim = Do::zero_index_with_ndim(info.out_ndim()); + let mut new_strides = Do::zero_index_with_ndim(info.out_ndim()); + izip!(self.dim.slice(), self.strides.slice(), indices) + .filter_map(|(d, s, slice_or_index)| match slice_or_index { + &SliceOrIndex::Slice(_) => Some((d, s)), + &SliceOrIndex::Index(_) => None, + }) + .zip(izip!(new_dim.slice_mut(), new_strides.slice_mut())) + .for_each(|((d, s), (new_d, new_s))| { + *new_d = *d; + *new_s = *s; + }); + + ArrayBase { + ptr: self.ptr, + data: self.data, + dim: new_dim, + strides: new_strides, + } + } + + /// Slice the array’s view in place without changing the number of dimensions. + /// + /// See also [`D::SliceArg`]. + /// + /// [`D::SliceArg`]: trait.Dimension.html#associatedtype.SliceArg + /// + /// **Panics** if an index is out of bounds or stride is zero.
+ /// (**Panics** if `D` is `IxDyn` and `info` does not match the number of array axes.) + pub fn islice(&mut self, info: I) + where + I: AsRef<[SliceOrIndex]>, + { + assert_eq!(info.as_ref().len(), self.ndim()); + info.as_ref() + .iter() + .enumerate() + .for_each(|(axis, slice_or_index)| match slice_or_index { + &SliceOrIndex::Slice(s) => self.islice_axis(Axis(axis), &s), + &SliceOrIndex::Index(i) => { + let i_usize = abs_index(self.shape()[axis] as Ixs, i); + self.isubview(Axis(axis), i_usize) + } + }); + } + + /// Return a view of the array, sliced along the specified axis. + /// + /// **Panics** if an index is out of bounds or stride is zero.
+ /// **Panics** if `axis` is out of bounds. + pub fn slice_axis(&self, axis: Axis, indices: &Si) -> ArrayView { + let mut arr = self.view(); + arr.islice_axis(axis, indices); + arr + } + + /// Return a mutable view of the array, sliced along the specified axis. + /// + /// **Panics** if an index is out of bounds or stride is zero.
+ /// **Panics** if `axis` is out of bounds. + pub fn slice_axis_mut(&mut self, axis: Axis, indices: &Si) -> ArrayViewMut + where S: DataMut, + { + let mut arr = self.view_mut(); + arr.islice_axis(axis, indices); + arr + } + + /// Slice the array’s view in place along the specified axis. + /// + /// **Panics** if an index is out of bounds or stride is zero.
+ /// **Panics** if `axis` is out of bounds. + pub fn islice_axis(&mut self, axis: Axis, indices: &Si) { + let offset = D::do_slice( + &mut self.dim.slice_mut()[axis.index()], + &mut self.strides.slice_mut()[axis.index()], + indices + ); unsafe { self.ptr = self.ptr.offset(offset); } diff --git a/src/lib.rs b/src/lib.rs index 5dac23cff..1c0fa0adb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -105,7 +105,7 @@ pub use dimension::NdIndex; pub use dimension::IxDynImpl; pub use indexes::{indices, indices_of}; pub use error::{ShapeError, ErrorKind}; -pub use si::{Si, S}; +pub use si::{Si, S, SliceInfo, SliceNextDim, SliceOrIndex}; use iterators::Baseiter; use iterators::{ElementsBase, ElementsBaseMut, Iter, IterMut}; @@ -425,9 +425,9 @@ pub type Ixs = isize; /// `.slice_mut()`. /// /// The slicing argument can be passed using the macro [`s![]`](macro.s!.html), -/// which will be used in all examples. (The explicit form is a reference -/// to a fixed size array of [`Si`]; see its docs for more information.) -/// [`Si`]: struct.Si.html +/// which will be used in all examples. (The explicit form is an instance of +/// struct [`SliceInfo`]; see its docs for more information.) +/// [`SliceInfo`]: struct.SliceInfo.html /// /// ``` /// // import the s![] macro @@ -478,12 +478,17 @@ pub type Ixs = isize; /// /// Subview methods allow you to restrict the array view while removing /// one axis from the array. Subview methods include `.subview()`, -/// `.isubview()`, `.subview_mut()`. +/// `.isubview()`, `.subview_mut()`. You can also take a subview by using a +/// single index instead of a range when slicing. /// /// Subview takes two arguments: `axis` and `index`. /// /// ``` -/// use ndarray::{arr3, aview2, Axis}; +/// #[macro_use(s)] extern crate ndarray; +/// +/// use ndarray::{arr3, aview1, aview2, Axis}; +/// +/// # fn main() { /// /// // 2 submatrices of 2 rows with 3 elements per row, means a shape of `[2, 2, 3]`. /// @@ -513,6 +518,13 @@ pub type Ixs = isize; /// /// assert_eq!(sub_col, aview2(&[[ 1, 4], /// [ 7, 10]])); +/// +/// // You can take multiple subviews at once (and slice at the same time) +/// +/// let double_sub = a.slice(s![1, .., 0]); +/// +/// assert_eq!(double_sub, aview1(&[7, 10])); +/// # } /// ``` /// /// `.isubview()` modifies the view in the same way as `subview()`, but diff --git a/src/si.rs b/src/si.rs index 2e6bc80a1..95b52c82c 100644 --- a/src/si.rs +++ b/src/si.rs @@ -5,9 +5,11 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. +use std::borrow::Borrow; use std::ops::{Range, RangeFrom, RangeTo, RangeFull}; use std::fmt; -use super::Ixs; +use std::marker::PhantomData; +use super::{Dim, Dimension, Ix, IxDyn, Ixs}; // [a:b:s] syntax for example [:3], [::-1] // [0,:] -- first row of matrix @@ -101,11 +103,177 @@ copy_and_clone!{Si} /// Slice value for the full range of an axis. pub const S: Si = Si(0, None, 1); +#[derive(Debug, Eq, PartialEq)] +pub enum SliceOrIndex { + Slice(Si), + Index(Ixs), +} + +copy_and_clone!{SliceOrIndex} + +impl SliceOrIndex { + #[inline] + pub fn step(self, step: Ixs) -> Self { + match self { + SliceOrIndex::Slice(s) => SliceOrIndex::Slice(s.step(step)), + SliceOrIndex::Index(s) => SliceOrIndex::Index(s), + } + } +} + +impl From> for SliceOrIndex { + #[inline] + fn from(r: Range) -> SliceOrIndex { + SliceOrIndex::Slice(Si::from(r)) + } +} + +impl From for SliceOrIndex { + #[inline] + fn from(r: Ixs) -> SliceOrIndex { + SliceOrIndex::Index(r) + } +} + +impl From> for SliceOrIndex { + #[inline] + fn from(r: RangeFrom) -> SliceOrIndex { + SliceOrIndex::Slice(Si::from(r)) + } +} + +impl From> for SliceOrIndex { + #[inline] + fn from(r: RangeTo) -> SliceOrIndex { + SliceOrIndex::Slice(Si::from(r)) + } +} + +impl From for SliceOrIndex { + #[inline] + fn from(r: RangeFull) -> SliceOrIndex { + SliceOrIndex::Slice(Si::from(r)) + } +} + +/// Represents all of the necessary information to perform a slice. +pub struct SliceInfo { + out_dim: PhantomData, + out_ndim: usize, + indices: T, +} + +impl SliceInfo { + /// Returns a new `SliceInfo` instance. + /// + /// If you call this method, you are guaranteeing that `out_dim` and + /// `out_ndim` are consistent with `indices`. + #[doc(hidden)] + pub unsafe fn new_unchecked( + indices: T, + out_dim: PhantomData, + out_ndim: usize, + ) -> SliceInfo { + SliceInfo { + out_dim: out_dim, + out_ndim: out_ndim, + indices: indices, + } + } + + /// Returns a slice of the slice/index information. + pub fn indices(&self) -> &T { + &self.indices + } + + /// Returns the number of dimensions after slicing. + pub fn out_ndim(&self) -> usize { + self.out_ndim + } +} + +impl, D: Dimension> AsRef<[SliceOrIndex]> for SliceInfo { + fn as_ref(&self) -> &[SliceOrIndex] { + self.indices.borrow() + } +} + +macro_rules! impl_sliceinfo_from_array { + ($ndim:expr) => { + impl From<[Si; $ndim]> for SliceInfo<[SliceOrIndex; $ndim], Dim<[Ix; $ndim]>> { + fn from(slices: [Si; $ndim]) -> Self { + let mut indices = [SliceOrIndex::Index(0); $ndim]; + for (i, s) in slices.iter().enumerate() { + indices[i] = SliceOrIndex::Slice(*s); + } + SliceInfo { + out_dim: PhantomData, + out_ndim: $ndim, + indices: indices, + } + } + } + } +} + +impl_sliceinfo_from_array!{0} +impl_sliceinfo_from_array!{1} +impl_sliceinfo_from_array!{2} +impl_sliceinfo_from_array!{3} +impl_sliceinfo_from_array!{4} +impl_sliceinfo_from_array!{5} +impl_sliceinfo_from_array!{6} + +impl<'a> From<&'a [Si]> for SliceInfo, IxDyn> { + fn from(slices: &[Si]) -> Self { + SliceInfo { + out_dim: PhantomData, + out_ndim: slices.len(), + indices: slices.iter().map(|s| SliceOrIndex::Slice(*s)).collect(), + } + } +} + +#[doc(hidden)] +pub trait SliceNextDim { + fn next_dim(&self, (PhantomData, usize)) -> (PhantomData, usize); +} + +impl SliceNextDim for Range { + fn next_dim(&self, (_dim, ndim): (PhantomData, usize)) -> (PhantomData, usize) { + (PhantomData, ndim + 1) + } +} + +impl SliceNextDim for RangeFrom { + fn next_dim(&self, (_dim, ndim): (PhantomData, usize)) -> (PhantomData, usize) { + (PhantomData, ndim + 1) + } +} + +impl SliceNextDim for RangeTo { + fn next_dim(&self, (_dim, ndim): (PhantomData, usize)) -> (PhantomData, usize) { + (PhantomData, ndim + 1) + } +} + +impl SliceNextDim for RangeFull { + fn next_dim(&self, (_dim, ndim): (PhantomData, usize)) -> (PhantomData, usize) { + (PhantomData, ndim + 1) + } +} + +impl SliceNextDim for Ixs { + fn next_dim(&self, (_dim, ndim): (PhantomData, usize)) -> (PhantomData, usize) { + (PhantomData, ndim) + } +} + /// Slice argument constructor. /// /// `s![]` takes a list of ranges, separated by comma, with optional strides -/// that are separated from the range by a semicolon. -/// It is converted into a slice argument with type `&[Si; N]`. +/// that are separated from the range by a semicolon. It is converted into a +/// `SliceInfo` instance. /// /// Each range uses signed indices, where a negative value is counted from /// the end of the axis. Strides are also signed and may be negative, but @@ -121,10 +289,6 @@ pub const S: Si = Si(0, None, 1); /// and columns 1..5 with default step size 1. The slice would have /// shape `[2, 4]`. /// -/// If an array has two axes, the slice argument is passed as -/// type `&[Si; 2]`. The macro expansion of `s![a..b;c, d..e]` -/// is equivalent to `&[Si(a, Some(b), c), Si(d, Some(e), 1)]`. -/// /// ``` /// #[macro_use] /// extern crate ndarray; @@ -143,34 +307,54 @@ pub const S: Si = Si(0, None, 1); #[macro_export] macro_rules! s( // convert a..b;c into @step(a..b, c), final item - (@parse [$($stack:tt)*] $r:expr;$s:expr) => { - &[$($stack)* s!(@step $r, $s)] + (@parse $dim_ndim:expr, [$($stack:tt)*] $r:expr;$s:expr) => { + { + let (out_dim, out_ndim) = $crate::SliceNextDim::next_dim(&$r, $dim_ndim); + unsafe { + $crate::SliceInfo::new_unchecked([$($stack)* s!(@step $r, $s)], out_dim, out_ndim) + } + } }; // convert a..b into @step(a..b, 1), final item - (@parse [$($stack:tt)*] $r:expr) => { - &[$($stack)* s!(@step $r, 1)] + (@parse $dim_ndim:expr, [$($stack:tt)*] $r:expr) => { + { + let (out_dim, out_ndim) = $crate::SliceNextDim::next_dim(&$r, $dim_ndim); + unsafe { + $crate::SliceInfo::new_unchecked([$($stack)* s!(@step $r, 1)], out_dim, out_ndim) + } + } }; // convert a..b;c into @step(a..b, c), final item, trailing comma - (@parse [$($stack:tt)*] $r:expr;$s:expr ,) => { - &[$($stack)* s!(@step $r, $s)] + (@parse $dim_ndim:expr, [$($stack:tt)*] $r:expr;$s:expr ,) => { + { + let (out_dim, out_ndim) = $crate::SliceNextDim::next_dim(&$r, $dim_ndim); + unsafe { + $crate::SliceInfo::new_unchecked([$($stack)* s!(@step $r, $s)], out_dim, out_ndim) + } + } }; // convert a..b into @step(a..b, 1), final item, trailing comma - (@parse [$($stack:tt)*] $r:expr ,) => { - &[$($stack)* s!(@step $r, 1)] + (@parse $dim_ndim:expr, [$($stack:tt)*] $r:expr ,) => { + { + let (out_dim, out_ndim) = $crate::SliceNextDim::next_dim(&$r, $dim_ndim); + unsafe { + $crate::SliceInfo::new_unchecked([$($stack)* s!(@step $r, 1)], out_dim, out_ndim) + } + } }; // convert a..b;c into @step(a..b, c) - (@parse [$($stack:tt)*] $r:expr;$s:expr, $($t:tt)*) => { - s![@parse [$($stack)* s!(@step $r, $s),] $($t)*] + (@parse $dim_ndim:expr, [$($stack:tt)*] $r:expr;$s:expr, $($t:tt)*) => { + s![@parse $crate::SliceNextDim::next_dim(&$r, $dim_ndim), [$($stack)* s!(@step $r, $s),] $($t)*] }; // convert a..b into @step(a..b, 1) - (@parse [$($stack:tt)*] $r:expr, $($t:tt)*) => { - s![@parse [$($stack)* s!(@step $r, 1),] $($t)*] + (@parse $dim_ndim:expr, [$($stack:tt)*] $r:expr, $($t:tt)*) => { + s![@parse $crate::SliceNextDim::next_dim(&$r, $dim_ndim), [$($stack)* s!(@step $r, 1),] $($t)*] }; - // convert range, step into Si + // convert range, step into SliceOrIndex (@step $r:expr, $s:expr) => { - <$crate::Si as ::std::convert::From<_>>::from($r).step($s) + <$crate::SliceOrIndex as ::std::convert::From<_>>::from($r).step($s) }; ($($t:tt)*) => { - s![@parse [] $($t)*] + s![@parse (::std::marker::PhantomData::<$crate::Ix0>, 0), [] $($t)*] }; ); diff --git a/tests/array.rs b/tests/array.rs index 740b6f7e0..73c62c547 100644 --- a/tests/array.rs +++ b/tests/array.rs @@ -6,7 +6,7 @@ extern crate ndarray; extern crate defmac; extern crate itertools; -use ndarray::{S, Si}; +use ndarray::{S, Si, SliceInfo}; use ndarray::prelude::*; use ndarray::{ rcarr2, @@ -62,11 +62,68 @@ fn test_slice() let vi = A.slice(s![1.., ..;2]); assert_eq!(vi.shape(), &[2, 2]); - let vi = A.slice(&[S, S]); + let vi = A.slice(SliceInfo::from([S, S])); assert_eq!(vi.shape(), A.shape()); assert!(vi.iter().zip(A.iter()).all(|(a, b)| a == b)); } +#[test] +fn test_slice_with_subview() +{ + let mut A = RcArray::::zeros((3, 5, 4)); + for (i, elt) in A.iter_mut().enumerate() { + *elt = i; + } + + let vi = A.slice(s![1.., 2, ..;2]); + assert_eq!(vi.shape(), &[2, 2]); + assert!( + vi.iter() + .zip(A.subview(Axis(1), 2).slice(s![1.., ..;2]).iter()) + .all(|(a, b)| a == b) + ); + + let vi = A.slice(s![1, 2, ..;2]); + assert_eq!(vi.shape(), &[2]); + assert!( + vi.iter() + .zip( + A.subview(Axis(0), 1) + .subview(Axis(0), 2) + .slice(s![..;2]) + .iter() + ) + .all(|(a, b)| a == b) + ); +} + +#[test] +fn test_islice_with_isubview() +{ + let mut A = RcArray::::zeros((3, 5, 4)); + for (i, elt) in A.iter_mut().enumerate() { + *elt = i; + } + + let mut vi = A.view(); + vi.islice(s![1.., 2, ..;2]); + assert_eq!(vi.shape(), &[2, 1, 2]); + assert!( + vi.iter() + .zip(A.slice(s![1.., 2..3, ..;2]).iter()) + .all(|(a, b)| a == b) + ); + + let mut vi = A.view(); + vi.islice(s![1, 2, ..;2]); + assert_eq!(vi.shape(), &[1, 1, 2]); + assert!( + vi.iter() + .zip(A.slice(s![1..2, 2..3, ..;2]).iter()) + .all(|(a, b)| a == b) + ); +} + #[should_panic] #[test] fn index_out_of_bounds() { @@ -79,7 +136,14 @@ fn index_out_of_bounds() { fn slice_oob() { let a = RcArray::::zeros((3, 4)); - let _vi = a.slice(&[Si(0, Some(10), 1), S]); + let _vi = a.slice(SliceInfo::from([Si(0, Some(10), 1), S])); +} + +#[should_panic] +#[test] +fn slice_axis_oob() { + let a = RcArray::::zeros((3, 4)); + let _vi = a.slice_axis(Axis(0), &Si(0, Some(10), 1)); } #[should_panic] @@ -102,7 +166,7 @@ fn test_index() assert_eq!(*a, A[[i, j]]); } - let vi = A.slice(&[Si(1, None, 1), Si(0, None, 2)]); + let vi = A.slice(SliceInfo::from([Si(1, None, 1), Si(0, None, 2)])); let mut it = vi.iter(); for ((i, j), x) in zip(indices((1, 2)), &mut it) { assert_eq!(*x, vi[[i, j]]); @@ -171,7 +235,7 @@ fn test_negative_stride_rcarray() } { - let vi = mat.slice(&[S, Si(0, None, -1), Si(0, None, -1)]); + let vi = mat.slice(SliceInfo::from([S, Si(0, None, -1), Si(0, None, -1)])); assert_eq!(vi.shape(), &[2, 4, 2]); // Test against sequential iterator let seq = [7f32,6., 5.,4.,3.,2.,1.,0.,15.,14.,13., 12.,11., 10., 9., 8.]; @@ -203,7 +267,7 @@ fn test_cow() assert_eq!(n[[0, 1]], 0); assert_eq!(n.get((0, 1)), Some(&0)); let mut rev = mat.reshape(4); - rev.islice(&[Si(0, None, -1)]); + rev.islice(SliceInfo::from([Si(0, None, -1)])); assert_eq!(rev[0], 4); assert_eq!(rev[1], 3); assert_eq!(rev[2], 2); @@ -367,7 +431,7 @@ fn assign() let mut a = arr2(&[[1, 2], [3, 4]]); { let mut v = a.view_mut(); - v.islice(&[Si(0, Some(1), 1), S]); + v.islice(SliceInfo::from([Si(0, Some(1), 1), S])); v.fill(0); } assert_eq!(a, arr2(&[[0, 0], [3, 4]])); @@ -667,7 +731,7 @@ fn view_mut() { #[test] fn slice_mut() { let mut a = RcArray::from_vec(vec![1, 2, 3, 4]).reshape((2, 2)); - for elt in a.slice_mut(&[S, S]) { + for elt in a.slice_mut(SliceInfo::from([S, S])) { *elt = 0; } assert_eq!(a, aview2(&[[0, 0], [0, 0]])); @@ -675,14 +739,14 @@ fn slice_mut() { let mut b = arr2(&[[1, 2, 3], [4, 5, 6]]); let c = b.clone(); // make sure we can mutate b even if it has to be unshared first - for elt in b.slice_mut(&[S, Si(0, Some(1), 1)]) { + for elt in b.slice_mut(SliceInfo::from([S, Si(0, Some(1), 1)])) { *elt = 0; } assert_eq!(b, aview2(&[[0, 2, 3], [0, 5, 6]])); assert!(c != b); - for elt in b.slice_mut(&[S, Si(0, None, 2)]) { + for elt in b.slice_mut(SliceInfo::from([S, Si(0, None, 2)])) { *elt = 99; } assert_eq!(b, aview2(&[[99, 2, 99], diff --git a/tests/iterators.rs b/tests/iterators.rs index a75eefbb8..c50b37ef2 100644 --- a/tests/iterators.rs +++ b/tests/iterators.rs @@ -4,7 +4,7 @@ extern crate itertools; use ndarray::{Array0, Array2}; use ndarray::RcArray; -use ndarray::{Ix, Si, S}; +use ndarray::{Ix, Si, S, SliceInfo}; use ndarray::{ ArrayBase, Data, @@ -99,22 +99,22 @@ fn as_slice() { assert_slice_correct(&v.subview(Axis(0), 0)); assert_slice_correct(&v.subview(Axis(0), 1)); - assert!(v.slice(&[S, Si(0, Some(1), 1)]).as_slice().is_none()); - println!("{:?}", v.slice(&[Si(0, Some(1), 2), S])); - assert!(v.slice(&[Si(0, Some(1), 2), S]).as_slice().is_some()); + assert!(v.slice(SliceInfo::from([S, Si(0, Some(1), 1)])).as_slice().is_none()); + println!("{:?}", v.slice(SliceInfo::from([Si(0, Some(1), 2), S]))); + assert!(v.slice(SliceInfo::from([Si(0, Some(1), 2), S])).as_slice().is_some()); // `u` is contiguous, because the column stride of `2` doesn't matter // when the result is just one row anyway -- length of that dimension is 1 - let u = v.slice(&[Si(0, Some(1), 2), S]); + let u = v.slice(SliceInfo::from([Si(0, Some(1), 2), S])); println!("{:?}", u.shape()); println!("{:?}", u.strides()); - println!("{:?}", v.slice(&[Si(0, Some(1), 2), S])); + println!("{:?}", v.slice(SliceInfo::from([Si(0, Some(1), 2), S]))); assert!(u.as_slice().is_some()); assert_slice_correct(&u); let a = a.reshape((8, 1)); assert_slice_correct(&a); - let u = a.slice(&[Si(0, None, 2), S]); + let u = a.slice(SliceInfo::from([Si(0, None, 2), S])); println!("u={:?}, shape={:?}, strides={:?}", u, u.shape(), u.strides()); assert!(u.as_slice().is_none()); } diff --git a/tests/oper.rs b/tests/oper.rs index fb6515285..2b02b85a6 100644 --- a/tests/oper.rs +++ b/tests/oper.rs @@ -7,7 +7,7 @@ use ndarray::{rcarr1, rcarr2}; use ndarray::{LinalgScalar, Data}; use ndarray::linalg::general_mat_mul; use ndarray::linalg::general_mat_vec_mul; -use ndarray::Si; +use ndarray::{Si, SliceInfo}; use ndarray::{Ix, Ixs}; use std::fmt; @@ -570,7 +570,7 @@ fn scaled_add_3() { { let mut av = a.slice_mut(s![..;s1, ..;s2]); - let c = c.slice(&cslice); + let c = c.slice(SliceInfo::from(&*cslice)); let mut answerv = answer.slice_mut(s![..;s1, ..;s2]); answerv += &(beta * &c); From 5f1a18abd63ca57d016dd52cf3064b3666ed3f12 Mon Sep 17 00:00:00 2001 From: Jim Turner Date: Wed, 18 Oct 2017 22:24:52 -0400 Subject: [PATCH 02/30] Remove redundant assert The same assertion occurs in `self.islice()`, so this one is redundant. --- src/impl_methods.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/impl_methods.rs b/src/impl_methods.rs index be27ea8fb..8b1d45543 100644 --- a/src/impl_methods.rs +++ b/src/impl_methods.rs @@ -262,7 +262,6 @@ impl ArrayBase where S: Data, D: Dimension { let info: &SliceInfo<_, _> = info.borrow(); let indices: &[SliceOrIndex] = info.indices().borrow().borrow(); - assert_eq!(indices.len(), self.ndim()); // Slice and subview in-place without changing the number of dimensions. self.islice(indices); From 4d5e3c0b10ab8cb5336efcccc4354c9850a49415 Mon Sep 17 00:00:00 2001 From: Jim Turner Date: Wed, 18 Oct 2017 23:18:05 -0400 Subject: [PATCH 03/30] Fix slicing for Rust < 1.21.0 --- src/impl_methods.rs | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/src/impl_methods.rs b/src/impl_methods.rs index 8b1d45543..1889e77a6 100644 --- a/src/impl_methods.rs +++ b/src/impl_methods.rs @@ -269,16 +269,18 @@ impl ArrayBase where S: Data, D: Dimension // Copy the dim and strides that remain after removing the subview axes. let mut new_dim = Do::zero_index_with_ndim(info.out_ndim()); let mut new_strides = Do::zero_index_with_ndim(info.out_ndim()); - izip!(self.dim.slice(), self.strides.slice(), indices) - .filter_map(|(d, s, slice_or_index)| match slice_or_index { + let remaining = izip!(self.dim.slice(), self.strides.slice(), indices).filter_map( + |(d, s, slice_or_index)| match slice_or_index { &SliceOrIndex::Slice(_) => Some((d, s)), &SliceOrIndex::Index(_) => None, - }) - .zip(izip!(new_dim.slice_mut(), new_strides.slice_mut())) - .for_each(|((d, s), (new_d, new_s))| { - *new_d = *d; - *new_s = *s; - }); + }, + ); + for ((d, s), (new_d, new_s)) in + remaining.zip(izip!(new_dim.slice_mut(), new_strides.slice_mut())) + { + *new_d = *d; + *new_s = *s; + } ArrayBase { ptr: self.ptr, @@ -301,16 +303,15 @@ impl ArrayBase where S: Data, D: Dimension I: AsRef<[SliceOrIndex]>, { assert_eq!(info.as_ref().len(), self.ndim()); - info.as_ref() - .iter() - .enumerate() - .for_each(|(axis, slice_or_index)| match slice_or_index { + for (axis, slice_or_index) in info.as_ref().iter().enumerate() { + match slice_or_index { &SliceOrIndex::Slice(s) => self.islice_axis(Axis(axis), &s), &SliceOrIndex::Index(i) => { let i_usize = abs_index(self.shape()[axis] as Ixs, i); self.isubview(Axis(axis), i_usize) } - }); + } + } } /// Return a view of the array, sliced along the specified axis. From 0cd356389bfae3b82dd3b3af3fe2dbe46f82cadd Mon Sep 17 00:00:00 2001 From: Jim Turner Date: Thu, 19 Oct 2017 17:47:03 -0400 Subject: [PATCH 04/30] Add type-checking of input size for islice() --- src/impl_methods.rs | 18 +++++++++--------- src/si.rs | 6 +++--- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/impl_methods.rs b/src/impl_methods.rs index 1889e77a6..a9220c682 100644 --- a/src/impl_methods.rs +++ b/src/impl_methods.rs @@ -261,7 +261,7 @@ impl ArrayBase where S: Data, D: Dimension Do: Dimension, { let info: &SliceInfo<_, _> = info.borrow(); - let indices: &[SliceOrIndex] = info.indices().borrow().borrow(); + let indices: &D::SliceArg = info.indices().borrow(); // Slice and subview in-place without changing the number of dimensions. self.islice(indices); @@ -269,12 +269,11 @@ impl ArrayBase where S: Data, D: Dimension // Copy the dim and strides that remain after removing the subview axes. let mut new_dim = Do::zero_index_with_ndim(info.out_ndim()); let mut new_strides = Do::zero_index_with_ndim(info.out_ndim()); - let remaining = izip!(self.dim.slice(), self.strides.slice(), indices).filter_map( - |(d, s, slice_or_index)| match slice_or_index { + let remaining = izip!(self.dim.slice(), self.strides.slice(), indices.borrow()) + .filter_map(|(d, s, slice_or_index)| match slice_or_index { &SliceOrIndex::Slice(_) => Some((d, s)), &SliceOrIndex::Index(_) => None, - }, - ); + }); for ((d, s), (new_d, new_s)) in remaining.zip(izip!(new_dim.slice_mut(), new_strides.slice_mut())) { @@ -298,12 +297,13 @@ impl ArrayBase where S: Data, D: Dimension /// /// **Panics** if an index is out of bounds or stride is zero.
/// (**Panics** if `D` is `IxDyn` and `info` does not match the number of array axes.) - pub fn islice(&mut self, info: I) + pub fn islice(&mut self, indices: T) where - I: AsRef<[SliceOrIndex]>, + T: Borrow, { - assert_eq!(info.as_ref().len(), self.ndim()); - for (axis, slice_or_index) in info.as_ref().iter().enumerate() { + let indices: &[SliceOrIndex] = indices.borrow().borrow(); + assert_eq!(indices.len(), self.ndim()); + for (axis, slice_or_index) in indices.iter().enumerate() { match slice_or_index { &SliceOrIndex::Slice(s) => self.islice_axis(Axis(axis), &s), &SliceOrIndex::Index(i) => { diff --git a/src/si.rs b/src/si.rs index 95b52c82c..6b83decf0 100644 --- a/src/si.rs +++ b/src/si.rs @@ -192,9 +192,9 @@ impl SliceInfo { } } -impl, D: Dimension> AsRef<[SliceOrIndex]> for SliceInfo { - fn as_ref(&self) -> &[SliceOrIndex] { - self.indices.borrow() +impl Borrow for SliceInfo { + fn borrow(&self) -> &T { + &self.indices } } From e71f63680fa2fa53a2adfb885dfeec13682aed0f Mon Sep 17 00:00:00 2001 From: Jim Turner Date: Thu, 19 Oct 2017 17:53:53 -0400 Subject: [PATCH 05/30] Pass Si by value instead of by reference --- src/dimension/dimension_trait.rs | 5 ++--- src/impl_methods.rs | 8 ++++---- tests/array.rs | 2 +- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/dimension/dimension_trait.rs b/src/dimension/dimension_trait.rs index eba879354..6c8525369 100644 --- a/src/dimension/dimension_trait.rs +++ b/src/dimension/dimension_trait.rs @@ -252,15 +252,14 @@ pub trait Dimension : Clone + Eq + Debug + Send + Sync + Default + /// Modify dimension, stride and return data pointer offset /// /// **Panics** if any stride is 0 or if any index is out of bounds. - fn do_slice(dim: &mut Ix, stride: &mut Ix, slice: &Si) -> isize { + fn do_slice(dim: &mut Ix, stride: &mut Ix, slice: Si) -> isize { let mut offset = 0; let dr = dim; let sr = stride; - let slc = *slice; let m = *dr; let mi = m as Ixs; - let Si(b1, opt_e1, s1) = slc; + let Si(b1, opt_e1, s1) = slice; let e1 = opt_e1.unwrap_or(mi); let b1 = abs_index(mi, b1); diff --git a/src/impl_methods.rs b/src/impl_methods.rs index a9220c682..54e30b2e6 100644 --- a/src/impl_methods.rs +++ b/src/impl_methods.rs @@ -305,7 +305,7 @@ impl ArrayBase where S: Data, D: Dimension assert_eq!(indices.len(), self.ndim()); for (axis, slice_or_index) in indices.iter().enumerate() { match slice_or_index { - &SliceOrIndex::Slice(s) => self.islice_axis(Axis(axis), &s), + &SliceOrIndex::Slice(s) => self.islice_axis(Axis(axis), s), &SliceOrIndex::Index(i) => { let i_usize = abs_index(self.shape()[axis] as Ixs, i); self.isubview(Axis(axis), i_usize) @@ -318,7 +318,7 @@ impl ArrayBase where S: Data, D: Dimension /// /// **Panics** if an index is out of bounds or stride is zero.
/// **Panics** if `axis` is out of bounds. - pub fn slice_axis(&self, axis: Axis, indices: &Si) -> ArrayView { + pub fn slice_axis(&self, axis: Axis, indices: Si) -> ArrayView { let mut arr = self.view(); arr.islice_axis(axis, indices); arr @@ -328,7 +328,7 @@ impl ArrayBase where S: Data, D: Dimension /// /// **Panics** if an index is out of bounds or stride is zero.
/// **Panics** if `axis` is out of bounds. - pub fn slice_axis_mut(&mut self, axis: Axis, indices: &Si) -> ArrayViewMut + pub fn slice_axis_mut(&mut self, axis: Axis, indices: Si) -> ArrayViewMut where S: DataMut, { let mut arr = self.view_mut(); @@ -340,7 +340,7 @@ impl ArrayBase where S: Data, D: Dimension /// /// **Panics** if an index is out of bounds or stride is zero.
/// **Panics** if `axis` is out of bounds. - pub fn islice_axis(&mut self, axis: Axis, indices: &Si) { + pub fn islice_axis(&mut self, axis: Axis, indices: Si) { let offset = D::do_slice( &mut self.dim.slice_mut()[axis.index()], &mut self.strides.slice_mut()[axis.index()], diff --git a/tests/array.rs b/tests/array.rs index 73c62c547..e44c80265 100644 --- a/tests/array.rs +++ b/tests/array.rs @@ -143,7 +143,7 @@ fn slice_oob() #[test] fn slice_axis_oob() { let a = RcArray::::zeros((3, 4)); - let _vi = a.slice_axis(Axis(0), &Si(0, Some(10), 1)); + let _vi = a.slice_axis(Axis(0), Si(0, Some(10), 1)); } #[should_panic] From a84c384df953e28ed9a4af3adcb2cbd4c6e5f196 Mon Sep 17 00:00:00 2001 From: Jim Turner Date: Fri, 20 Oct 2017 14:48:05 -0400 Subject: [PATCH 06/30] Remove support for Rust < 1.21.0 --- .travis.yml | 3 --- src/impl_methods.rs | 22 +++++++++++----------- 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/.travis.yml b/.travis.yml index f258a3e46..e7a3e26a5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,9 +4,6 @@ sudo: required dist: trusty matrix: include: - - rust: 1.18.0 - env: - - FEATURES='test' - rust: stable env: - FEATURES='test' diff --git a/src/impl_methods.rs b/src/impl_methods.rs index 54e30b2e6..f80203fed 100644 --- a/src/impl_methods.rs +++ b/src/impl_methods.rs @@ -269,17 +269,16 @@ impl ArrayBase where S: Data, D: Dimension // Copy the dim and strides that remain after removing the subview axes. let mut new_dim = Do::zero_index_with_ndim(info.out_ndim()); let mut new_strides = Do::zero_index_with_ndim(info.out_ndim()); - let remaining = izip!(self.dim.slice(), self.strides.slice(), indices.borrow()) + izip!(self.dim.slice(), self.strides.slice(), indices.borrow()) .filter_map(|(d, s, slice_or_index)| match slice_or_index { &SliceOrIndex::Slice(_) => Some((d, s)), &SliceOrIndex::Index(_) => None, + }) + .zip(izip!(new_dim.slice_mut(), new_strides.slice_mut())) + .for_each(|((d, s), (new_d, new_s))| { + *new_d = *d; + *new_s = *s; }); - for ((d, s), (new_d, new_s)) in - remaining.zip(izip!(new_dim.slice_mut(), new_strides.slice_mut())) - { - *new_d = *d; - *new_s = *s; - } ArrayBase { ptr: self.ptr, @@ -303,15 +302,16 @@ impl ArrayBase where S: Data, D: Dimension { let indices: &[SliceOrIndex] = indices.borrow().borrow(); assert_eq!(indices.len(), self.ndim()); - for (axis, slice_or_index) in indices.iter().enumerate() { - match slice_or_index { + indices + .iter() + .enumerate() + .for_each(|(axis, slice_or_index)| match slice_or_index { &SliceOrIndex::Slice(s) => self.islice_axis(Axis(axis), s), &SliceOrIndex::Index(i) => { let i_usize = abs_index(self.shape()[axis] as Ixs, i); self.isubview(Axis(axis), i_usize) } - } - } + }); } /// Return a view of the array, sliced along the specified axis. From 4d2d577d27abd23652db448fbc327cdf055a325d Mon Sep 17 00:00:00 2001 From: Jim Turner Date: Fri, 20 Oct 2017 15:28:14 -0400 Subject: [PATCH 07/30] Implement From> for SliceInfo This also adds `.is_slice()` and `is_index()` methods to `SliceOrIndex`. --- src/si.rs | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/si.rs b/src/si.rs index 6b83decf0..9250e811d 100644 --- a/src/si.rs +++ b/src/si.rs @@ -112,6 +112,20 @@ pub enum SliceOrIndex { copy_and_clone!{SliceOrIndex} impl SliceOrIndex { + pub fn is_slice(&self) -> bool { + match self { + &SliceOrIndex::Slice(_) => true, + _ => false, + } + } + + pub fn is_index(&self) -> bool { + match self { + &SliceOrIndex::Index(_) => true, + _ => false, + } + } + #[inline] pub fn step(self, step: Ixs) -> Self { match self { @@ -234,6 +248,16 @@ impl<'a> From<&'a [Si]> for SliceInfo, IxDyn> { } } +impl From> for SliceInfo, IxDyn> { + fn from(indices: Vec) -> Self { + SliceInfo { + out_dim: PhantomData, + out_ndim: indices.iter().filter(|s| s.is_slice()).count(), + indices: indices, + } + } +} + #[doc(hidden)] pub trait SliceNextDim { fn next_dim(&self, (PhantomData, usize)) -> (PhantomData, usize); From 4ee8729333301448e658262e2d328c57ddf1bfb1 Mon Sep 17 00:00:00 2001 From: Jim Turner Date: Fri, 20 Oct 2017 15:29:31 -0400 Subject: [PATCH 08/30] Remove Sized constraint on T in SliceInfo --- src/si.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/si.rs b/src/si.rs index 9250e811d..f13ddc95b 100644 --- a/src/si.rs +++ b/src/si.rs @@ -171,7 +171,7 @@ impl From for SliceOrIndex { } /// Represents all of the necessary information to perform a slice. -pub struct SliceInfo { +pub struct SliceInfo { out_dim: PhantomData, out_ndim: usize, indices: T, @@ -194,7 +194,9 @@ impl SliceInfo { indices: indices, } } +} +impl SliceInfo { /// Returns a slice of the slice/index information. pub fn indices(&self) -> &T { &self.indices @@ -206,7 +208,7 @@ impl SliceInfo { } } -impl Borrow for SliceInfo { +impl Borrow for SliceInfo { fn borrow(&self) -> &T { &self.indices } From 98cdc244d8c5d2c4774d05dd1e51513e7628a836 Mon Sep 17 00:00:00 2001 From: Jim Turner Date: Fri, 20 Oct 2017 16:45:08 -0400 Subject: [PATCH 09/30] Remove out_ndim member from SliceInfo --- src/dimension/dimension_trait.rs | 10 ++++ src/impl_methods.rs | 5 +- src/si.rs | 88 ++++++++++++++------------------ 3 files changed, 50 insertions(+), 53 deletions(-) diff --git a/src/dimension/dimension_trait.rs b/src/dimension/dimension_trait.rs index 6c8525369..4e803fa53 100644 --- a/src/dimension/dimension_trait.rs +++ b/src/dimension/dimension_trait.rs @@ -42,6 +42,10 @@ pub trait Dimension : Clone + Eq + Debug + Send + Sync + Default + MulAssign + for<'x> MulAssign<&'x Self> + MulAssign { + /// For fixed-size dimension representations (e.g. `Ix2`), this should be + /// `Some(ndim)`, and for variable-size dimension representations (e.g. + /// `IxDyn`), this should be `None`. + const NDIM: Option; /// `SliceArg` is the type which is used to specify slicing for this /// dimension. /// @@ -428,6 +432,7 @@ macro_rules! impl_insert_axis_array( ); impl Dimension for Dim<[Ix; 0]> { + const NDIM: Option = Some(0); type SliceArg = [SliceOrIndex; 0]; type Pattern = (); type Smaller = Self; @@ -464,6 +469,7 @@ impl Dimension for Dim<[Ix; 0]> { impl Dimension for Dim<[Ix; 1]> { + const NDIM: Option = Some(1); type SliceArg = [SliceOrIndex; 1]; type Pattern = Ix; type Smaller = Ix0; @@ -557,6 +563,7 @@ impl Dimension for Dim<[Ix; 1]> { } impl Dimension for Dim<[Ix; 2]> { + const NDIM: Option = Some(2); type SliceArg = [SliceOrIndex; 2]; type Pattern = (Ix, Ix); type Smaller = Ix1; @@ -692,6 +699,7 @@ impl Dimension for Dim<[Ix; 2]> { } impl Dimension for Dim<[Ix; 3]> { + const NDIM: Option = Some(3); type SliceArg = [SliceOrIndex; 3]; type Pattern = (Ix, Ix, Ix); type Smaller = Ix2; @@ -809,6 +817,7 @@ impl Dimension for Dim<[Ix; 3]> { macro_rules! large_dim { ($n:expr, $name:ident, $pattern:ty, $larger:ty, { $($insert_axis:tt)* }) => ( impl Dimension for Dim<[Ix; $n]> { + const NDIM: Option = Some($n); type SliceArg = [SliceOrIndex; $n]; type Pattern = $pattern; type Smaller = Dim<[Ix; $n - 1]>; @@ -860,6 +869,7 @@ large_dim!(6, Ix6, (Ix, Ix, Ix, Ix, Ix, Ix), IxDyn, { /// and memory wasteful, but it allows an arbitrary and dynamic number of axes. impl Dimension for IxDyn { + const NDIM: Option = None; type SliceArg = [SliceOrIndex]; type Pattern = Self; type Smaller = Self; diff --git a/src/impl_methods.rs b/src/impl_methods.rs index f80203fed..200636f84 100644 --- a/src/impl_methods.rs +++ b/src/impl_methods.rs @@ -267,8 +267,9 @@ impl ArrayBase where S: Data, D: Dimension self.islice(indices); // Copy the dim and strides that remain after removing the subview axes. - let mut new_dim = Do::zero_index_with_ndim(info.out_ndim()); - let mut new_strides = Do::zero_index_with_ndim(info.out_ndim()); + let out_ndim = info.out_ndim(); + let mut new_dim = Do::zero_index_with_ndim(out_ndim); + let mut new_strides = Do::zero_index_with_ndim(out_ndim); izip!(self.dim.slice(), self.strides.slice(), indices.borrow()) .filter_map(|(d, s, slice_or_index)| match slice_or_index { &SliceOrIndex::Slice(_) => Some((d, s)), diff --git a/src/si.rs b/src/si.rs index f13ddc95b..81fe6c097 100644 --- a/src/si.rs +++ b/src/si.rs @@ -173,7 +173,6 @@ impl From for SliceOrIndex { /// Represents all of the necessary information to perform a slice. pub struct SliceInfo { out_dim: PhantomData, - out_ndim: usize, indices: T, } @@ -186,26 +185,28 @@ impl SliceInfo { pub unsafe fn new_unchecked( indices: T, out_dim: PhantomData, - out_ndim: usize, ) -> SliceInfo { SliceInfo { out_dim: out_dim, - out_ndim: out_ndim, indices: indices, } } } +impl, D: Dimension> SliceInfo { + /// Returns the number of dimensions after slicing. + pub fn out_ndim(&self) -> usize { + D::NDIM.unwrap_or_else(|| { + self.indices.borrow().iter().filter(|s| s.is_slice()).count() + }) + } +} + impl SliceInfo { /// Returns a slice of the slice/index information. pub fn indices(&self) -> &T { &self.indices } - - /// Returns the number of dimensions after slicing. - pub fn out_ndim(&self) -> usize { - self.out_ndim - } } impl Borrow for SliceInfo { @@ -224,7 +225,6 @@ macro_rules! impl_sliceinfo_from_array { } SliceInfo { out_dim: PhantomData, - out_ndim: $ndim, indices: indices, } } @@ -244,7 +244,6 @@ impl<'a> From<&'a [Si]> for SliceInfo, IxDyn> { fn from(slices: &[Si]) -> Self { SliceInfo { out_dim: PhantomData, - out_ndim: slices.len(), indices: slices.iter().map(|s| SliceOrIndex::Slice(*s)).collect(), } } @@ -254,7 +253,6 @@ impl From> for SliceInfo, IxDyn> { fn from(indices: Vec) -> Self { SliceInfo { out_dim: PhantomData, - out_ndim: indices.iter().filter(|s| s.is_slice()).count(), indices: indices, } } @@ -262,36 +260,36 @@ impl From> for SliceInfo, IxDyn> { #[doc(hidden)] pub trait SliceNextDim { - fn next_dim(&self, (PhantomData, usize)) -> (PhantomData, usize); + fn next_dim(&self, PhantomData) -> PhantomData; } impl SliceNextDim for Range { - fn next_dim(&self, (_dim, ndim): (PhantomData, usize)) -> (PhantomData, usize) { - (PhantomData, ndim + 1) + fn next_dim(&self, _: PhantomData) -> PhantomData { + PhantomData } } impl SliceNextDim for RangeFrom { - fn next_dim(&self, (_dim, ndim): (PhantomData, usize)) -> (PhantomData, usize) { - (PhantomData, ndim + 1) + fn next_dim(&self, _: PhantomData) -> PhantomData { + PhantomData } } impl SliceNextDim for RangeTo { - fn next_dim(&self, (_dim, ndim): (PhantomData, usize)) -> (PhantomData, usize) { - (PhantomData, ndim + 1) + fn next_dim(&self, _: PhantomData) -> PhantomData { + PhantomData } } impl SliceNextDim for RangeFull { - fn next_dim(&self, (_dim, ndim): (PhantomData, usize)) -> (PhantomData, usize) { - (PhantomData, ndim + 1) + fn next_dim(&self, _: PhantomData) -> PhantomData { + PhantomData } } impl SliceNextDim for Ixs { - fn next_dim(&self, (_dim, ndim): (PhantomData, usize)) -> (PhantomData, usize) { - (PhantomData, ndim) + fn next_dim(&self, _: PhantomData) -> PhantomData { + PhantomData } } @@ -333,54 +331,42 @@ impl SliceNextDim for Ixs { #[macro_export] macro_rules! s( // convert a..b;c into @step(a..b, c), final item - (@parse $dim_ndim:expr, [$($stack:tt)*] $r:expr;$s:expr) => { - { - let (out_dim, out_ndim) = $crate::SliceNextDim::next_dim(&$r, $dim_ndim); - unsafe { - $crate::SliceInfo::new_unchecked([$($stack)* s!(@step $r, $s)], out_dim, out_ndim) - } + (@parse $dim:expr, [$($stack:tt)*] $r:expr;$s:expr) => { + unsafe { + $crate::SliceInfo::new_unchecked([$($stack)* s!(@step $r, $s)], $crate::SliceNextDim::next_dim(&$r, $dim)) } }; // convert a..b into @step(a..b, 1), final item - (@parse $dim_ndim:expr, [$($stack:tt)*] $r:expr) => { - { - let (out_dim, out_ndim) = $crate::SliceNextDim::next_dim(&$r, $dim_ndim); - unsafe { - $crate::SliceInfo::new_unchecked([$($stack)* s!(@step $r, 1)], out_dim, out_ndim) - } + (@parse $dim:expr, [$($stack:tt)*] $r:expr) => { + unsafe { + $crate::SliceInfo::new_unchecked([$($stack)* s!(@step $r, 1)], $crate::SliceNextDim::next_dim(&$r, $dim)) } }; // convert a..b;c into @step(a..b, c), final item, trailing comma - (@parse $dim_ndim:expr, [$($stack:tt)*] $r:expr;$s:expr ,) => { - { - let (out_dim, out_ndim) = $crate::SliceNextDim::next_dim(&$r, $dim_ndim); - unsafe { - $crate::SliceInfo::new_unchecked([$($stack)* s!(@step $r, $s)], out_dim, out_ndim) - } + (@parse $dim:expr, [$($stack:tt)*] $r:expr;$s:expr ,) => { + unsafe { + $crate::SliceInfo::new_unchecked([$($stack)* s!(@step $r, $s)], $crate::SliceNextDim::next_dim(&$r, $dim)) } }; // convert a..b into @step(a..b, 1), final item, trailing comma - (@parse $dim_ndim:expr, [$($stack:tt)*] $r:expr ,) => { - { - let (out_dim, out_ndim) = $crate::SliceNextDim::next_dim(&$r, $dim_ndim); - unsafe { - $crate::SliceInfo::new_unchecked([$($stack)* s!(@step $r, 1)], out_dim, out_ndim) - } + (@parse $dim:expr, [$($stack:tt)*] $r:expr ,) => { + unsafe { + $crate::SliceInfo::new_unchecked([$($stack)* s!(@step $r, 1)], $crate::SliceNextDim::next_dim(&$r, $dim)) } }; // convert a..b;c into @step(a..b, c) - (@parse $dim_ndim:expr, [$($stack:tt)*] $r:expr;$s:expr, $($t:tt)*) => { - s![@parse $crate::SliceNextDim::next_dim(&$r, $dim_ndim), [$($stack)* s!(@step $r, $s),] $($t)*] + (@parse $dim:expr, [$($stack:tt)*] $r:expr;$s:expr, $($t:tt)*) => { + s![@parse $crate::SliceNextDim::next_dim(&$r, $dim), [$($stack)* s!(@step $r, $s),] $($t)*] }; // convert a..b into @step(a..b, 1) - (@parse $dim_ndim:expr, [$($stack:tt)*] $r:expr, $($t:tt)*) => { - s![@parse $crate::SliceNextDim::next_dim(&$r, $dim_ndim), [$($stack)* s!(@step $r, 1),] $($t)*] + (@parse $dim:expr, [$($stack:tt)*] $r:expr, $($t:tt)*) => { + s![@parse $crate::SliceNextDim::next_dim(&$r, $dim), [$($stack)* s!(@step $r, 1),] $($t)*] }; // convert range, step into SliceOrIndex (@step $r:expr, $s:expr) => { <$crate::SliceOrIndex as ::std::convert::From<_>>::from($r).step($s) }; ($($t:tt)*) => { - s![@parse (::std::marker::PhantomData::<$crate::Ix0>, 0), [] $($t)*] + s![@parse ::std::marker::PhantomData::<$crate::Ix0>, [] $($t)*] }; ); From b35a7b58a29382746921c3a02ee63cd14f6be8c1 Mon Sep 17 00:00:00 2001 From: Jim Turner Date: Fri, 20 Oct 2017 16:49:33 -0400 Subject: [PATCH 10/30] Remove T type parameter from slice*() --- src/impl_methods.rs | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/src/impl_methods.rs b/src/impl_methods.rs index 200636f84..e922c39b8 100644 --- a/src/impl_methods.rs +++ b/src/impl_methods.rs @@ -219,10 +219,9 @@ impl ArrayBase where S: Data, D: Dimension /// /// **Panics** if an index is out of bounds or stride is zero.
/// (**Panics** if `D` is `IxDyn` and `info` does not match the number of array axes.) - pub fn slice(&self, info: I) -> ArrayView + pub fn slice(&self, info: I) -> ArrayView where - I: Borrow>, - T: Borrow, + I: Borrow>, Do: Dimension, { self.view().slice_into(info) @@ -236,10 +235,9 @@ impl ArrayBase where S: Data, D: Dimension /// /// **Panics** if an index is out of bounds or stride is zero.
/// (**Panics** if `D` is `IxDyn` and `info` does not match the number of array axes.) - pub fn slice_mut(&mut self, info: I) -> ArrayViewMut + pub fn slice_mut(&mut self, info: I) -> ArrayViewMut where - I: Borrow>, - T: Borrow, + I: Borrow>, Do: Dimension, S: DataMut, { @@ -254,23 +252,22 @@ impl ArrayBase where S: Data, D: Dimension /// /// **Panics** if an index is out of bounds or stride is zero.
/// (**Panics** if `D` is `IxDyn` and `info` does not match the number of array axes.) - pub fn slice_into(mut self, info: I) -> ArrayBase + pub fn slice_into(mut self, info: I) -> ArrayBase where - I: Borrow>, - T: Borrow, + I: Borrow>, Do: Dimension, { let info: &SliceInfo<_, _> = info.borrow(); - let indices: &D::SliceArg = info.indices().borrow(); + let indices: &[SliceOrIndex] = info.indices().borrow(); // Slice and subview in-place without changing the number of dimensions. - self.islice(indices); + self.islice(info.indices()); // Copy the dim and strides that remain after removing the subview axes. let out_ndim = info.out_ndim(); let mut new_dim = Do::zero_index_with_ndim(out_ndim); let mut new_strides = Do::zero_index_with_ndim(out_ndim); - izip!(self.dim.slice(), self.strides.slice(), indices.borrow()) + izip!(self.dim.slice(), self.strides.slice(), indices) .filter_map(|(d, s, slice_or_index)| match slice_or_index { &SliceOrIndex::Slice(_) => Some((d, s)), &SliceOrIndex::Index(_) => None, From 27fe45868157055be4baaf527b99a3ca111bb39a Mon Sep 17 00:00:00 2001 From: Jim Turner Date: Fri, 20 Oct 2017 19:18:22 -0400 Subject: [PATCH 11/30] Make slice() work cleanly for SliceInfo, _> --- src/impl_methods.rs | 8 ++-- src/si.rs | 109 +++++++++++++++++++++----------------------- tests/array.rs | 20 ++++---- tests/iterators.rs | 14 +++--- tests/oper.rs | 7 +-- 5 files changed, 78 insertions(+), 80 deletions(-) diff --git a/src/impl_methods.rs b/src/impl_methods.rs index e922c39b8..8d1edd4e5 100644 --- a/src/impl_methods.rs +++ b/src/impl_methods.rs @@ -257,17 +257,17 @@ impl ArrayBase where S: Data, D: Dimension I: Borrow>, Do: Dimension, { - let info: &SliceInfo<_, _> = info.borrow(); - let indices: &[SliceOrIndex] = info.indices().borrow(); + let info: &SliceInfo = info.borrow(); + let indices: &D::SliceArg = info.borrow(); // Slice and subview in-place without changing the number of dimensions. - self.islice(info.indices()); + self.islice(indices); // Copy the dim and strides that remain after removing the subview axes. let out_ndim = info.out_ndim(); let mut new_dim = Do::zero_index_with_ndim(out_ndim); let mut new_strides = Do::zero_index_with_ndim(out_ndim); - izip!(self.dim.slice(), self.strides.slice(), indices) + izip!(self.dim.slice(), self.strides.slice(), indices.borrow()) .filter_map(|(d, s, slice_or_index)| match slice_or_index { &SliceOrIndex::Slice(_) => Some((d, s)), &SliceOrIndex::Index(_) => None, diff --git a/src/si.rs b/src/si.rs index 81fe6c097..72d69ed2f 100644 --- a/src/si.rs +++ b/src/si.rs @@ -9,7 +9,7 @@ use std::borrow::Borrow; use std::ops::{Range, RangeFrom, RangeTo, RangeFull}; use std::fmt; use std::marker::PhantomData; -use super::{Dim, Dimension, Ix, IxDyn, Ixs}; +use super::{Dimension, Ixs}; // [a:b:s] syntax for example [:3], [::-1] // [0,:] -- first row of matrix @@ -176,16 +176,16 @@ pub struct SliceInfo { indices: T, } -impl SliceInfo { +impl SliceInfo +where + D: Dimension, +{ /// Returns a new `SliceInfo` instance. /// /// If you call this method, you are guaranteeing that `out_dim` and /// `out_ndim` are consistent with `indices`. #[doc(hidden)] - pub unsafe fn new_unchecked( - indices: T, - out_dim: PhantomData, - ) -> SliceInfo { + pub unsafe fn new_unchecked(indices: T, out_dim: PhantomData) -> SliceInfo { SliceInfo { out_dim: out_dim, indices: indices, @@ -193,67 +193,64 @@ impl SliceInfo { } } -impl, D: Dimension> SliceInfo { - /// Returns the number of dimensions after slicing. - pub fn out_ndim(&self) -> usize { - D::NDIM.unwrap_or_else(|| { - self.indices.borrow().iter().filter(|s| s.is_slice()).count() - }) +impl SliceInfo +where + T: Borrow<[SliceOrIndex]>, + D: Dimension, +{ + /// Returns a new `SliceInfo` instance. + /// + /// **Panics** if `D` is not consistent with `indices`. + pub fn new(indices: T) -> SliceInfo { + let out_ndim = indices.borrow().iter().filter(|s| s.is_slice()).count(); + if let Some(ndim) = D::NDIM { + assert_eq!(out_ndim, ndim); + } + SliceInfo { + out_dim: PhantomData, + indices: indices, + } } } -impl SliceInfo { - /// Returns a slice of the slice/index information. - pub fn indices(&self) -> &T { - &self.indices +impl SliceInfo +where + T: Borrow<[SliceOrIndex]>, + D: Dimension, +{ + /// Returns the number of dimensions after slicing and taking subviews. + pub fn out_ndim(&self) -> usize { + D::NDIM.unwrap_or_else(|| { + self.indices + .borrow() + .iter() + .filter(|s| s.is_slice()) + .count() + }) } } -impl Borrow for SliceInfo { +impl Borrow for SliceInfo +where + D: Dimension, +{ fn borrow(&self) -> &T { &self.indices } } -macro_rules! impl_sliceinfo_from_array { - ($ndim:expr) => { - impl From<[Si; $ndim]> for SliceInfo<[SliceOrIndex; $ndim], Dim<[Ix; $ndim]>> { - fn from(slices: [Si; $ndim]) -> Self { - let mut indices = [SliceOrIndex::Index(0); $ndim]; - for (i, s) in slices.iter().enumerate() { - indices[i] = SliceOrIndex::Slice(*s); - } - SliceInfo { - out_dim: PhantomData, - indices: indices, - } - } - } - } -} - -impl_sliceinfo_from_array!{0} -impl_sliceinfo_from_array!{1} -impl_sliceinfo_from_array!{2} -impl_sliceinfo_from_array!{3} -impl_sliceinfo_from_array!{4} -impl_sliceinfo_from_array!{5} -impl_sliceinfo_from_array!{6} - -impl<'a> From<&'a [Si]> for SliceInfo, IxDyn> { - fn from(slices: &[Si]) -> Self { - SliceInfo { - out_dim: PhantomData, - indices: slices.iter().map(|s| SliceOrIndex::Slice(*s)).collect(), - } - } -} - -impl From> for SliceInfo, IxDyn> { - fn from(indices: Vec) -> Self { - SliceInfo { - out_dim: PhantomData, - indices: indices, +impl Borrow> for SliceInfo +where + T: Borrow<[SliceOrIndex]>, + D: Dimension, +{ + fn borrow(&self) -> &SliceInfo<[SliceOrIndex], D> { + unsafe { + // This is okay because the only non-zero-sized member of + // `SliceInfo` is `indices`, so `&SliceInfo<[SliceOrIndex], D>` + // should have the same bitwise representation as + // `&[SliceOrIndex]`. + ::std::mem::transmute(self.indices.borrow()) } } } diff --git a/tests/array.rs b/tests/array.rs index e44c80265..cb2f5b3fa 100644 --- a/tests/array.rs +++ b/tests/array.rs @@ -6,7 +6,7 @@ extern crate ndarray; extern crate defmac; extern crate itertools; -use ndarray::{S, Si, SliceInfo}; +use ndarray::Si; use ndarray::prelude::*; use ndarray::{ rcarr2, @@ -62,7 +62,7 @@ fn test_slice() let vi = A.slice(s![1.., ..;2]); assert_eq!(vi.shape(), &[2, 2]); - let vi = A.slice(SliceInfo::from([S, S])); + let vi = A.slice(s![.., ..]); assert_eq!(vi.shape(), A.shape()); assert!(vi.iter().zip(A.iter()).all(|(a, b)| a == b)); } @@ -136,7 +136,7 @@ fn index_out_of_bounds() { fn slice_oob() { let a = RcArray::::zeros((3, 4)); - let _vi = a.slice(SliceInfo::from([Si(0, Some(10), 1), S])); + let _vi = a.slice(s![..10, ..]); } #[should_panic] @@ -166,7 +166,7 @@ fn test_index() assert_eq!(*a, A[[i, j]]); } - let vi = A.slice(SliceInfo::from([Si(1, None, 1), Si(0, None, 2)])); + let vi = A.slice(s![1.., ..;2]); let mut it = vi.iter(); for ((i, j), x) in zip(indices((1, 2)), &mut it) { assert_eq!(*x, vi[[i, j]]); @@ -235,7 +235,7 @@ fn test_negative_stride_rcarray() } { - let vi = mat.slice(SliceInfo::from([S, Si(0, None, -1), Si(0, None, -1)])); + let vi = mat.slice(s![.., ..;-1, ..;-1]); assert_eq!(vi.shape(), &[2, 4, 2]); // Test against sequential iterator let seq = [7f32,6., 5.,4.,3.,2.,1.,0.,15.,14.,13., 12.,11., 10., 9., 8.]; @@ -267,7 +267,7 @@ fn test_cow() assert_eq!(n[[0, 1]], 0); assert_eq!(n.get((0, 1)), Some(&0)); let mut rev = mat.reshape(4); - rev.islice(SliceInfo::from([Si(0, None, -1)])); + rev.islice(s![..;-1]); assert_eq!(rev[0], 4); assert_eq!(rev[1], 3); assert_eq!(rev[2], 2); @@ -431,7 +431,7 @@ fn assign() let mut a = arr2(&[[1, 2], [3, 4]]); { let mut v = a.view_mut(); - v.islice(SliceInfo::from([Si(0, Some(1), 1), S])); + v.islice(s![..1, ..]); v.fill(0); } assert_eq!(a, arr2(&[[0, 0], [3, 4]])); @@ -731,7 +731,7 @@ fn view_mut() { #[test] fn slice_mut() { let mut a = RcArray::from_vec(vec![1, 2, 3, 4]).reshape((2, 2)); - for elt in a.slice_mut(SliceInfo::from([S, S])) { + for elt in a.slice_mut(s![.., ..]) { *elt = 0; } assert_eq!(a, aview2(&[[0, 0], [0, 0]])); @@ -739,14 +739,14 @@ fn slice_mut() { let mut b = arr2(&[[1, 2, 3], [4, 5, 6]]); let c = b.clone(); // make sure we can mutate b even if it has to be unshared first - for elt in b.slice_mut(SliceInfo::from([S, Si(0, Some(1), 1)])) { + for elt in b.slice_mut(s![.., ..1]) { *elt = 0; } assert_eq!(b, aview2(&[[0, 2, 3], [0, 5, 6]])); assert!(c != b); - for elt in b.slice_mut(SliceInfo::from([S, Si(0, None, 2)])) { + for elt in b.slice_mut(s![.., ..;2]) { *elt = 99; } assert_eq!(b, aview2(&[[99, 2, 99], diff --git a/tests/iterators.rs b/tests/iterators.rs index c50b37ef2..41197eafa 100644 --- a/tests/iterators.rs +++ b/tests/iterators.rs @@ -4,7 +4,7 @@ extern crate itertools; use ndarray::{Array0, Array2}; use ndarray::RcArray; -use ndarray::{Ix, Si, S, SliceInfo}; +use ndarray::Ix; use ndarray::{ ArrayBase, Data, @@ -99,22 +99,22 @@ fn as_slice() { assert_slice_correct(&v.subview(Axis(0), 0)); assert_slice_correct(&v.subview(Axis(0), 1)); - assert!(v.slice(SliceInfo::from([S, Si(0, Some(1), 1)])).as_slice().is_none()); - println!("{:?}", v.slice(SliceInfo::from([Si(0, Some(1), 2), S]))); - assert!(v.slice(SliceInfo::from([Si(0, Some(1), 2), S])).as_slice().is_some()); + assert!(v.slice(s![.., ..1]).as_slice().is_none()); + println!("{:?}", v.slice(s![..1;2, ..])); + assert!(v.slice(s![..1;2, ..]).as_slice().is_some()); // `u` is contiguous, because the column stride of `2` doesn't matter // when the result is just one row anyway -- length of that dimension is 1 - let u = v.slice(SliceInfo::from([Si(0, Some(1), 2), S])); + let u = v.slice(s![..1;2, ..]); println!("{:?}", u.shape()); println!("{:?}", u.strides()); - println!("{:?}", v.slice(SliceInfo::from([Si(0, Some(1), 2), S]))); + println!("{:?}", v.slice(s![..1;2, ..])); assert!(u.as_slice().is_some()); assert_slice_correct(&u); let a = a.reshape((8, 1)); assert_slice_correct(&a); - let u = a.slice(SliceInfo::from([Si(0, None, 2), S])); + let u = a.slice(s![..;2, ..]); println!("u={:?}, shape={:?}, strides={:?}", u, u.shape(), u.strides()); assert!(u.as_slice().is_none()); } diff --git a/tests/oper.rs b/tests/oper.rs index 2b02b85a6..16d04ebb4 100644 --- a/tests/oper.rs +++ b/tests/oper.rs @@ -8,6 +8,7 @@ use ndarray::{LinalgScalar, Data}; use ndarray::linalg::general_mat_mul; use ndarray::linalg::general_mat_vec_mul; use ndarray::{Si, SliceInfo}; +use ndarray::SliceOrIndex::Slice; use ndarray::{Ix, Ixs}; use std::fmt; @@ -561,16 +562,16 @@ fn scaled_add_3() { vec![n, q] }; let cslice = if n == 1 { - vec![Si(0, None, s2)] + vec![Slice(Si(0, None, s2))] } else { - vec![Si(0, None, s1), Si(0, None, s2)] + vec![Slice(Si(0, None, s1)), Slice(Si(0, None, s2))] }; let c = range_mat64(n, q).into_shape(cdim).unwrap(); { let mut av = a.slice_mut(s![..;s1, ..;s2]); - let c = c.slice(SliceInfo::from(&*cslice)); + let c = c.slice(SliceInfo::<_, IxDyn>::new(cslice)); let mut answerv = answer.slice_mut(s![..;s1, ..;s2]); answerv += &(beta * &c); From 23affedfe6c291fb6069447e20611268f92bfe5f Mon Sep 17 00:00:00 2001 From: Jim Turner Date: Fri, 20 Oct 2017 20:04:21 -0400 Subject: [PATCH 12/30] Change transmute() to a pointer cast and deref --- src/si.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/si.rs b/src/si.rs index 72d69ed2f..72660a270 100644 --- a/src/si.rs +++ b/src/si.rs @@ -250,7 +250,8 @@ where // `SliceInfo` is `indices`, so `&SliceInfo<[SliceOrIndex], D>` // should have the same bitwise representation as // `&[SliceOrIndex]`. - ::std::mem::transmute(self.indices.borrow()) + &*(self.indices.borrow() as *const [SliceOrIndex] + as *const SliceInfo<[SliceOrIndex], D>) } } } From 66f464dde00c775d0b243ed70e2e3a7d10152cbb Mon Sep 17 00:00:00 2001 From: Jim Turner Date: Fri, 20 Oct 2017 22:23:54 -0400 Subject: [PATCH 13/30] Add tests for SliceInfo types --- src/si.rs | 14 +++++ tests/array.rs | 160 ++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 173 insertions(+), 1 deletion(-) diff --git a/src/si.rs b/src/si.rs index 72660a270..60a02195d 100644 --- a/src/si.rs +++ b/src/si.rs @@ -256,6 +256,20 @@ where } } +impl Clone for SliceInfo +where + T: Clone, + D: Dimension, +{ + fn clone(&self) -> Self { + SliceInfo { + out_dim: PhantomData, + indices: self.indices.clone(), + } + } +} + + #[doc(hidden)] pub trait SliceNextDim { fn next_dim(&self, PhantomData) -> PhantomData; diff --git a/tests/array.rs b/tests/array.rs index cb2f5b3fa..1c9b33d65 100644 --- a/tests/array.rs +++ b/tests/array.rs @@ -6,7 +6,7 @@ extern crate ndarray; extern crate defmac; extern crate itertools; -use ndarray::Si; +use ndarray::{Si, SliceInfo, SliceOrIndex}; use ndarray::prelude::*; use ndarray::{ rcarr2, @@ -67,6 +67,164 @@ fn test_slice() assert!(vi.iter().zip(A.iter()).all(|(a, b)| a == b)); } +#[test] +fn test_slice_array_fixed() +{ + let mut arr = Array2::::zeros((5, 5)); + let info = s![1.., ..;2]; + arr.slice(info.clone()); + arr.slice_mut(info.clone()); + arr.view().slice_into(info.clone()); + arr.view().islice(info.clone()); +} + +#[test] +fn test_slice_array_fixed_ref() +{ + let mut arr = Array2::::zeros((5, 5)); + let info = s![1.., ..;2]; + arr.slice(&info); + arr.slice_mut(&info); + arr.view().slice_into(&info); + arr.view().islice(&info); +} + +#[test] +fn test_slice_dyninput_array_fixed() +{ + let mut arr = Array2::::zeros((5, 5)).into_dyn(); + let info = s![1.., ..;2]; + arr.slice(info.clone()); + arr.slice_mut(info.clone()); + arr.view().slice_into(info.clone()); + arr.view().islice(info.clone()); + +} + +#[test] +fn test_slice_dyninput_array_fixed_ref() +{ + let mut arr = Array2::::zeros((5, 5)).into_dyn(); + let info = s![1.., ..;2]; + arr.slice(&info); + arr.slice_mut(&info); + arr.view().slice_into(&info); + arr.view().islice(&info); + +} + +#[test] +fn test_slice_array_dyn() +{ + let mut arr = Array2::::zeros((5, 5)); + let info = SliceInfo::<_, IxDyn>::new([ + SliceOrIndex::Slice(Si::from(1..)), + SliceOrIndex::Slice(Si::from(..).step(2)), + ]); + arr.slice(info.clone()); + arr.slice_mut(info.clone()); + arr.view().slice_into(info.clone()); + arr.view().islice(info.clone()); +} + +#[test] +fn test_slice_array_dyn_ref() +{ + let mut arr = Array2::::zeros((5, 5)); + let info = SliceInfo::<_, IxDyn>::new([ + SliceOrIndex::Slice(Si::from(1..)), + SliceOrIndex::Slice(Si::from(..).step(2)), + ]); + arr.slice(&info); + arr.slice_mut(&info); + arr.view().slice_into(&info); + arr.view().islice(&info); +} + +#[test] +fn test_slice_dyninput_array_dyn() +{ + let mut arr = Array2::::zeros((5, 5)).into_dyn(); + let info = SliceInfo::<_, IxDyn>::new([ + SliceOrIndex::Slice(Si::from(1..)), + SliceOrIndex::Slice(Si::from(..).step(2)), + ]); + arr.slice(info.clone()); + arr.slice_mut(info.clone()); + arr.view().slice_into(info.clone()); + arr.view().islice(info.clone()); +} + +#[test] +fn test_slice_dyninput_array_dyn_ref() +{ + let mut arr = Array2::::zeros((5, 5)).into_dyn(); + let info = SliceInfo::<_, IxDyn>::new([ + SliceOrIndex::Slice(Si::from(1..)), + SliceOrIndex::Slice(Si::from(..).step(2)), + ]); + arr.slice(&info); + arr.slice_mut(&info); + arr.view().slice_into(&info); + arr.view().islice(&info); +} + +#[test] +fn test_slice_dyninput_vec_fixed() +{ + let mut arr = Array2::::zeros((5, 5)).into_dyn(); + let info = SliceInfo::<_, Ix2>::new(vec![ + SliceOrIndex::Slice(Si::from(1..)), + SliceOrIndex::Slice(Si::from(..).step(2)), + ]); + arr.slice(info.clone()); + arr.slice_mut(info.clone()); + arr.view().slice_into(info.clone()); + arr.view().islice(info.clone()); +} + +#[test] +fn test_slice_dyninput_vec_fixed_ref() +{ + let mut arr = Array2::::zeros((5, 5)).into_dyn(); + let info = SliceInfo::<_, Ix2>::new(vec![ + SliceOrIndex::Slice(Si::from(1..)), + SliceOrIndex::Slice(Si::from(..).step(2)), + ]); + arr.slice(&info); + arr.slice_mut(&info); + arr.view().slice_into(&info); + arr.view().islice(&info); +} + +#[test] +fn test_slice_dyninput_vec_dyn() +{ + let mut arr = Array2::::zeros((5, 5)).into_dyn(); + let info = SliceInfo::<_, IxDyn>::new(vec![ + SliceOrIndex::Slice(Si::from(1..)), + SliceOrIndex::Slice(Si::from(..).step(2)), + ]); + arr.slice(info.clone()); + arr.slice_mut(info.clone()); + arr.view().slice_into(info.clone()); + arr.view().islice(info.clone()); +} + +#[test] +fn test_slice_dyninput_vec_dyn_ref() +{ + let mut arr = Array2::::zeros((5, 5)).into_dyn(); + let info = SliceInfo::<_, IxDyn>::new(vec![ + SliceOrIndex::Slice(Si::from(1..)), + SliceOrIndex::Slice(Si::from(..).step(2)), + ]); + arr.slice(&info); + arr.slice_mut(&info); + arr.view().slice_into(&info); + arr.view().islice(&info); +} + #[test] fn test_slice_with_subview() { From 89ea1dbd0be227cdac96996e524e0cc0246a293e Mon Sep 17 00:00:00 2001 From: Jim Turner Date: Fri, 20 Oct 2017 22:44:16 -0400 Subject: [PATCH 14/30] Support slicing with more SliceInfo types --- src/impl_methods.rs | 6 ++--- src/si.rs | 66 +++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 67 insertions(+), 5 deletions(-) diff --git a/src/impl_methods.rs b/src/impl_methods.rs index 8d1edd4e5..d35fc92e9 100644 --- a/src/impl_methods.rs +++ b/src/impl_methods.rs @@ -258,16 +258,16 @@ impl ArrayBase where S: Data, D: Dimension Do: Dimension, { let info: &SliceInfo = info.borrow(); - let indices: &D::SliceArg = info.borrow(); + let indices: &[SliceOrIndex] = info.indices().borrow(); // Slice and subview in-place without changing the number of dimensions. - self.islice(indices); + self.islice(info.indices()); // Copy the dim and strides that remain after removing the subview axes. let out_ndim = info.out_ndim(); let mut new_dim = Do::zero_index_with_ndim(out_ndim); let mut new_strides = Do::zero_index_with_ndim(out_ndim); - izip!(self.dim.slice(), self.strides.slice(), indices.borrow()) + izip!(self.dim.slice(), self.strides.slice(), indices) .filter_map(|(d, s, slice_or_index)| match slice_or_index { &SliceOrIndex::Slice(_) => Some((d, s)), &SliceOrIndex::Index(_) => None, diff --git a/src/si.rs b/src/si.rs index 60a02195d..b43a30e01 100644 --- a/src/si.rs +++ b/src/si.rs @@ -230,15 +230,67 @@ where } } -impl Borrow for SliceInfo +impl SliceInfo where D: Dimension, { - fn borrow(&self) -> &T { + pub fn indices(&self) -> &T { &self.indices } } +macro_rules! impl_borrow_array_for_sliceinfo { + ($ndim:expr) => { + impl Borrow<[SliceOrIndex; $ndim]> for SliceInfo + where + T: Borrow<[SliceOrIndex; $ndim]>, + D: Dimension, + { + fn borrow(&self) -> &[SliceOrIndex; $ndim] { + self.indices.borrow() + } + } + + impl<'a, T: ?Sized, D> Borrow<[SliceOrIndex; $ndim]> for &'a SliceInfo + where + T: Borrow<[SliceOrIndex; $ndim]>, + D: Dimension, + { + fn borrow(&self) -> &[SliceOrIndex; $ndim] { + (*self).borrow() + } + } + } +} + +impl_borrow_array_for_sliceinfo!(0); +impl_borrow_array_for_sliceinfo!(1); +impl_borrow_array_for_sliceinfo!(2); +impl_borrow_array_for_sliceinfo!(3); +impl_borrow_array_for_sliceinfo!(4); +impl_borrow_array_for_sliceinfo!(5); +impl_borrow_array_for_sliceinfo!(6); + +impl Borrow<[SliceOrIndex]> for SliceInfo +where + T: Borrow<[SliceOrIndex]>, + D: Dimension, +{ + fn borrow(&self) -> &[SliceOrIndex] { + self.indices.borrow() + } +} + +impl<'a, T: ?Sized, D> Borrow<[SliceOrIndex]> for &'a SliceInfo +where + T: Borrow<[SliceOrIndex]>, + D: Dimension, +{ + fn borrow(&self) -> &[SliceOrIndex] { + (*self).borrow() + } +} + impl Borrow> for SliceInfo where T: Borrow<[SliceOrIndex]>, @@ -256,6 +308,16 @@ where } } +impl<'a, T, D> Borrow> for &'a SliceInfo +where + T: Borrow<[SliceOrIndex]>, + D: Dimension, +{ + fn borrow(&self) -> &SliceInfo<[SliceOrIndex], D> { + (*self).borrow() + } +} + impl Clone for SliceInfo where T: Clone, From 6775e4130b4deacafc72509908fbe1db9b4b673d Mon Sep 17 00:00:00 2001 From: bluss Date: Tue, 24 Oct 2017 22:22:53 +0200 Subject: [PATCH 15/30] Remove I: Borrow<_> from *slice*() methods --- src/impl_methods.rs | 23 +++----- src/si.rs | 88 +++++----------------------- tests/array.rs | 137 ++++++++++---------------------------------- tests/oper.rs | 3 +- 4 files changed, 53 insertions(+), 198 deletions(-) diff --git a/src/impl_methods.rs b/src/impl_methods.rs index d35fc92e9..f88abb4b9 100644 --- a/src/impl_methods.rs +++ b/src/impl_methods.rs @@ -219,9 +219,8 @@ impl ArrayBase where S: Data, D: Dimension /// /// **Panics** if an index is out of bounds or stride is zero.
/// (**Panics** if `D` is `IxDyn` and `info` does not match the number of array axes.) - pub fn slice(&self, info: I) -> ArrayView + pub fn slice(&self, info: &SliceInfo) -> ArrayView where - I: Borrow>, Do: Dimension, { self.view().slice_into(info) @@ -235,9 +234,8 @@ impl ArrayBase where S: Data, D: Dimension /// /// **Panics** if an index is out of bounds or stride is zero.
/// (**Panics** if `D` is `IxDyn` and `info` does not match the number of array axes.) - pub fn slice_mut(&mut self, info: I) -> ArrayViewMut + pub fn slice_mut(&mut self, info: &SliceInfo) -> ArrayViewMut where - I: Borrow>, Do: Dimension, S: DataMut, { @@ -252,16 +250,14 @@ impl ArrayBase where S: Data, D: Dimension /// /// **Panics** if an index is out of bounds or stride is zero.
/// (**Panics** if `D` is `IxDyn` and `info` does not match the number of array axes.) - pub fn slice_into(mut self, info: I) -> ArrayBase + pub fn slice_into(mut self, info: &SliceInfo) -> ArrayBase where - I: Borrow>, Do: Dimension, { - let info: &SliceInfo = info.borrow(); - let indices: &[SliceOrIndex] = info.indices().borrow(); - // Slice and subview in-place without changing the number of dimensions. - self.islice(info.indices()); + self.islice(&info.indices); + + let indices: &[SliceOrIndex] = info.indices.borrow(); // Copy the dim and strides that remain after removing the subview axes. let out_ndim = info.out_ndim(); @@ -294,11 +290,8 @@ impl ArrayBase where S: Data, D: Dimension /// /// **Panics** if an index is out of bounds or stride is zero.
/// (**Panics** if `D` is `IxDyn` and `info` does not match the number of array axes.) - pub fn islice(&mut self, indices: T) - where - T: Borrow, - { - let indices: &[SliceOrIndex] = indices.borrow().borrow(); + pub fn islice(&mut self, indices: &D::SliceArg) { + let indices: &[SliceOrIndex] = indices.borrow(); assert_eq!(indices.len(), self.ndim()); indices .iter() diff --git a/src/si.rs b/src/si.rs index b43a30e01..eb8249889 100644 --- a/src/si.rs +++ b/src/si.rs @@ -6,7 +6,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. use std::borrow::Borrow; -use std::ops::{Range, RangeFrom, RangeTo, RangeFull}; +use std::ops::{Range, RangeFrom, RangeTo, RangeFull, Deref}; use std::fmt; use std::marker::PhantomData; use super::{Dimension, Ixs}; @@ -173,7 +173,12 @@ impl From for SliceOrIndex { /// Represents all of the necessary information to perform a slice. pub struct SliceInfo { out_dim: PhantomData, - indices: T, + pub(crate) indices: T, +} + +impl Deref for SliceInfo where D: Dimension { + type Target = T; + fn deref(&self) -> &Self::Target { &self.indices } } impl SliceInfo @@ -230,67 +235,6 @@ where } } -impl SliceInfo -where - D: Dimension, -{ - pub fn indices(&self) -> &T { - &self.indices - } -} - -macro_rules! impl_borrow_array_for_sliceinfo { - ($ndim:expr) => { - impl Borrow<[SliceOrIndex; $ndim]> for SliceInfo - where - T: Borrow<[SliceOrIndex; $ndim]>, - D: Dimension, - { - fn borrow(&self) -> &[SliceOrIndex; $ndim] { - self.indices.borrow() - } - } - - impl<'a, T: ?Sized, D> Borrow<[SliceOrIndex; $ndim]> for &'a SliceInfo - where - T: Borrow<[SliceOrIndex; $ndim]>, - D: Dimension, - { - fn borrow(&self) -> &[SliceOrIndex; $ndim] { - (*self).borrow() - } - } - } -} - -impl_borrow_array_for_sliceinfo!(0); -impl_borrow_array_for_sliceinfo!(1); -impl_borrow_array_for_sliceinfo!(2); -impl_borrow_array_for_sliceinfo!(3); -impl_borrow_array_for_sliceinfo!(4); -impl_borrow_array_for_sliceinfo!(5); -impl_borrow_array_for_sliceinfo!(6); - -impl Borrow<[SliceOrIndex]> for SliceInfo -where - T: Borrow<[SliceOrIndex]>, - D: Dimension, -{ - fn borrow(&self) -> &[SliceOrIndex] { - self.indices.borrow() - } -} - -impl<'a, T: ?Sized, D> Borrow<[SliceOrIndex]> for &'a SliceInfo -where - T: Borrow<[SliceOrIndex]>, - D: Dimension, -{ - fn borrow(&self) -> &[SliceOrIndex] { - (*self).borrow() - } -} - impl Borrow> for SliceInfo where T: Borrow<[SliceOrIndex]>, @@ -308,15 +252,11 @@ where } } -impl<'a, T, D> Borrow> for &'a SliceInfo +impl Copy for SliceInfo where - T: Borrow<[SliceOrIndex]>, + T: Copy, D: Dimension, -{ - fn borrow(&self) -> &SliceInfo<[SliceOrIndex], D> { - (*self).borrow() - } -} +{ } impl Clone for SliceInfo where @@ -407,25 +347,25 @@ macro_rules! s( // convert a..b;c into @step(a..b, c), final item (@parse $dim:expr, [$($stack:tt)*] $r:expr;$s:expr) => { unsafe { - $crate::SliceInfo::new_unchecked([$($stack)* s!(@step $r, $s)], $crate::SliceNextDim::next_dim(&$r, $dim)) + &$crate::SliceInfo::new_unchecked([$($stack)* s!(@step $r, $s)], $crate::SliceNextDim::next_dim(&$r, $dim)) } }; // convert a..b into @step(a..b, 1), final item (@parse $dim:expr, [$($stack:tt)*] $r:expr) => { unsafe { - $crate::SliceInfo::new_unchecked([$($stack)* s!(@step $r, 1)], $crate::SliceNextDim::next_dim(&$r, $dim)) + &$crate::SliceInfo::new_unchecked([$($stack)* s!(@step $r, 1)], $crate::SliceNextDim::next_dim(&$r, $dim)) } }; // convert a..b;c into @step(a..b, c), final item, trailing comma (@parse $dim:expr, [$($stack:tt)*] $r:expr;$s:expr ,) => { unsafe { - $crate::SliceInfo::new_unchecked([$($stack)* s!(@step $r, $s)], $crate::SliceNextDim::next_dim(&$r, $dim)) + &$crate::SliceInfo::new_unchecked([$($stack)* s!(@step $r, $s)], $crate::SliceNextDim::next_dim(&$r, $dim)) } }; // convert a..b into @step(a..b, 1), final item, trailing comma (@parse $dim:expr, [$($stack:tt)*] $r:expr ,) => { unsafe { - $crate::SliceInfo::new_unchecked([$($stack)* s!(@step $r, 1)], $crate::SliceNextDim::next_dim(&$r, $dim)) + &$crate::SliceInfo::new_unchecked([$($stack)* s!(@step $r, 1)], $crate::SliceNextDim::next_dim(&$r, $dim)) } }; // convert a..b;c into @step(a..b, c) diff --git a/tests/array.rs b/tests/array.rs index 1c9b33d65..4d96e12a2 100644 --- a/tests/array.rs +++ b/tests/array.rs @@ -14,6 +14,7 @@ use ndarray::{ }; use ndarray::indices; use itertools::{enumerate, zip}; +use std::borrow::Borrow; #[test] fn test_matmul_rcarray() @@ -72,21 +73,10 @@ fn test_slice_array_fixed() { let mut arr = Array2::::zeros((5, 5)); let info = s![1.., ..;2]; - arr.slice(info.clone()); - arr.slice_mut(info.clone()); - arr.view().slice_into(info.clone()); - arr.view().islice(info.clone()); -} - -#[test] -fn test_slice_array_fixed_ref() -{ - let mut arr = Array2::::zeros((5, 5)); - let info = s![1.., ..;2]; - arr.slice(&info); - arr.slice_mut(&info); - arr.view().slice_into(&info); - arr.view().islice(&info); + arr.slice(info); + arr.slice_mut(info); + arr.view().slice_into(info); + arr.view().islice(info); } #[test] @@ -94,135 +84,66 @@ fn test_slice_dyninput_array_fixed() { let mut arr = Array2::::zeros((5, 5)).into_dyn(); let info = s![1.., ..;2]; - arr.slice(info.clone()); - arr.slice_mut(info.clone()); - arr.view().slice_into(info.clone()); - arr.view().islice(info.clone()); - -} - -#[test] -fn test_slice_dyninput_array_fixed_ref() -{ - let mut arr = Array2::::zeros((5, 5)).into_dyn(); - let info = s![1.., ..;2]; - arr.slice(&info); - arr.slice_mut(&info); - arr.view().slice_into(&info); - arr.view().islice(&info); - + arr.slice(info); + arr.slice_mut(info); + arr.view().slice_into(info); + arr.view().islice(&**info); } #[test] fn test_slice_array_dyn() { let mut arr = Array2::::zeros((5, 5)); - let info = SliceInfo::<_, IxDyn>::new([ + let info = &SliceInfo::<_, IxDyn>::new([ SliceOrIndex::Slice(Si::from(1..)), SliceOrIndex::Slice(Si::from(..).step(2)), ]); - arr.slice(info.clone()); - arr.slice_mut(info.clone()); - arr.view().slice_into(info.clone()); - arr.view().islice(info.clone()); -} - -#[test] -fn test_slice_array_dyn_ref() -{ - let mut arr = Array2::::zeros((5, 5)); - let info = SliceInfo::<_, IxDyn>::new([ - SliceOrIndex::Slice(Si::from(1..)), - SliceOrIndex::Slice(Si::from(..).step(2)), - ]); - arr.slice(&info); - arr.slice_mut(&info); - arr.view().slice_into(&info); - arr.view().islice(&info); + arr.slice(info); + arr.slice_mut(info); + arr.view().slice_into(info); + arr.view().islice(info); } #[test] fn test_slice_dyninput_array_dyn() { let mut arr = Array2::::zeros((5, 5)).into_dyn(); - let info = SliceInfo::<_, IxDyn>::new([ - SliceOrIndex::Slice(Si::from(1..)), - SliceOrIndex::Slice(Si::from(..).step(2)), - ]); - arr.slice(info.clone()); - arr.slice_mut(info.clone()); - arr.view().slice_into(info.clone()); - arr.view().islice(info.clone()); -} - -#[test] -fn test_slice_dyninput_array_dyn_ref() -{ - let mut arr = Array2::::zeros((5, 5)).into_dyn(); - let info = SliceInfo::<_, IxDyn>::new([ + let info = &SliceInfo::<_, IxDyn>::new([ SliceOrIndex::Slice(Si::from(1..)), SliceOrIndex::Slice(Si::from(..).step(2)), ]); - arr.slice(&info); - arr.slice_mut(&info); - arr.view().slice_into(&info); - arr.view().islice(&info); + arr.slice(info); + arr.slice_mut(info); + arr.view().slice_into(info); + arr.view().islice(&**info); } #[test] fn test_slice_dyninput_vec_fixed() { let mut arr = Array2::::zeros((5, 5)).into_dyn(); - let info = SliceInfo::<_, Ix2>::new(vec![ + let info = &SliceInfo::<_, Ix2>::new(vec![ SliceOrIndex::Slice(Si::from(1..)), SliceOrIndex::Slice(Si::from(..).step(2)), ]); - arr.slice(info.clone()); - arr.slice_mut(info.clone()); - arr.view().slice_into(info.clone()); - arr.view().islice(info.clone()); -} - -#[test] -fn test_slice_dyninput_vec_fixed_ref() -{ - let mut arr = Array2::::zeros((5, 5)).into_dyn(); - let info = SliceInfo::<_, Ix2>::new(vec![ - SliceOrIndex::Slice(Si::from(1..)), - SliceOrIndex::Slice(Si::from(..).step(2)), - ]); - arr.slice(&info); - arr.slice_mut(&info); - arr.view().slice_into(&info); - arr.view().islice(&info); + arr.slice(info.borrow()); + arr.slice_mut(info.borrow()); + arr.view().slice_into(info.borrow()); + arr.view().islice(&*info); } #[test] fn test_slice_dyninput_vec_dyn() { let mut arr = Array2::::zeros((5, 5)).into_dyn(); - let info = SliceInfo::<_, IxDyn>::new(vec![ - SliceOrIndex::Slice(Si::from(1..)), - SliceOrIndex::Slice(Si::from(..).step(2)), - ]); - arr.slice(info.clone()); - arr.slice_mut(info.clone()); - arr.view().slice_into(info.clone()); - arr.view().islice(info.clone()); -} - -#[test] -fn test_slice_dyninput_vec_dyn_ref() -{ - let mut arr = Array2::::zeros((5, 5)).into_dyn(); - let info = SliceInfo::<_, IxDyn>::new(vec![ + let info = &SliceInfo::<_, IxDyn>::new(vec![ SliceOrIndex::Slice(Si::from(1..)), SliceOrIndex::Slice(Si::from(..).step(2)), ]); - arr.slice(&info); - arr.slice_mut(&info); - arr.view().slice_into(&info); - arr.view().islice(&info); + arr.slice(info.borrow()); + arr.slice_mut(info.borrow()); + arr.view().slice_into(info.borrow()); + arr.view().islice(&*info); } #[test] diff --git a/tests/oper.rs b/tests/oper.rs index 16d04ebb4..9599b5943 100644 --- a/tests/oper.rs +++ b/tests/oper.rs @@ -11,6 +11,7 @@ use ndarray::{Si, SliceInfo}; use ndarray::SliceOrIndex::Slice; use ndarray::{Ix, Ixs}; +use std::borrow::Borrow; use std::fmt; use num_traits::Float; @@ -571,7 +572,7 @@ fn scaled_add_3() { { let mut av = a.slice_mut(s![..;s1, ..;s2]); - let c = c.slice(SliceInfo::<_, IxDyn>::new(cslice)); + let c = c.slice(SliceInfo::<_, IxDyn>::new(cslice).borrow()); let mut answerv = answer.slice_mut(s![..;s1, ..;s2]); answerv += &(beta * &c); From 9f139547a2762029914b8270d73b8889d21f77ed Mon Sep 17 00:00:00 2001 From: Jim Turner Date: Tue, 24 Oct 2017 17:43:38 -0400 Subject: [PATCH 16/30] Remove visibility to SliceInfo.indices --- src/impl_methods.rs | 4 ++-- src/si.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/impl_methods.rs b/src/impl_methods.rs index f88abb4b9..095fbb258 100644 --- a/src/impl_methods.rs +++ b/src/impl_methods.rs @@ -255,9 +255,9 @@ impl ArrayBase where S: Data, D: Dimension Do: Dimension, { // Slice and subview in-place without changing the number of dimensions. - self.islice(&info.indices); + self.islice(&*info); - let indices: &[SliceOrIndex] = info.indices.borrow(); + let indices: &[SliceOrIndex] = (**info.borrow()).borrow(); // Copy the dim and strides that remain after removing the subview axes. let out_ndim = info.out_ndim(); diff --git a/src/si.rs b/src/si.rs index eb8249889..d61c9d72f 100644 --- a/src/si.rs +++ b/src/si.rs @@ -173,7 +173,7 @@ impl From for SliceOrIndex { /// Represents all of the necessary information to perform a slice. pub struct SliceInfo { out_dim: PhantomData, - pub(crate) indices: T, + indices: T, } impl Deref for SliceInfo where D: Dimension { From c927ac57c1573b253b5cdbfad1752649bd0feb9f Mon Sep 17 00:00:00 2001 From: Jim Turner Date: Tue, 24 Oct 2017 17:53:17 -0400 Subject: [PATCH 17/30] Change Borrow to AsRef --- src/dimension/dimension_trait.rs | 4 ++-- src/impl_methods.rs | 6 +++--- src/si.rs | 17 ++++++++--------- tests/array.rs | 13 ++++++------- tests/oper.rs | 3 +-- 5 files changed, 20 insertions(+), 23 deletions(-) diff --git a/src/dimension/dimension_trait.rs b/src/dimension/dimension_trait.rs index 4e803fa53..2f1b07036 100644 --- a/src/dimension/dimension_trait.rs +++ b/src/dimension/dimension_trait.rs @@ -7,7 +7,7 @@ // except according to those terms. -use std::borrow::Borrow; +use std::convert::AsRef; use std::fmt::Debug; use std::ops::{Index, IndexMut}; use std::ops::{Add, Sub, Mul, AddAssign, SubAssign, MulAssign}; @@ -59,7 +59,7 @@ pub trait Dimension : Clone + Eq + Debug + Send + Sync + Default + /// /// The easiest way to create a `SliceArg` is using the macro /// [`s![]`](macro.s!.html). - type SliceArg: ?Sized + Borrow<[SliceOrIndex]>; + type SliceArg: ?Sized + AsRef<[SliceOrIndex]>; /// Pattern matching friendly form of the dimension value. /// /// - For `Ix1`: `usize`, diff --git a/src/impl_methods.rs b/src/impl_methods.rs index 095fbb258..6e10343f6 100644 --- a/src/impl_methods.rs +++ b/src/impl_methods.rs @@ -6,7 +6,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::borrow::Borrow; +use std::convert::AsRef; use std::cmp; use std::ptr as std_ptr; use std::slice; @@ -257,7 +257,7 @@ impl ArrayBase where S: Data, D: Dimension // Slice and subview in-place without changing the number of dimensions. self.islice(&*info); - let indices: &[SliceOrIndex] = (**info.borrow()).borrow(); + let indices: &[SliceOrIndex] = (**info).as_ref(); // Copy the dim and strides that remain after removing the subview axes. let out_ndim = info.out_ndim(); @@ -291,7 +291,7 @@ impl ArrayBase where S: Data, D: Dimension /// **Panics** if an index is out of bounds or stride is zero.
/// (**Panics** if `D` is `IxDyn` and `info` does not match the number of array axes.) pub fn islice(&mut self, indices: &D::SliceArg) { - let indices: &[SliceOrIndex] = indices.borrow(); + let indices: &[SliceOrIndex] = indices.as_ref(); assert_eq!(indices.len(), self.ndim()); indices .iter() diff --git a/src/si.rs b/src/si.rs index d61c9d72f..cffe155de 100644 --- a/src/si.rs +++ b/src/si.rs @@ -5,7 +5,6 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::borrow::Borrow; use std::ops::{Range, RangeFrom, RangeTo, RangeFull, Deref}; use std::fmt; use std::marker::PhantomData; @@ -200,14 +199,14 @@ where impl SliceInfo where - T: Borrow<[SliceOrIndex]>, + T: AsRef<[SliceOrIndex]>, D: Dimension, { /// Returns a new `SliceInfo` instance. /// /// **Panics** if `D` is not consistent with `indices`. pub fn new(indices: T) -> SliceInfo { - let out_ndim = indices.borrow().iter().filter(|s| s.is_slice()).count(); + let out_ndim = indices.as_ref().iter().filter(|s| s.is_slice()).count(); if let Some(ndim) = D::NDIM { assert_eq!(out_ndim, ndim); } @@ -220,14 +219,14 @@ where impl SliceInfo where - T: Borrow<[SliceOrIndex]>, + T: AsRef<[SliceOrIndex]>, D: Dimension, { /// Returns the number of dimensions after slicing and taking subviews. pub fn out_ndim(&self) -> usize { D::NDIM.unwrap_or_else(|| { self.indices - .borrow() + .as_ref() .iter() .filter(|s| s.is_slice()) .count() @@ -235,18 +234,18 @@ where } } -impl Borrow> for SliceInfo +impl AsRef> for SliceInfo where - T: Borrow<[SliceOrIndex]>, + T: AsRef<[SliceOrIndex]>, D: Dimension, { - fn borrow(&self) -> &SliceInfo<[SliceOrIndex], D> { + fn as_ref(&self) -> &SliceInfo<[SliceOrIndex], D> { unsafe { // This is okay because the only non-zero-sized member of // `SliceInfo` is `indices`, so `&SliceInfo<[SliceOrIndex], D>` // should have the same bitwise representation as // `&[SliceOrIndex]`. - &*(self.indices.borrow() as *const [SliceOrIndex] + &*(self.indices.as_ref() as *const [SliceOrIndex] as *const SliceInfo<[SliceOrIndex], D>) } } diff --git a/tests/array.rs b/tests/array.rs index 4d96e12a2..19f9c6a6f 100644 --- a/tests/array.rs +++ b/tests/array.rs @@ -14,7 +14,6 @@ use ndarray::{ }; use ndarray::indices; use itertools::{enumerate, zip}; -use std::borrow::Borrow; #[test] fn test_matmul_rcarray() @@ -126,9 +125,9 @@ fn test_slice_dyninput_vec_fixed() SliceOrIndex::Slice(Si::from(1..)), SliceOrIndex::Slice(Si::from(..).step(2)), ]); - arr.slice(info.borrow()); - arr.slice_mut(info.borrow()); - arr.view().slice_into(info.borrow()); + arr.slice(info.as_ref()); + arr.slice_mut(info.as_ref()); + arr.view().slice_into(info.as_ref()); arr.view().islice(&*info); } @@ -140,9 +139,9 @@ fn test_slice_dyninput_vec_dyn() SliceOrIndex::Slice(Si::from(1..)), SliceOrIndex::Slice(Si::from(..).step(2)), ]); - arr.slice(info.borrow()); - arr.slice_mut(info.borrow()); - arr.view().slice_into(info.borrow()); + arr.slice(info.as_ref()); + arr.slice_mut(info.as_ref()); + arr.view().slice_into(info.as_ref()); arr.view().islice(&*info); } diff --git a/tests/oper.rs b/tests/oper.rs index 9599b5943..1f69df0f5 100644 --- a/tests/oper.rs +++ b/tests/oper.rs @@ -11,7 +11,6 @@ use ndarray::{Si, SliceInfo}; use ndarray::SliceOrIndex::Slice; use ndarray::{Ix, Ixs}; -use std::borrow::Borrow; use std::fmt; use num_traits::Float; @@ -572,7 +571,7 @@ fn scaled_add_3() { { let mut av = a.slice_mut(s![..;s1, ..;s2]); - let c = c.slice(SliceInfo::<_, IxDyn>::new(cslice).borrow()); + let c = c.slice(SliceInfo::<_, IxDyn>::new(cslice).as_ref()); let mut answerv = answer.slice_mut(s![..;s1, ..;s2]); answerv += &(beta * &c); From c4f0bf363cc46095d8210e3f33fbb01fad858ca0 Mon Sep 17 00:00:00 2001 From: Jim Turner Date: Wed, 25 Oct 2017 11:49:51 -0400 Subject: [PATCH 18/30] Switch from deref + coerce to as_ref --- src/si.rs | 10 ++++++++++ tests/array.rs | 8 ++++---- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/si.rs b/src/si.rs index cffe155de..230ce2823 100644 --- a/src/si.rs +++ b/src/si.rs @@ -234,6 +234,16 @@ where } } +impl AsRef<[SliceOrIndex]> for SliceInfo +where + T: AsRef<[SliceOrIndex]>, + D: Dimension, +{ + fn as_ref(&self) -> &[SliceOrIndex] { + self.indices.as_ref() + } +} + impl AsRef> for SliceInfo where T: AsRef<[SliceOrIndex]>, diff --git a/tests/array.rs b/tests/array.rs index 19f9c6a6f..7729038fa 100644 --- a/tests/array.rs +++ b/tests/array.rs @@ -86,7 +86,7 @@ fn test_slice_dyninput_array_fixed() arr.slice(info); arr.slice_mut(info); arr.view().slice_into(info); - arr.view().islice(&**info); + arr.view().islice(info.as_ref()); } #[test] @@ -114,7 +114,7 @@ fn test_slice_dyninput_array_dyn() arr.slice(info); arr.slice_mut(info); arr.view().slice_into(info); - arr.view().islice(&**info); + arr.view().islice(info.as_ref()); } #[test] @@ -128,7 +128,7 @@ fn test_slice_dyninput_vec_fixed() arr.slice(info.as_ref()); arr.slice_mut(info.as_ref()); arr.view().slice_into(info.as_ref()); - arr.view().islice(&*info); + arr.view().islice(info.as_ref()); } #[test] @@ -142,7 +142,7 @@ fn test_slice_dyninput_vec_dyn() arr.slice(info.as_ref()); arr.slice_mut(info.as_ref()); arr.view().slice_into(info.as_ref()); - arr.view().islice(&*info); + arr.view().islice(info.as_ref()); } #[test] From 5cdd44c9f3746407e3e84b8c624a06dc55795158 Mon Sep 17 00:00:00 2001 From: Jim Turner Date: Wed, 25 Oct 2017 14:23:34 -0400 Subject: [PATCH 19/30] Remove Si type and rename si module --- src/dimension/dimension_trait.rs | 18 ++-- src/impl_methods.rs | 36 +++++--- src/lib.rs | 4 +- src/{si.rs => slice.rs} | 141 +++++++++++-------------------- tests/array.rs | 20 ++--- tests/oper.rs | 11 +-- 6 files changed, 100 insertions(+), 130 deletions(-) rename src/{si.rs => slice.rs} (77%) diff --git a/src/dimension/dimension_trait.rs b/src/dimension/dimension_trait.rs index 2f1b07036..03f2265c8 100644 --- a/src/dimension/dimension_trait.rs +++ b/src/dimension/dimension_trait.rs @@ -14,7 +14,7 @@ use std::ops::{Add, Sub, Mul, AddAssign, SubAssign, MulAssign}; use itertools::{enumerate, zip}; -use {Ix, Ixs, Ix0, Ix1, Ix2, Ix3, Ix4, Ix5, Ix6, IxDyn, Dim, Si, SliceOrIndex, IxDynImpl}; +use {Ix, Ixs, Ix0, Ix1, Ix2, Ix3, Ix4, Ix5, Ix6, IxDyn, Dim, SliceOrIndex, IxDynImpl}; use IntoDimension; use RemoveAxis; use {ArrayView1, ArrayViewMut1}; @@ -256,14 +256,14 @@ pub trait Dimension : Clone + Eq + Debug + Send + Sync + Default + /// Modify dimension, stride and return data pointer offset /// /// **Panics** if any stride is 0 or if any index is out of bounds. - fn do_slice(dim: &mut Ix, stride: &mut Ix, slice: Si) -> isize { + fn do_slice(dim: &mut Ix, stride: &mut Ix, start: isize, end: Option, step: isize) -> isize { let mut offset = 0; let dr = dim; let sr = stride; let m = *dr; let mi = m as Ixs; - let Si(b1, opt_e1, s1) = slice; + let (b1, opt_e1, s1) = (start, end, step); let e1 = opt_e1.unwrap_or(mi); let b1 = abs_index(mi, b1); @@ -271,11 +271,11 @@ pub trait Dimension : Clone + Eq + Debug + Send + Sync + Default + if e1 < b1 { e1 = b1; } ndassert!(b1 <= m, - "Slice begin {} is past end of axis of length {} (for Si {:?})", - b1, m, slice); + "Slice begin {} is past end of axis of length {}", + b1, m); ndassert!(e1 <= m, - "Slice end {} is past end of axis of length {} (for Si {:?})", - e1, m, slice); + "Slice end {} is past end of axis of length {}", + e1, m); let m = e1 - b1; // stride @@ -284,9 +284,7 @@ pub trait Dimension : Clone + Eq + Debug + Send + Sync + Default + // Data pointer offset offset += stride_offset(b1, *sr); // Adjust for strides - ndassert!(s1 != 0, - "Slice stride must not be none (for Si {:?})", - slice); + ndassert!(s1 != 0, "Slice stride must not be none"); // How to implement negative strides: // // Increase start pointer by diff --git a/src/impl_methods.rs b/src/impl_methods.rs index 6e10343f6..f6a62d6d7 100644 --- a/src/impl_methods.rs +++ b/src/impl_methods.rs @@ -32,7 +32,6 @@ use zip::Zip; use { NdIndex, - Si, SliceInfo, SliceOrIndex }; @@ -265,7 +264,7 @@ impl ArrayBase where S: Data, D: Dimension let mut new_strides = Do::zero_index_with_ndim(out_ndim); izip!(self.dim.slice(), self.strides.slice(), indices) .filter_map(|(d, s, slice_or_index)| match slice_or_index { - &SliceOrIndex::Slice(_) => Some((d, s)), + &SliceOrIndex::Slice(..) => Some((d, s)), &SliceOrIndex::Index(_) => None, }) .zip(izip!(new_dim.slice_mut(), new_strides.slice_mut())) @@ -297,7 +296,9 @@ impl ArrayBase where S: Data, D: Dimension .iter() .enumerate() .for_each(|(axis, slice_or_index)| match slice_or_index { - &SliceOrIndex::Slice(s) => self.islice_axis(Axis(axis), s), + &SliceOrIndex::Slice(start, end, step) => { + self.islice_axis(Axis(axis), start, end, step) + } &SliceOrIndex::Index(i) => { let i_usize = abs_index(self.shape()[axis] as Ixs, i); self.isubview(Axis(axis), i_usize) @@ -309,9 +310,15 @@ impl ArrayBase where S: Data, D: Dimension /// /// **Panics** if an index is out of bounds or stride is zero.
/// **Panics** if `axis` is out of bounds. - pub fn slice_axis(&self, axis: Axis, indices: Si) -> ArrayView { + pub fn slice_axis( + &self, + axis: Axis, + start: isize, + end: Option, + step: isize, + ) -> ArrayView { let mut arr = self.view(); - arr.islice_axis(axis, indices); + arr.islice_axis(axis, start, end, step); arr } @@ -319,11 +326,18 @@ impl ArrayBase where S: Data, D: Dimension /// /// **Panics** if an index is out of bounds or stride is zero.
/// **Panics** if `axis` is out of bounds. - pub fn slice_axis_mut(&mut self, axis: Axis, indices: Si) -> ArrayViewMut - where S: DataMut, + pub fn slice_axis_mut( + &mut self, + axis: Axis, + start: isize, + end: Option, + step: isize, + ) -> ArrayViewMut + where + S: DataMut, { let mut arr = self.view_mut(); - arr.islice_axis(axis, indices); + arr.islice_axis(axis, start, end, step); arr } @@ -331,11 +345,13 @@ impl ArrayBase where S: Data, D: Dimension /// /// **Panics** if an index is out of bounds or stride is zero.
/// **Panics** if `axis` is out of bounds. - pub fn islice_axis(&mut self, axis: Axis, indices: Si) { + pub fn islice_axis(&mut self, axis: Axis, start: isize, end: Option, step: isize) { let offset = D::do_slice( &mut self.dim.slice_mut()[axis.index()], &mut self.strides.slice_mut()[axis.index()], - indices + start, + end, + step, ); unsafe { self.ptr = self.ptr.offset(offset); diff --git a/src/lib.rs b/src/lib.rs index 1c0fa0adb..cd7a0c01d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -105,7 +105,7 @@ pub use dimension::NdIndex; pub use dimension::IxDynImpl; pub use indexes::{indices, indices_of}; pub use error::{ShapeError, ErrorKind}; -pub use si::{Si, S, SliceInfo, SliceNextDim, SliceOrIndex}; +pub use slice::{SliceInfo, SliceNextDim, SliceOrIndex}; use iterators::Baseiter; use iterators::{ElementsBase, ElementsBaseMut, Iter, IterMut}; @@ -143,7 +143,7 @@ mod free_functions; pub use free_functions::*; pub use iterators::iter; -mod si; +mod slice; mod layout; mod indexes; mod iterators; diff --git a/src/si.rs b/src/slice.rs similarity index 77% rename from src/si.rs rename to src/slice.rs index 230ce2823..a54d98c2d 100644 --- a/src/si.rs +++ b/src/slice.rs @@ -10,101 +10,35 @@ use std::fmt; use std::marker::PhantomData; use super::{Dimension, Ixs}; -// [a:b:s] syntax for example [:3], [::-1] -// [0,:] -- first row of matrix -// [:,0] -- first column of matrix - -#[derive(PartialEq, Eq, Hash)] -/// A slice, a description of a range of an array axis. +/// A slice (range with step) or an index. /// -/// Fields are `begin`, `end` and `stride`, where -/// negative `begin` or `end` indexes are counted from the back -/// of the axis. /// -/// If `end` is `None`, the slice extends to the end of the axis. +/// For the `Slice` variant, the fields are `begin`, `end`, and `step`, where +/// negative `begin` or `end` indexes are counted from the back of the axis. If +/// `end` is `None`, the slice extends to the end of the axis. /// -/// See also the [`s![] macro`](macro.s!.html), a convenient way to specify -/// an array of `Si`. +/// For the `Index` variant, the field is the index. /// -/// ## Examples +/// See also the [`s![] macro`](macro.s!.html) for a convenient way to create a +/// `&SliceInfo<[SliceOrIndex; n], D>`. /// -/// `Si(0, None, 1)` is the full range of an axis. -/// Python equivalent is `[:]`. Macro equivalent is `s![..]`. +/// ## Examples /// -/// `Si(a, Some(b), 2)` is every second element from `a` until `b`. -/// Python equivalent is `[a:b:2]`. Macro equivalent is `s![a..b;2]`. +/// `SliceOrIndex::Slice(0, None, 1)` is the full range of an axis. It can also +/// be created with `SliceOrIndex::from(..)`. The Python equivalent is `[:]`. +/// The macro equivalent is `s![..]`. /// -/// `Si(a, None, -1)` is every element, from `a` -/// until the end, in reverse order. Python equivalent is `[a::-1]`. -/// Macro equivalent is `s![a..;-1]`. +/// `SliceOrIndex::Slice(a, Some(b), 2)` is every second element from `a` until +/// `b`. It can also be created with `SliceOrIndex::from(a..b).step(2)`. The +/// Python equivalent is `[a:b:2]`. The macro equivalent is `s![a..b;2]`. /// -/// The constant [`S`] is a shorthand for the full range of an axis. -/// [`S`]: constant.S.html -pub struct Si(pub Ixs, pub Option, pub Ixs); - -impl fmt::Debug for Si { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - Si(0, _, _) => { } - Si(i, _, _) => { try!(write!(f, "{}", i)); } - } - try!(write!(f, "..")); - match *self { - Si(_, None, _) => { } - Si(_, Some(i), _) => { try!(write!(f, "{}", i)); } - } - match *self { - Si(_, _, 1) => { } - Si(_, _, s) => { try!(write!(f, ";{}", s)); } - } - Ok(()) - } -} - -impl From> for Si { - #[inline] - fn from(r: Range) -> Si { - Si(r.start, Some(r.end), 1) - } -} - -impl From> for Si { - #[inline] - fn from(r: RangeFrom) -> Si { - Si(r.start, None, 1) - } -} - -impl From> for Si { - #[inline] - fn from(r: RangeTo) -> Si { - Si(0, Some(r.end), 1) - } -} - -impl From for Si { - #[inline] - fn from(_: RangeFull) -> Si { - S - } -} - - -impl Si { - #[inline] - pub fn step(self, step: Ixs) -> Self { - Si(self.0, self.1, self.2 * step) - } -} - -copy_and_clone!{Si} - -/// Slice value for the full range of an axis. -pub const S: Si = Si(0, None, 1); - -#[derive(Debug, Eq, PartialEq)] +/// `SliceOrIndex::Slice(a, None, -1)` is every element, from `a` until the +/// end, in reverse order. It can also be created with +/// `SliceOrIndex::from(a..).step(-1)`. The Python equivalent is `[a::-1]`. The +/// macro equivalent is `s![a..;-1]`. +#[derive(Debug, PartialEq, Eq, Hash)] pub enum SliceOrIndex { - Slice(Si), + Slice(Ixs, Option, Ixs), Index(Ixs), } @@ -113,7 +47,7 @@ copy_and_clone!{SliceOrIndex} impl SliceOrIndex { pub fn is_slice(&self) -> bool { match self { - &SliceOrIndex::Slice(_) => true, + &SliceOrIndex::Slice(..) => true, _ => false, } } @@ -128,16 +62,37 @@ impl SliceOrIndex { #[inline] pub fn step(self, step: Ixs) -> Self { match self { - SliceOrIndex::Slice(s) => SliceOrIndex::Slice(s.step(step)), + SliceOrIndex::Slice(start, end, _) => SliceOrIndex::Slice(start, end, step), SliceOrIndex::Index(s) => SliceOrIndex::Index(s), } } } +impl fmt::Display for SliceOrIndex { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + SliceOrIndex::Index(index) => write!(f, "{}", index)?, + SliceOrIndex::Slice(start, end, step) => { + if start != 0 { + write!(f, "{}", start)?; + } + write!(f, "..")?; + if let Some(i) = end { + write!(f, "{}", i)?; + } + if step != 1 { + write!(f, ";{}", step)?; + } + } + } + Ok(()) + } +} + impl From> for SliceOrIndex { #[inline] fn from(r: Range) -> SliceOrIndex { - SliceOrIndex::Slice(Si::from(r)) + SliceOrIndex::Slice(r.start, Some(r.end), 1) } } @@ -151,21 +106,21 @@ impl From for SliceOrIndex { impl From> for SliceOrIndex { #[inline] fn from(r: RangeFrom) -> SliceOrIndex { - SliceOrIndex::Slice(Si::from(r)) + SliceOrIndex::Slice(r.start, None, 1) } } impl From> for SliceOrIndex { #[inline] fn from(r: RangeTo) -> SliceOrIndex { - SliceOrIndex::Slice(Si::from(r)) + SliceOrIndex::Slice(0, Some(r.end), 1) } } impl From for SliceOrIndex { #[inline] - fn from(r: RangeFull) -> SliceOrIndex { - SliceOrIndex::Slice(Si::from(r)) + fn from(_: RangeFull) -> SliceOrIndex { + SliceOrIndex::Slice(0, None, 1) } } diff --git a/tests/array.rs b/tests/array.rs index 7729038fa..876c34efe 100644 --- a/tests/array.rs +++ b/tests/array.rs @@ -6,7 +6,7 @@ extern crate ndarray; extern crate defmac; extern crate itertools; -use ndarray::{Si, SliceInfo, SliceOrIndex}; +use ndarray::{SliceInfo, SliceOrIndex}; use ndarray::prelude::*; use ndarray::{ rcarr2, @@ -94,8 +94,8 @@ fn test_slice_array_dyn() { let mut arr = Array2::::zeros((5, 5)); let info = &SliceInfo::<_, IxDyn>::new([ - SliceOrIndex::Slice(Si::from(1..)), - SliceOrIndex::Slice(Si::from(..).step(2)), + SliceOrIndex::from(1..), + SliceOrIndex::from(..).step(2), ]); arr.slice(info); arr.slice_mut(info); @@ -108,8 +108,8 @@ fn test_slice_dyninput_array_dyn() { let mut arr = Array2::::zeros((5, 5)).into_dyn(); let info = &SliceInfo::<_, IxDyn>::new([ - SliceOrIndex::Slice(Si::from(1..)), - SliceOrIndex::Slice(Si::from(..).step(2)), + SliceOrIndex::from(1..), + SliceOrIndex::from(..).step(2), ]); arr.slice(info); arr.slice_mut(info); @@ -122,8 +122,8 @@ fn test_slice_dyninput_vec_fixed() { let mut arr = Array2::::zeros((5, 5)).into_dyn(); let info = &SliceInfo::<_, Ix2>::new(vec![ - SliceOrIndex::Slice(Si::from(1..)), - SliceOrIndex::Slice(Si::from(..).step(2)), + SliceOrIndex::from(1..), + SliceOrIndex::from(..).step(2), ]); arr.slice(info.as_ref()); arr.slice_mut(info.as_ref()); @@ -136,8 +136,8 @@ fn test_slice_dyninput_vec_dyn() { let mut arr = Array2::::zeros((5, 5)).into_dyn(); let info = &SliceInfo::<_, IxDyn>::new(vec![ - SliceOrIndex::Slice(Si::from(1..)), - SliceOrIndex::Slice(Si::from(..).step(2)), + SliceOrIndex::from(1..), + SliceOrIndex::from(..).step(2), ]); arr.slice(info.as_ref()); arr.slice_mut(info.as_ref()); @@ -221,7 +221,7 @@ fn slice_oob() #[test] fn slice_axis_oob() { let a = RcArray::::zeros((3, 4)); - let _vi = a.slice_axis(Axis(0), Si(0, Some(10), 1)); + let _vi = a.slice_axis(Axis(0), 0, Some(10), 1); } #[should_panic] diff --git a/tests/oper.rs b/tests/oper.rs index 1f69df0f5..bb4a6fc2e 100644 --- a/tests/oper.rs +++ b/tests/oper.rs @@ -7,9 +7,7 @@ use ndarray::{rcarr1, rcarr2}; use ndarray::{LinalgScalar, Data}; use ndarray::linalg::general_mat_mul; use ndarray::linalg::general_mat_vec_mul; -use ndarray::{Si, SliceInfo}; -use ndarray::SliceOrIndex::Slice; -use ndarray::{Ix, Ixs}; +use ndarray::{Ix, Ixs, SliceInfo, SliceOrIndex}; use std::fmt; use num_traits::Float; @@ -562,9 +560,12 @@ fn scaled_add_3() { vec![n, q] }; let cslice = if n == 1 { - vec![Slice(Si(0, None, s2))] + vec![SliceOrIndex::from(..).step(s2)] } else { - vec![Slice(Si(0, None, s1)), Slice(Si(0, None, s2))] + vec![ + SliceOrIndex::from(..).step(s1), + SliceOrIndex::from(..).step(s2), + ] }; let c = range_mat64(n, q).into_shape(cdim).unwrap(); From 907d5874e1c487ff671255de23b9e881b1ff8498 Mon Sep 17 00:00:00 2001 From: Jim Turner Date: Wed, 25 Oct 2017 14:24:29 -0400 Subject: [PATCH 20/30] Reformat slice module --- src/slice.rs | 34 ++++++++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/src/slice.rs b/src/slice.rs index a54d98c2d..39243da19 100644 --- a/src/slice.rs +++ b/src/slice.rs @@ -5,7 +5,7 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::ops::{Range, RangeFrom, RangeTo, RangeFull, Deref}; +use std::ops::{Deref, Range, RangeFrom, RangeFull, RangeTo}; use std::fmt; use std::marker::PhantomData; use super::{Dimension, Ixs}; @@ -130,9 +130,14 @@ pub struct SliceInfo { indices: T, } -impl Deref for SliceInfo where D: Dimension { +impl Deref for SliceInfo +where + D: Dimension, +{ type Target = T; - fn deref(&self) -> &Self::Target { &self.indices } + fn deref(&self) -> &Self::Target { + &self.indices + } } impl SliceInfo @@ -220,7 +225,8 @@ impl Copy for SliceInfo where T: Copy, D: Dimension, -{ } +{ +} impl Clone for SliceInfo where @@ -311,25 +317,37 @@ macro_rules! s( // convert a..b;c into @step(a..b, c), final item (@parse $dim:expr, [$($stack:tt)*] $r:expr;$s:expr) => { unsafe { - &$crate::SliceInfo::new_unchecked([$($stack)* s!(@step $r, $s)], $crate::SliceNextDim::next_dim(&$r, $dim)) + &$crate::SliceInfo::new_unchecked( + [$($stack)* s!(@step $r, $s)], + $crate::SliceNextDim::next_dim(&$r, $dim), + ) } }; // convert a..b into @step(a..b, 1), final item (@parse $dim:expr, [$($stack:tt)*] $r:expr) => { unsafe { - &$crate::SliceInfo::new_unchecked([$($stack)* s!(@step $r, 1)], $crate::SliceNextDim::next_dim(&$r, $dim)) + &$crate::SliceInfo::new_unchecked( + [$($stack)* s!(@step $r, 1)], + $crate::SliceNextDim::next_dim(&$r, $dim), + ) } }; // convert a..b;c into @step(a..b, c), final item, trailing comma (@parse $dim:expr, [$($stack:tt)*] $r:expr;$s:expr ,) => { unsafe { - &$crate::SliceInfo::new_unchecked([$($stack)* s!(@step $r, $s)], $crate::SliceNextDim::next_dim(&$r, $dim)) + &$crate::SliceInfo::new_unchecked( + [$($stack)* s!(@step $r, $s)], + $crate::SliceNextDim::next_dim(&$r, $dim), + ) } }; // convert a..b into @step(a..b, 1), final item, trailing comma (@parse $dim:expr, [$($stack:tt)*] $r:expr ,) => { unsafe { - &$crate::SliceInfo::new_unchecked([$($stack)* s!(@step $r, 1)], $crate::SliceNextDim::next_dim(&$r, $dim)) + &$crate::SliceInfo::new_unchecked( + [$($stack)* s!(@step $r, 1)], + $crate::SliceNextDim::next_dim(&$r, $dim), + ) } }; // convert a..b;c into @step(a..b, c) From a056f02cf5c4083ea35e1d494996eb1603c19549 Mon Sep 17 00:00:00 2001 From: Jim Turner Date: Wed, 25 Oct 2017 15:14:32 -0400 Subject: [PATCH 21/30] Change SliceInfo to repr(C) --- src/slice.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/slice.rs b/src/slice.rs index 39243da19..13bb618d5 100644 --- a/src/slice.rs +++ b/src/slice.rs @@ -125,6 +125,7 @@ impl From for SliceOrIndex { } /// Represents all of the necessary information to perform a slice. +#[repr(C)] pub struct SliceInfo { out_dim: PhantomData, indices: T, From 2053e170de51ae3a9e38c243e5920d4bdbfa4366 Mon Sep 17 00:00:00 2001 From: Jim Turner Date: Thu, 26 Oct 2017 14:36:31 -0400 Subject: [PATCH 22/30] Rename .i*() to .*_inplace() --- examples/axis_ops.rs | 4 ++-- src/impl_methods.rs | 26 ++++++++++++++++---------- src/lib.rs | 10 +++++----- tests/array.rs | 34 +++++++++++++++++----------------- 4 files changed, 40 insertions(+), 34 deletions(-) diff --git a/examples/axis_ops.rs b/examples/axis_ops.rs index a5632e7a8..452dbba88 100644 --- a/examples/axis_ops.rs +++ b/examples/axis_ops.rs @@ -47,7 +47,7 @@ fn main() { } a.swap_axes(0, 1); a.swap_axes(0, 2); - a.islice(s![.., ..;-1, ..]); + a.slice_inplace(s![.., ..;-1, ..]); regularize(&mut a).ok(); let mut b = Array::::zeros((2, 3, 4)); @@ -64,6 +64,6 @@ fn main() { for (i, elt) in (0..).zip(&mut a) { *elt = i; } - a.islice(s![..;-1, ..;2, ..]); + a.slice_inplace(s![..;-1, ..;2, ..]); regularize(&mut a).ok(); } diff --git a/src/impl_methods.rs b/src/impl_methods.rs index f6a62d6d7..ab691f98f 100644 --- a/src/impl_methods.rs +++ b/src/impl_methods.rs @@ -254,7 +254,7 @@ impl ArrayBase where S: Data, D: Dimension Do: Dimension, { // Slice and subview in-place without changing the number of dimensions. - self.islice(&*info); + self.slice_inplace(&*info); let indices: &[SliceOrIndex] = (**info).as_ref(); @@ -289,7 +289,7 @@ impl ArrayBase where S: Data, D: Dimension /// /// **Panics** if an index is out of bounds or stride is zero.
/// (**Panics** if `D` is `IxDyn` and `info` does not match the number of array axes.) - pub fn islice(&mut self, indices: &D::SliceArg) { + pub fn slice_inplace(&mut self, indices: &D::SliceArg) { let indices: &[SliceOrIndex] = indices.as_ref(); assert_eq!(indices.len(), self.ndim()); indices @@ -297,11 +297,11 @@ impl ArrayBase where S: Data, D: Dimension .enumerate() .for_each(|(axis, slice_or_index)| match slice_or_index { &SliceOrIndex::Slice(start, end, step) => { - self.islice_axis(Axis(axis), start, end, step) + self.slice_axis_inplace(Axis(axis), start, end, step) } &SliceOrIndex::Index(i) => { let i_usize = abs_index(self.shape()[axis] as Ixs, i); - self.isubview(Axis(axis), i_usize) + self.subview_inplace(Axis(axis), i_usize) } }); } @@ -318,7 +318,7 @@ impl ArrayBase where S: Data, D: Dimension step: isize, ) -> ArrayView { let mut arr = self.view(); - arr.islice_axis(axis, start, end, step); + arr.slice_axis_inplace(axis, start, end, step); arr } @@ -337,7 +337,7 @@ impl ArrayBase where S: Data, D: Dimension S: DataMut, { let mut arr = self.view_mut(); - arr.islice_axis(axis, start, end, step); + arr.slice_axis_inplace(axis, start, end, step); arr } @@ -345,7 +345,13 @@ impl ArrayBase where S: Data, D: Dimension /// /// **Panics** if an index is out of bounds or stride is zero.
/// **Panics** if `axis` is out of bounds. - pub fn islice_axis(&mut self, axis: Axis, start: isize, end: Option, step: isize) { + pub fn slice_axis_inplace( + &mut self, + axis: Axis, + start: isize, + end: Option, + step: isize, + ) { let offset = D::do_slice( &mut self.dim.slice_mut()[axis.index()], &mut self.strides.slice_mut()[axis.index()], @@ -535,7 +541,7 @@ impl ArrayBase where S: Data, D: Dimension /// and select the subview of `index` along that axis. /// /// **Panics** if `index` is past the length of the axis. - pub fn isubview(&mut self, axis: Axis, index: Ix) { + pub fn subview_inplace(&mut self, axis: Axis, index: Ix) { dimension::do_sub(&mut self.dim, &mut self.ptr, &self.strides, axis.index(), index) } @@ -547,7 +553,7 @@ impl ArrayBase where S: Data, D: Dimension pub fn into_subview(mut self, axis: Axis, index: Ix) -> ArrayBase where D: RemoveAxis, { - self.isubview(axis, index); + self.subview_inplace(axis, index); self.remove_axis(axis) } @@ -578,7 +584,7 @@ impl ArrayBase where S: Data, D: Dimension { let mut subs = vec![self.view(); indices.len()]; for (&i, sub) in zip(indices, &mut subs[..]) { - sub.isubview(axis, i); + sub.subview_inplace(axis, i); } if subs.is_empty() { let mut dim = self.raw_dim(); diff --git a/src/lib.rs b/src/lib.rs index cd7a0c01d..c54a6a032 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -421,8 +421,8 @@ pub type Ixs = isize; /// ## Slicing /// /// You can use slicing to create a view of a subset of the data in -/// the array. Slicing methods include `.slice()`, `.islice()`, -/// `.slice_mut()`. +/// the array. Slicing methods include `.slice()`, `.slice_mut()`, +/// `.slice_inplace()`. /// /// The slicing argument can be passed using the macro [`s![]`](macro.s!.html), /// which will be used in all examples. (The explicit form is an instance of @@ -478,8 +478,8 @@ pub type Ixs = isize; /// /// Subview methods allow you to restrict the array view while removing /// one axis from the array. Subview methods include `.subview()`, -/// `.isubview()`, `.subview_mut()`. You can also take a subview by using a -/// single index instead of a range when slicing. +/// `.subview_inplace()`, `.subview_mut()`. You can also take a subview by +/// using a single index instead of a range when slicing. /// /// Subview takes two arguments: `axis` and `index`. /// @@ -527,7 +527,7 @@ pub type Ixs = isize; /// # } /// ``` /// -/// `.isubview()` modifies the view in the same way as `subview()`, but +/// `.subview_inplace()` modifies the view in the same way as `subview()`, but /// since it is *in place*, it cannot remove the collapsed axis. It becomes /// an axis of length 1. /// diff --git a/tests/array.rs b/tests/array.rs index 876c34efe..f1a5dc8b9 100644 --- a/tests/array.rs +++ b/tests/array.rs @@ -75,7 +75,7 @@ fn test_slice_array_fixed() arr.slice(info); arr.slice_mut(info); arr.view().slice_into(info); - arr.view().islice(info); + arr.view().slice_inplace(info); } #[test] @@ -86,7 +86,7 @@ fn test_slice_dyninput_array_fixed() arr.slice(info); arr.slice_mut(info); arr.view().slice_into(info); - arr.view().islice(info.as_ref()); + arr.view().slice_inplace(info.as_ref()); } #[test] @@ -100,7 +100,7 @@ fn test_slice_array_dyn() arr.slice(info); arr.slice_mut(info); arr.view().slice_into(info); - arr.view().islice(info); + arr.view().slice_inplace(info); } #[test] @@ -114,7 +114,7 @@ fn test_slice_dyninput_array_dyn() arr.slice(info); arr.slice_mut(info); arr.view().slice_into(info); - arr.view().islice(info.as_ref()); + arr.view().slice_inplace(info.as_ref()); } #[test] @@ -128,7 +128,7 @@ fn test_slice_dyninput_vec_fixed() arr.slice(info.as_ref()); arr.slice_mut(info.as_ref()); arr.view().slice_into(info.as_ref()); - arr.view().islice(info.as_ref()); + arr.view().slice_inplace(info.as_ref()); } #[test] @@ -142,7 +142,7 @@ fn test_slice_dyninput_vec_dyn() arr.slice(info.as_ref()); arr.slice_mut(info.as_ref()); arr.view().slice_into(info.as_ref()); - arr.view().islice(info.as_ref()); + arr.view().slice_inplace(info.as_ref()); } #[test] @@ -176,7 +176,7 @@ fn test_slice_with_subview() } #[test] -fn test_islice_with_isubview() +fn test_slice_inplace_with_subview_inplace() { let mut A = RcArray::::zeros((3, 5, 4)); for (i, elt) in A.iter_mut().enumerate() { @@ -184,7 +184,7 @@ fn test_islice_with_isubview() } let mut vi = A.view(); - vi.islice(s![1.., 2, ..;2]); + vi.slice_inplace(s![1.., 2, ..;2]); assert_eq!(vi.shape(), &[2, 1, 2]); assert!( vi.iter() @@ -193,7 +193,7 @@ fn test_islice_with_isubview() ); let mut vi = A.view(); - vi.islice(s![1, 2, ..;2]); + vi.slice_inplace(s![1, 2, ..;2]); assert_eq!(vi.shape(), &[1, 1, 2]); assert!( vi.iter() @@ -345,7 +345,7 @@ fn test_cow() assert_eq!(n[[0, 1]], 0); assert_eq!(n.get((0, 1)), Some(&0)); let mut rev = mat.reshape(4); - rev.islice(s![..;-1]); + rev.slice_inplace(s![..;-1]); assert_eq!(rev[0], 4); assert_eq!(rev[1], 3); assert_eq!(rev[2], 2); @@ -370,7 +370,7 @@ fn test_cow_shrink() // mutation shrinks the array and gives it different strides // let mut mat = RcArray::zeros((2, 3)); - //mat.islice(s![.., ..;2]); + //mat.slice_inplace(s![.., ..;2]); mat[[0, 0]] = 1; let n = mat.clone(); mat[[0, 1]] = 2; @@ -385,7 +385,7 @@ fn test_cow_shrink() assert_eq!(n.get((0, 1)), Some(&0)); // small has non-C strides this way let mut small = mat.reshape(6); - small.islice(s![4..;-1]); + small.slice_inplace(s![4..;-1]); assert_eq!(small[0], 6); assert_eq!(small[1], 5); let before = small.clone(); @@ -509,7 +509,7 @@ fn assign() let mut a = arr2(&[[1, 2], [3, 4]]); { let mut v = a.view_mut(); - v.islice(s![..1, ..]); + v.slice_inplace(s![..1, ..]); v.fill(0); } assert_eq!(a, arr2(&[[0, 0], [3, 4]])); @@ -1215,7 +1215,7 @@ fn to_owned_memory_order() { fn to_owned_neg_stride() { let mut c = arr2(&[[1, 2, 3], [4, 5, 6]]); - c.islice(s![.., ..;-1]); + c.slice_inplace(s![.., ..;-1]); let co = c.to_owned(); assert_eq!(c, co); } @@ -1380,10 +1380,10 @@ fn test_to_vec() { [7, 8, 9], [10,11,12]]); - a.islice(s![..;-1, ..]); + a.slice_inplace(s![..;-1, ..]); assert_eq!(a.row(3).to_vec(), vec![1, 2, 3]); assert_eq!(a.column(2).to_vec(), vec![12, 9, 6, 3]); - a.islice(s![.., ..;-1]); + a.slice_inplace(s![.., ..;-1]); assert_eq!(a.row(3).to_vec(), vec![3, 2, 1]); } @@ -1399,7 +1399,7 @@ fn test_array_clone_unalias() { #[test] fn test_array_clone_same_view() { let mut a = Array::from_iter(0..9).into_shape((3, 3)).unwrap(); - a.islice(s![..;-1, ..;-1]); + a.slice_inplace(s![..;-1, ..;-1]); let b = a.clone(); assert_eq!(a, b); } From 39371d353314c697e180496b08ee60222f5026a7 Mon Sep 17 00:00:00 2001 From: Jim Turner Date: Thu, 26 Oct 2017 14:37:14 -0400 Subject: [PATCH 23/30] Rename .slice_into() to .slice_move() --- src/impl_methods.rs | 6 +++--- src/lib.rs | 2 +- tests/array.rs | 12 ++++++------ 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/impl_methods.rs b/src/impl_methods.rs index ab691f98f..4fa485627 100644 --- a/src/impl_methods.rs +++ b/src/impl_methods.rs @@ -222,7 +222,7 @@ impl ArrayBase where S: Data, D: Dimension where Do: Dimension, { - self.view().slice_into(info) + self.view().slice_move(info) } /// Return a sliced read-write view of the array. @@ -238,7 +238,7 @@ impl ArrayBase where S: Data, D: Dimension Do: Dimension, S: DataMut, { - self.view_mut().slice_into(info) + self.view_mut().slice_move(info) } /// Slice the array’s view, possibly changing the number of dimensions. @@ -249,7 +249,7 @@ impl ArrayBase where S: Data, D: Dimension /// /// **Panics** if an index is out of bounds or stride is zero.
/// (**Panics** if `D` is `IxDyn` and `info` does not match the number of array axes.) - pub fn slice_into(mut self, info: &SliceInfo) -> ArrayBase + pub fn slice_move(mut self, info: &SliceInfo) -> ArrayBase where Do: Dimension, { diff --git a/src/lib.rs b/src/lib.rs index c54a6a032..31778e043 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -422,7 +422,7 @@ pub type Ixs = isize; /// /// You can use slicing to create a view of a subset of the data in /// the array. Slicing methods include `.slice()`, `.slice_mut()`, -/// `.slice_inplace()`. +/// `.slice_move()`, and `.slice_inplace()`. /// /// The slicing argument can be passed using the macro [`s![]`](macro.s!.html), /// which will be used in all examples. (The explicit form is an instance of diff --git a/tests/array.rs b/tests/array.rs index f1a5dc8b9..444f47da6 100644 --- a/tests/array.rs +++ b/tests/array.rs @@ -74,7 +74,7 @@ fn test_slice_array_fixed() let info = s![1.., ..;2]; arr.slice(info); arr.slice_mut(info); - arr.view().slice_into(info); + arr.view().slice_move(info); arr.view().slice_inplace(info); } @@ -85,7 +85,7 @@ fn test_slice_dyninput_array_fixed() let info = s![1.., ..;2]; arr.slice(info); arr.slice_mut(info); - arr.view().slice_into(info); + arr.view().slice_move(info); arr.view().slice_inplace(info.as_ref()); } @@ -99,7 +99,7 @@ fn test_slice_array_dyn() ]); arr.slice(info); arr.slice_mut(info); - arr.view().slice_into(info); + arr.view().slice_move(info); arr.view().slice_inplace(info); } @@ -113,7 +113,7 @@ fn test_slice_dyninput_array_dyn() ]); arr.slice(info); arr.slice_mut(info); - arr.view().slice_into(info); + arr.view().slice_move(info); arr.view().slice_inplace(info.as_ref()); } @@ -127,7 +127,7 @@ fn test_slice_dyninput_vec_fixed() ]); arr.slice(info.as_ref()); arr.slice_mut(info.as_ref()); - arr.view().slice_into(info.as_ref()); + arr.view().slice_move(info.as_ref()); arr.view().slice_inplace(info.as_ref()); } @@ -141,7 +141,7 @@ fn test_slice_dyninput_vec_dyn() ]); arr.slice(info.as_ref()); arr.slice_mut(info.as_ref()); - arr.view().slice_into(info.as_ref()); + arr.view().slice_move(info.as_ref()); arr.view().slice_inplace(info.as_ref()); } From 1848f6b7ea87cb322d9d24eedfd6774a4dabc1dc Mon Sep 17 00:00:00 2001 From: Jim Turner Date: Thu, 26 Oct 2017 14:58:51 -0400 Subject: [PATCH 24/30] Fix remaining calls to .islice() --- serialization-tests/tests/serialize.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/serialization-tests/tests/serialize.rs b/serialization-tests/tests/serialize.rs index 0355981eb..99d9f8191 100644 --- a/serialization-tests/tests/serialize.rs +++ b/serialization-tests/tests/serialize.rs @@ -53,7 +53,7 @@ fn serial_many_dim() { // Test a sliced array. let mut a = RcArray::linspace(0., 31., 32).reshape((2, 2, 2, 4)); - a.islice(s![..;-1, .., .., ..2]); + a.slice_inplace(s![..;-1, .., .., ..2]); let serial = json::encode(&a).unwrap(); println!("Encode {:?} => {:?}", a, serial); let res = json::decode::>(&serial); @@ -114,7 +114,7 @@ fn serial_many_dim_serde() { // Test a sliced array. let mut a = RcArray::linspace(0., 31., 32).reshape((2, 2, 2, 4)); - a.islice(s![..;-1, .., .., ..2]); + a.slice_inplace(s![..;-1, .., .., ..2]); let serial = serde_json::to_string(&a).unwrap(); println!("Encode {:?} => {:?}", a, serial); let res = serde_json::from_str::>(&serial); @@ -221,7 +221,7 @@ fn serial_many_dim_serde_msgpack() { // Test a sliced array. let mut a = RcArray::linspace(0., 31., 32).reshape((2, 2, 2, 4)); - a.islice(s![..;-1, .., .., ..2]); + a.slice_inplace(s![..;-1, .., .., ..2]); let mut buf = Vec::new(); serde::Serialize::serialize(&a, &mut rmp_serde::Serializer::new(&mut buf)).ok().unwrap(); @@ -273,7 +273,7 @@ fn serial_many_dim_ron() { // Test a sliced array. let mut a = RcArray::linspace(0., 31., 32).reshape((2, 2, 2, 4)); - a.islice(s![..;-1, .., .., ..2]); + a.slice_inplace(s![..;-1, .., .., ..2]); let a_s = ron_serialize(&a).unwrap(); From 5bc5cd3ecc9b47f500299954e5f206bac26ebdb9 Mon Sep 17 00:00:00 2001 From: Jim Turner Date: Thu, 26 Oct 2017 15:01:58 -0400 Subject: [PATCH 25/30] Rename .into_subview() to .subview_move() This maintains consistency with .slice_move(). --- src/impl_methods.rs | 6 +++--- tests/dimension.rs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/impl_methods.rs b/src/impl_methods.rs index 4fa485627..136060b21 100644 --- a/src/impl_methods.rs +++ b/src/impl_methods.rs @@ -502,7 +502,7 @@ impl ArrayBase where S: Data, D: Dimension pub fn subview(&self, axis: Axis, index: Ix) -> ArrayView where D: RemoveAxis, { - self.view().into_subview(axis, index) + self.view().subview_move(axis, index) } /// Along `axis`, select the subview `index` and return a read-write view @@ -534,7 +534,7 @@ impl ArrayBase where S: Data, D: Dimension where S: DataMut, D: RemoveAxis, { - self.view_mut().into_subview(axis, index) + self.view_mut().subview_move(axis, index) } /// Collapse dimension `axis` into length one, @@ -550,7 +550,7 @@ impl ArrayBase where S: Data, D: Dimension /// with that axis removed. /// /// See [`.subview()`](#method.subview) and [*Subviews*](#subviews) for full documentation. - pub fn into_subview(mut self, axis: Axis, index: Ix) -> ArrayBase + pub fn subview_move(mut self, axis: Axis, index: Ix) -> ArrayBase where D: RemoveAxis, { self.subview_inplace(axis, index); diff --git a/tests/dimension.rs b/tests/dimension.rs index fb2817ddf..a8086831d 100644 --- a/tests/dimension.rs +++ b/tests/dimension.rs @@ -53,7 +53,7 @@ fn remove_axis() a.subview(Axis(1), 0); let a = RcArray::::zeros(vec![4,5,6]); - let _b = a.into_subview(Axis(1), 0).reshape((4, 6)).reshape(vec![2, 3, 4]); + let _b = a.subview_move(Axis(1), 0).reshape((4, 6)).reshape(vec![2, 3, 4]); } #[test] From 8c1fc99b446742820bbd57c6875014511bdc9cbd Mon Sep 17 00:00:00 2001 From: Jim Turner Date: Thu, 26 Oct 2017 15:23:51 -0400 Subject: [PATCH 26/30] Revert "Rename .into_subview() to .subview_move()" This reverts commit 5bc5cd3ecc9b47f500299954e5f206bac26ebdb9. --- src/impl_methods.rs | 6 +++--- tests/dimension.rs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/impl_methods.rs b/src/impl_methods.rs index 136060b21..4fa485627 100644 --- a/src/impl_methods.rs +++ b/src/impl_methods.rs @@ -502,7 +502,7 @@ impl ArrayBase where S: Data, D: Dimension pub fn subview(&self, axis: Axis, index: Ix) -> ArrayView where D: RemoveAxis, { - self.view().subview_move(axis, index) + self.view().into_subview(axis, index) } /// Along `axis`, select the subview `index` and return a read-write view @@ -534,7 +534,7 @@ impl ArrayBase where S: Data, D: Dimension where S: DataMut, D: RemoveAxis, { - self.view_mut().subview_move(axis, index) + self.view_mut().into_subview(axis, index) } /// Collapse dimension `axis` into length one, @@ -550,7 +550,7 @@ impl ArrayBase where S: Data, D: Dimension /// with that axis removed. /// /// See [`.subview()`](#method.subview) and [*Subviews*](#subviews) for full documentation. - pub fn subview_move(mut self, axis: Axis, index: Ix) -> ArrayBase + pub fn into_subview(mut self, axis: Axis, index: Ix) -> ArrayBase where D: RemoveAxis, { self.subview_inplace(axis, index); diff --git a/tests/dimension.rs b/tests/dimension.rs index a8086831d..fb2817ddf 100644 --- a/tests/dimension.rs +++ b/tests/dimension.rs @@ -53,7 +53,7 @@ fn remove_axis() a.subview(Axis(1), 0); let a = RcArray::::zeros(vec![4,5,6]); - let _b = a.subview_move(Axis(1), 0).reshape((4, 6)).reshape(vec![2, 3, 4]); + let _b = a.into_subview(Axis(1), 0).reshape((4, 6)).reshape(vec![2, 3, 4]); } #[test] From 6561c223154b345fd610866a9ea84f5e5c9af0ea Mon Sep 17 00:00:00 2001 From: Jim Turner Date: Thu, 26 Oct 2017 17:04:25 -0400 Subject: [PATCH 27/30] Update documentation --- src/dimension/dimension_trait.rs | 4 +- src/impl_methods.rs | 25 +++++++--- src/lib.rs | 53 +++++++++++++++------ src/slice.rs | 80 +++++++++++++++++++++++--------- 4 files changed, 116 insertions(+), 46 deletions(-) diff --git a/src/dimension/dimension_trait.rs b/src/dimension/dimension_trait.rs index 03f2265c8..5401ca00e 100644 --- a/src/dimension/dimension_trait.rs +++ b/src/dimension/dimension_trait.rs @@ -57,8 +57,8 @@ pub trait Dimension : Clone + Eq + Debug + Send + Sync + Default + /// - and so on.. /// - For `IxDyn`: `[SliceOrIndex]` /// - /// The easiest way to create a `SliceArg` is using the macro - /// [`s![]`](macro.s!.html). + /// The easiest way to create a `&SliceInfo` is using the + /// [`s![]`](macro.s!.html) macro. type SliceArg: ?Sized + AsRef<[SliceOrIndex]>; /// Pattern matching friendly form of the dimension value. /// diff --git a/src/impl_methods.rs b/src/impl_methods.rs index 4fa485627..0d0000a9c 100644 --- a/src/impl_methods.rs +++ b/src/impl_methods.rs @@ -209,11 +209,12 @@ impl ArrayBase where S: Data, D: Dimension } - /// Return a sliced array. + /// Return a sliced view of the array. /// /// See [*Slicing*](#slicing) for full documentation. - /// See also [`D::SliceArg`]. + /// See also [`SliceInfo`] and [`D::SliceArg`]. /// + /// [`SliceInfo`]: struct.SliceInfo.html /// [`D::SliceArg`]: trait.Dimension.html#associatedtype.SliceArg /// /// **Panics** if an index is out of bounds or stride is zero.
@@ -227,8 +228,10 @@ impl ArrayBase where S: Data, D: Dimension /// Return a sliced read-write view of the array. /// - /// See also [`D::SliceArg`]. + /// See [*Slicing*](#slicing) for full documentation. + /// See also [`SliceInfo`] and [`D::SliceArg`]. /// + /// [`SliceInfo`]: struct.SliceInfo.html /// [`D::SliceArg`]: trait.Dimension.html#associatedtype.SliceArg /// /// **Panics** if an index is out of bounds or stride is zero.
@@ -241,10 +244,12 @@ impl ArrayBase where S: Data, D: Dimension self.view_mut().slice_move(info) } - /// Slice the array’s view, possibly changing the number of dimensions. + /// Slice the array, possibly changing the number of dimensions. /// - /// See also [`D::SliceArg`]. + /// See [*Slicing*](#slicing) for full documentation. + /// See also [`SliceInfo`] and [`D::SliceArg`]. /// + /// [`SliceInfo`]: struct.SliceInfo.html /// [`D::SliceArg`]: trait.Dimension.html#associatedtype.SliceArg /// /// **Panics** if an index is out of bounds or stride is zero.
@@ -281,8 +286,14 @@ impl ArrayBase where S: Data, D: Dimension } } - /// Slice the array’s view in place without changing the number of dimensions. + /// Slice the array in place without changing the number of dimensions. + /// + /// Note that [`&SliceInfo`](struct.SliceInfo.html) (produced by the + /// [`s![]`](macro.s!.html) macro) will usually coerce into `&D::SliceArg` + /// automatically, but in some cases (e.g. if `D` is `IxDyn`), you may need + /// to call `.as_ref()`. /// + /// See [*Slicing*](#slicing) for full documentation. /// See also [`D::SliceArg`]. /// /// [`D::SliceArg`]: trait.Dimension.html#associatedtype.SliceArg @@ -341,7 +352,7 @@ impl ArrayBase where S: Data, D: Dimension arr } - /// Slice the array’s view in place along the specified axis. + /// Slice the array in place along the specified axis. /// /// **Panics** if an index is out of bounds or stride is zero.
/// **Panics** if `axis` is out of bounds. diff --git a/src/lib.rs b/src/lib.rs index 31778e043..0c85d68fc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -421,13 +421,24 @@ pub type Ixs = isize; /// ## Slicing /// /// You can use slicing to create a view of a subset of the data in -/// the array. Slicing methods include `.slice()`, `.slice_mut()`, -/// `.slice_move()`, and `.slice_inplace()`. +/// the array. Slicing methods include [`.slice()`], [`.slice_mut()`], +/// [`.slice_move()`], and [`.slice_inplace()`]. /// /// The slicing argument can be passed using the macro [`s![]`](macro.s!.html), /// which will be used in all examples. (The explicit form is an instance of -/// struct [`SliceInfo`]; see its docs for more information.) -/// [`SliceInfo`]: struct.SliceInfo.html +/// [`&SliceInfo`]; see its docs for more information.) +/// +/// [`&SliceInfo`]: struct.SliceInfo.html +/// +/// If a range is used, the axis is preserved. If an index is used, a subview +/// is taken with respect to the axis. See [*Subviews*](#subviews) for more +/// information about subviews. Note that [`.slice_inplace()`] behaves like +/// [`.subview_inplace()`] by preserving the number of dimensions. +/// +/// [`.slice()`]: #method.slice +/// [`.slice_mut()`]: #method.slice_mut +/// [`.slice_move()`]: #method.slice_move +/// [`.slice_inplace()`]: #method.slice_inplace /// /// ``` /// // import the s![] macro @@ -455,8 +466,6 @@ pub type Ixs = isize; /// // - Every element in each row: `..` /// /// let b = a.slice(s![.., 0..1, ..]); -/// // without the macro, the explicit argument is `&[S, Si(0, Some(1), 1), S]` -/// /// let c = arr3(&[[[ 1, 2, 3]], /// [[ 7, 8, 9]]]); /// assert_eq!(b, c); @@ -471,18 +480,36 @@ pub type Ixs = isize; /// let e = arr3(&[[[ 6, 5, 4]], /// [[12, 11, 10]]]); /// assert_eq!(d, e); +/// assert_eq!(d.shape(), &[2, 1, 3]); +/// +/// // Let’s create a slice while taking a subview with +/// // +/// // - Both submatrices of the greatest dimension: `..` +/// // - The last row in each submatrix, removing that axis: `-1` +/// // - Row elements in reverse order: `..;-1` +/// let f = a.slice(s![.., -1, ..;-1]); +/// let g = arr3(&[[ 6, 5, 4], +/// [12, 11, 10]]); +/// assert_eq!(f, g); +/// assert_eq!(f.shape(), &[2, 3]); /// } /// ``` /// /// ## Subviews /// -/// Subview methods allow you to restrict the array view while removing -/// one axis from the array. Subview methods include `.subview()`, -/// `.subview_inplace()`, `.subview_mut()`. You can also take a subview by -/// using a single index instead of a range when slicing. +/// Subview methods allow you to restrict the array view while removing one +/// axis from the array. Subview methods include [`.subview()`], +/// [`.subview_mut()`], [`.into_subview()`], and [`.subview_inplace()`]. You +/// can also take a subview by using a single index instead of a range when +/// slicing. /// /// Subview takes two arguments: `axis` and `index`. /// +/// [`.subview()`]: #method.subview +/// [`.subview_mut()`]: #method.subview_mut +/// [`.into_subview()`]: #method.into_subview +/// [`.subview_inplace()`]: #method.subview_inplace +/// /// ``` /// #[macro_use(s)] extern crate ndarray; /// @@ -520,15 +547,13 @@ pub type Ixs = isize; /// [ 7, 10]])); /// /// // You can take multiple subviews at once (and slice at the same time) -/// /// let double_sub = a.slice(s![1, .., 0]); -/// /// assert_eq!(double_sub, aview1(&[7, 10])); /// # } /// ``` /// -/// `.subview_inplace()` modifies the view in the same way as `subview()`, but -/// since it is *in place*, it cannot remove the collapsed axis. It becomes +/// [`.subview_inplace()`] modifies the view in the same way as [`.subview()`], +/// but since it is *in place*, it cannot remove the collapsed axis. It becomes /// an axis of length 1. /// /// `.outer_iter()` is an iterator of every subview along the zeroth (outer) diff --git a/src/slice.rs b/src/slice.rs index 13bb618d5..8cca262b8 100644 --- a/src/slice.rs +++ b/src/slice.rs @@ -12,14 +12,7 @@ use super::{Dimension, Ixs}; /// A slice (range with step) or an index. /// -/// -/// For the `Slice` variant, the fields are `begin`, `end`, and `step`, where -/// negative `begin` or `end` indexes are counted from the back of the axis. If -/// `end` is `None`, the slice extends to the end of the axis. -/// -/// For the `Index` variant, the field is the index. -/// -/// See also the [`s![] macro`](macro.s!.html) for a convenient way to create a +/// See also the [`s![]`](macro.s!.html) macro for a convenient way to create a /// `&SliceInfo<[SliceOrIndex; n], D>`. /// /// ## Examples @@ -38,13 +31,18 @@ use super::{Dimension, Ixs}; /// macro equivalent is `s![a..;-1]`. #[derive(Debug, PartialEq, Eq, Hash)] pub enum SliceOrIndex { + /// A range with step size. The fields are `begin`, `end`, and `step`, + /// where negative `begin` or `end` indexes are counted from the back of + /// the axis. If `end` is `None`, the slice extends to the end of the axis. Slice(Ixs, Option, Ixs), + /// A single index. Index(Ixs), } copy_and_clone!{SliceOrIndex} impl SliceOrIndex { + /// Returns `true` if `self` is a `Slice` value. pub fn is_slice(&self) -> bool { match self { &SliceOrIndex::Slice(..) => true, @@ -52,6 +50,7 @@ impl SliceOrIndex { } } + /// Returns `true` if `self` is an `Index` value. pub fn is_index(&self) -> bool { match self { &SliceOrIndex::Index(_) => true, @@ -59,6 +58,7 @@ impl SliceOrIndex { } } + /// Returns a new `SliceOrIndex` with the given step size. #[inline] pub fn step(self, step: Ixs) -> Self { match self { @@ -125,6 +125,12 @@ impl From for SliceOrIndex { } /// Represents all of the necessary information to perform a slice. +/// +/// The type `T` is typically `[SliceOrIndex; n]`, `[SliceOrIndex]`, or +/// `Vec`. The type `D` is the output dimension after calling +/// [`.slice()`]. +/// +/// [`.slice()`]: struct.ArrayBase.html#method.slice #[repr(C)] pub struct SliceInfo { out_dim: PhantomData, @@ -183,7 +189,13 @@ where T: AsRef<[SliceOrIndex]>, D: Dimension, { - /// Returns the number of dimensions after slicing and taking subviews. + /// Returns the number of dimensions after calling + /// [`.slice()`](struct.ArrayBase.html#method.slice) (including taking + /// subviews). + /// + /// If `D` is a fixed-size dimension type, then this is equivalent to + /// `D::NDIM.unwrap()`. Otherwise, the value is calculated by iterating + /// over the ranges/indices. pub fn out_ndim(&self) -> usize { D::NDIM.unwrap_or_else(|| { self.indices @@ -280,23 +292,45 @@ impl SliceNextDim for Ixs { /// Slice argument constructor. /// -/// `s![]` takes a list of ranges, separated by comma, with optional strides -/// that are separated from the range by a semicolon. It is converted into a -/// `SliceInfo` instance. +/// `s![]` takes a list of ranges/indices, separated by comma, with optional +/// step sizes that are separated from the range by a semicolon. It is +/// converted into a [`&SliceInfo`] instance. +/// +/// [`&SliceInfo`]: struct.SliceInfo.html +/// +/// Each range/index uses signed indices, where a negative value is counted +/// from the end of the axis. Step sizes are also signed and may be negative, +/// but must not be zero. +/// +/// The syntax is `s![` *[ axis-slice-or-index [, axis-slice-or-index [ , ... ] +/// ] ]* `]`, where *axis-slice-or-index* is any of the following: +/// +/// * *index*: an index to use for taking a subview with respect to that axis +/// * *range*: a range with step size 1 to use for slicing that axis +/// * *range* `;` *step*: a range with step size *step* to use for slicing that axis +/// +/// The number of *axis-slice-or-index* must match the number of axes in the +/// array. *index*, *range*, and *step* can be expressions. *index* and *step* +/// must be of type [`Ixs`]. *range* can be of type `Range`, +/// `RangeTo`, `RangeFrom`, or `RangeFull`. +/// +/// [`Ixs`]: type.Ixs.html +/// +/// For example `s![0..4;2, 6, 1..5]` is a slice of the first axis for 0..4 +/// with step size 2, a subview of the second axis at index 6, and a slice of +/// the third axis for 1..5 with default step size 1. The input array must have +/// 3 dimensions. The resulting slice would have shape `[2, 4]` for +/// [`.slice()`], [`.slice_mut()`], and [`.slice_move()`], and shape +/// `[2, 1, 4]` for [`.slice_inplace()`]. /// -/// Each range uses signed indices, where a negative value is counted from -/// the end of the axis. Strides are also signed and may be negative, but -/// must not be zero. +/// [`.slice()`]: struct.ArrayBase.html#method.slice +/// [`.slice_mut()`]: struct.ArrayBase.html#method.slice_mut +/// [`.slice_move()`]: struct.ArrayBase.html#method.slice_move +/// [`.slice_inplace()`]: struct.ArrayBase.html#method.slice_inplace /// -/// The syntax is `s![` *[ axis-slice [, axis-slice [ , ... ] ] ]* `]`. -/// Where *axis-slice* is either *i* `..` *j* or *i* `..` *j* `;` *step*, -/// and *i* is the start index, *j* end index and *step* the element step -/// size (which defaults to 1). The number of *axis-slice* must match the -/// number of axes in the array. +/// See also [*Slicing*](struct.ArrayBase.html#slicing). /// -/// For example `s![0..4;2, 1..5]` is a slice of rows 0..4 with step size 2, -/// and columns 1..5 with default step size 1. The slice would have -/// shape `[2, 4]`. +/// # Example /// /// ``` /// #[macro_use] From db9adfa068df734a91df0b3ccb3227f22f638561 Mon Sep 17 00:00:00 2001 From: Jim Turner Date: Thu, 26 Oct 2017 17:11:23 -0400 Subject: [PATCH 28/30] Update stride -> step size in docs --- src/impl_methods.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/impl_methods.rs b/src/impl_methods.rs index 0d0000a9c..b09671928 100644 --- a/src/impl_methods.rs +++ b/src/impl_methods.rs @@ -217,7 +217,7 @@ impl ArrayBase where S: Data, D: Dimension /// [`SliceInfo`]: struct.SliceInfo.html /// [`D::SliceArg`]: trait.Dimension.html#associatedtype.SliceArg /// - /// **Panics** if an index is out of bounds or stride is zero.
+ /// **Panics** if an index is out of bounds or step size is zero.
/// (**Panics** if `D` is `IxDyn` and `info` does not match the number of array axes.) pub fn slice(&self, info: &SliceInfo) -> ArrayView where @@ -234,7 +234,7 @@ impl ArrayBase where S: Data, D: Dimension /// [`SliceInfo`]: struct.SliceInfo.html /// [`D::SliceArg`]: trait.Dimension.html#associatedtype.SliceArg /// - /// **Panics** if an index is out of bounds or stride is zero.
+ /// **Panics** if an index is out of bounds or step size is zero.
/// (**Panics** if `D` is `IxDyn` and `info` does not match the number of array axes.) pub fn slice_mut(&mut self, info: &SliceInfo) -> ArrayViewMut where @@ -252,7 +252,7 @@ impl ArrayBase where S: Data, D: Dimension /// [`SliceInfo`]: struct.SliceInfo.html /// [`D::SliceArg`]: trait.Dimension.html#associatedtype.SliceArg /// - /// **Panics** if an index is out of bounds or stride is zero.
+ /// **Panics** if an index is out of bounds or step size is zero.
/// (**Panics** if `D` is `IxDyn` and `info` does not match the number of array axes.) pub fn slice_move(mut self, info: &SliceInfo) -> ArrayBase where @@ -298,7 +298,7 @@ impl ArrayBase where S: Data, D: Dimension /// /// [`D::SliceArg`]: trait.Dimension.html#associatedtype.SliceArg /// - /// **Panics** if an index is out of bounds or stride is zero.
+ /// **Panics** if an index is out of bounds or step size is zero.
/// (**Panics** if `D` is `IxDyn` and `info` does not match the number of array axes.) pub fn slice_inplace(&mut self, indices: &D::SliceArg) { let indices: &[SliceOrIndex] = indices.as_ref(); @@ -319,7 +319,7 @@ impl ArrayBase where S: Data, D: Dimension /// Return a view of the array, sliced along the specified axis. /// - /// **Panics** if an index is out of bounds or stride is zero.
+ /// **Panics** if an index is out of bounds or step size is zero.
/// **Panics** if `axis` is out of bounds. pub fn slice_axis( &self, @@ -335,7 +335,7 @@ impl ArrayBase where S: Data, D: Dimension /// Return a mutable view of the array, sliced along the specified axis. /// - /// **Panics** if an index is out of bounds or stride is zero.
+ /// **Panics** if an index is out of bounds or step size is zero.
/// **Panics** if `axis` is out of bounds. pub fn slice_axis_mut( &mut self, @@ -354,7 +354,7 @@ impl ArrayBase where S: Data, D: Dimension /// Slice the array in place along the specified axis. /// - /// **Panics** if an index is out of bounds or stride is zero.
+ /// **Panics** if an index is out of bounds or step size is zero.
/// **Panics** if `axis` is out of bounds. pub fn slice_axis_inplace( &mut self, From 6f44baca2b46d4b1422fa3112aec37b6398a36ae Mon Sep 17 00:00:00 2001 From: Jim Turner Date: Thu, 26 Oct 2017 17:11:45 -0400 Subject: [PATCH 29/30] Change isize -> Ixs in slice_axis*() signatures --- src/impl_methods.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/impl_methods.rs b/src/impl_methods.rs index b09671928..6987b3e62 100644 --- a/src/impl_methods.rs +++ b/src/impl_methods.rs @@ -324,9 +324,9 @@ impl ArrayBase where S: Data, D: Dimension pub fn slice_axis( &self, axis: Axis, - start: isize, - end: Option, - step: isize, + start: Ixs, + end: Option, + step: Ixs, ) -> ArrayView { let mut arr = self.view(); arr.slice_axis_inplace(axis, start, end, step); @@ -340,9 +340,9 @@ impl ArrayBase where S: Data, D: Dimension pub fn slice_axis_mut( &mut self, axis: Axis, - start: isize, - end: Option, - step: isize, + start: Ixs, + end: Option, + step: Ixs, ) -> ArrayViewMut where S: DataMut, @@ -359,9 +359,9 @@ impl ArrayBase where S: Data, D: Dimension pub fn slice_axis_inplace( &mut self, axis: Axis, - start: isize, - end: Option, - step: isize, + start: Ixs, + end: Option, + step: Ixs, ) { let offset = D::do_slice( &mut self.dim.slice_mut()[axis.index()], From 190ca342189fd38f122028a8799cf1d8bc0e4eae Mon Sep 17 00:00:00 2001 From: Jim Turner Date: Thu, 26 Oct 2017 17:14:01 -0400 Subject: [PATCH 30/30] Fix failing doc test --- src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 0c85d68fc..1fbc71e22 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -445,7 +445,7 @@ pub type Ixs = isize; /// #[macro_use(s)] /// extern crate ndarray; /// -/// use ndarray::arr3; +/// use ndarray::{arr2, arr3}; /// /// fn main() { /// @@ -488,7 +488,7 @@ pub type Ixs = isize; /// // - The last row in each submatrix, removing that axis: `-1` /// // - Row elements in reverse order: `..;-1` /// let f = a.slice(s![.., -1, ..;-1]); -/// let g = arr3(&[[ 6, 5, 4], +/// let g = arr2(&[[ 6, 5, 4], /// [12, 11, 10]]); /// assert_eq!(f, g); /// assert_eq!(f.shape(), &[2, 3]);