diff --git a/.travis.yml b/.travis.yml index 9bb06918e..e6d67261d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,7 +4,7 @@ sudo: required dist: trusty matrix: include: - - rust: 1.26.0 + - rust: 1.27.0 env: - FEATURES='test docs' - rust: stable diff --git a/README.rst b/README.rst index b7703e6df..fbbb5698c 100644 --- a/README.rst +++ b/README.rst @@ -92,9 +92,10 @@ Recent Changes (ndarray) - Add ``var_axis`` method for computing variance by @LukeMathWalker. - Add support for 128-bit integer scalars (``i128`` and ``u128``). + - Add support for slicing with inclusive ranges (``start..=end`` and ``..=end``). - Bump ``num-traits`` and ``num-complex`` to version ``0.2``. - Bump ``blas-src`` to version ``0.2``. - - Bump minimum required Rust version to 1.26. + - Bump minimum required Rust version to 1.27. - Additional contributors to this release: @ExpHP, @jturner314, @alexbool, @messense, @danmack, @nbro - 0.11.2 diff --git a/src/lib.rs b/src/lib.rs index 185cdaf62..9868b0c53 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -53,7 +53,7 @@ //! + Efficient floating point matrix multiplication even for very large //! matrices; can optionally use BLAS to improve it further. //! + See also the [`ndarray-parallel`] crate for integration with rayon. -//! - **Requires Rust 1.26** +//! - **Requires Rust 1.27** //! //! [`ndarray-parallel`]: https://docs.rs/ndarray-parallel //! diff --git a/src/slice.rs b/src/slice.rs index 7f0d84ac0..baa62fee7 100644 --- a/src/slice.rs +++ b/src/slice.rs @@ -6,15 +6,16 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. use error::{ShapeError, ErrorKind}; -use std::ops::{Deref, Range, RangeFrom, RangeFull, RangeTo}; +use std::ops::{Deref, Range, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive}; use std::fmt; use std::marker::PhantomData; use super::Dimension; /// A slice (range with step size). /// -/// 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. +/// `end` is an exclusive index. 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.s.html) macro. /// @@ -66,58 +67,6 @@ impl Slice { } } -macro_rules! impl_slice_from_index_type { - ($index:ty) => { - impl From> for Slice { - #[inline] - fn from(r: Range<$index>) -> Slice { - Slice { - start: r.start as isize, - end: Some(r.end as isize), - step: 1, - } - } - } - - impl From> for Slice { - #[inline] - fn from(r: RangeFrom<$index>) -> Slice { - Slice { - start: r.start as isize, - end: None, - step: 1, - } - } - } - - impl From> for Slice { - #[inline] - fn from(r: RangeTo<$index>) -> Slice { - Slice { - start: 0, - end: Some(r.end as isize), - step: 1, - } - } - } - } -} - -impl_slice_from_index_type!(isize); -impl_slice_from_index_type!(usize); -impl_slice_from_index_type!(i32); - -impl From for Slice { - #[inline] - fn from(_: RangeFull) -> Slice { - Slice { - start: 0, - end: None, - step: 1, - } - } -} - /// A slice (range with step) or an index. /// /// See also the [`s![]`](macro.s!.html) macro for a convenient way to create a @@ -144,9 +93,9 @@ impl From for Slice { /// The macro equivalent is `s![a..;-1]`. #[derive(Debug, PartialEq, Eq, Hash)] pub enum SliceOrIndex { - /// A range with step size. 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. + /// A range with step size. `end` is an exclusive index. 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 { start: isize, end: Option, @@ -219,41 +168,35 @@ impl fmt::Display for SliceOrIndex { } } -impl From for SliceOrIndex { - #[inline] - fn from(s: Slice) -> SliceOrIndex { - SliceOrIndex::Slice { - start: s.start, - end: s.end, - step: s.step, - } - } -} - -macro_rules! impl_sliceorindex_from_index_type { - ($index:ty) => { - impl From<$index> for SliceOrIndex { +macro_rules! impl_slice_variant_from_range { + ($self:ty, $constructor:path, $index:ty) => { + impl From> for $self { #[inline] - fn from(r: $index) -> SliceOrIndex { - SliceOrIndex::Index(r as isize) + fn from(r: Range<$index>) -> $self { + $constructor { + start: r.start as isize, + end: Some(r.end as isize), + step: 1, + } } } - impl From> for SliceOrIndex { + impl From> for $self { #[inline] - fn from(r: Range<$index>) -> SliceOrIndex { - SliceOrIndex::Slice { - start: r.start as isize, - end: Some(r.end as isize), + fn from(r: RangeInclusive<$index>) -> $self { + let end = *r.end() as isize; + $constructor { + start: *r.start() as isize, + end: if end == -1 { None } else { Some(end + 1) }, step: 1, } } } - impl From> for SliceOrIndex { + impl From> for $self { #[inline] - fn from(r: RangeFrom<$index>) -> SliceOrIndex { - SliceOrIndex::Slice { + fn from(r: RangeFrom<$index>) -> $self { + $constructor { start: r.start as isize, end: None, step: 1, @@ -261,22 +204,47 @@ macro_rules! impl_sliceorindex_from_index_type { } } - impl From> for SliceOrIndex { + impl From> for $self { #[inline] - fn from(r: RangeTo<$index>) -> SliceOrIndex { - SliceOrIndex::Slice { + fn from(r: RangeTo<$index>) -> $self { + $constructor { start: 0, end: Some(r.end as isize), step: 1, } } } - } + + impl From> for $self { + #[inline] + fn from(r: RangeToInclusive<$index>) -> $self { + let end = r.end as isize; + $constructor { + start: 0, + end: if end == -1 { None } else { Some(end + 1) }, + step: 1, + } + } + } + }; } +impl_slice_variant_from_range!(Slice, Slice, isize); +impl_slice_variant_from_range!(Slice, Slice, usize); +impl_slice_variant_from_range!(Slice, Slice, i32); +impl_slice_variant_from_range!(SliceOrIndex, SliceOrIndex::Slice, isize); +impl_slice_variant_from_range!(SliceOrIndex, SliceOrIndex::Slice, usize); +impl_slice_variant_from_range!(SliceOrIndex, SliceOrIndex::Slice, i32); -impl_sliceorindex_from_index_type!(isize); -impl_sliceorindex_from_index_type!(usize); -impl_sliceorindex_from_index_type!(i32); +impl From for Slice { + #[inline] + fn from(_: RangeFull) -> Slice { + Slice { + start: 0, + end: None, + step: 1, + } + } +} impl From for SliceOrIndex { #[inline] @@ -289,6 +257,31 @@ impl From for SliceOrIndex { } } +impl From for SliceOrIndex { + #[inline] + fn from(s: Slice) -> SliceOrIndex { + SliceOrIndex::Slice { + start: s.start, + end: s.end, + step: s.step, + } + } +} + +macro_rules! impl_sliceorindex_from_index { + ($index:ty) => { + impl From<$index> for SliceOrIndex { + #[inline] + fn from(r: $index) -> SliceOrIndex { + SliceOrIndex::Index(r as isize) + } + } + }; +} +impl_sliceorindex_from_index!(isize); +impl_sliceorindex_from_index!(usize); +impl_sliceorindex_from_index!(i32); + /// Represents all of the necessary information to perform a slice. /// /// The type `T` is typically `[SliceOrIndex; n]`, `[SliceOrIndex]`, or @@ -427,49 +420,35 @@ pub trait SliceNextDim { fn next_dim(&self, PhantomData) -> PhantomData; } -impl SliceNextDim for Slice { - fn next_dim(&self, _: PhantomData) -> PhantomData { - PhantomData - } -} - -macro_rules! impl_slicenextdim_for_index_type { - ($index:ty) => { - impl SliceNextDim for $index { +macro_rules! impl_slicenextdim_equal { + ($self:ty) => { + impl SliceNextDim for $self { fn next_dim(&self, _: PhantomData) -> PhantomData { PhantomData } } } } - -impl_slicenextdim_for_index_type!(isize); -impl_slicenextdim_for_index_type!(usize); -impl_slicenextdim_for_index_type!(i32); - -impl SliceNextDim for Range { - fn next_dim(&self, _: PhantomData) -> PhantomData { - PhantomData - } -} - -impl SliceNextDim for RangeFrom { - fn next_dim(&self, _: PhantomData) -> PhantomData { - PhantomData - } -} - -impl SliceNextDim for RangeTo { - fn next_dim(&self, _: PhantomData) -> PhantomData { - PhantomData - } -} - -impl SliceNextDim for RangeFull { - fn next_dim(&self, _: PhantomData) -> PhantomData { - PhantomData +impl_slicenextdim_equal!(isize); +impl_slicenextdim_equal!(usize); +impl_slicenextdim_equal!(i32); + +macro_rules! impl_slicenextdim_larger { + (($($generics:tt)*), $self:ty) => { + impl SliceNextDim for $self { + fn next_dim(&self, _: PhantomData) -> PhantomData { + PhantomData + } + } } } +impl_slicenextdim_larger!((T), Range); +impl_slicenextdim_larger!((T), RangeInclusive); +impl_slicenextdim_larger!((T), RangeFrom); +impl_slicenextdim_larger!((T), RangeTo); +impl_slicenextdim_larger!((T), RangeToInclusive); +impl_slicenextdim_larger!((), RangeFull); +impl_slicenextdim_larger!((), Slice); /// Slice argument constructor. /// diff --git a/tests/array.rs b/tests/array.rs index 1b01b8616..01f9041ec 100644 --- a/tests/array.rs +++ b/tests/array.rs @@ -82,6 +82,14 @@ fn test_slice() assert!(vi.iter().zip(A.iter()).all(|(a, b)| a == b)); } +#[test] +fn test_slice_inclusive_range() { + let arr = array![[1, 2, 3], [4, 5, 6]]; + assert_eq!(arr.slice(s![1..=1, 1..=2]), array![[5, 6]]); + assert_eq!(arr.slice(s![1..=-1, -2..=2;-1]), array![[6, 5]]); + assert_eq!(arr.slice(s![0..=-1, 0..=2;2]), array![[1, 3], [4, 6]]); +} + /// Test that the compiler can infer a type for a sliced array from the /// arguments to `s![]`. ///