From 4405d361c075b7567ad905ed2878080e954262bc Mon Sep 17 00:00:00 2001 From: Jim Turner Date: Sat, 23 Jun 2018 22:19:42 -0400 Subject: [PATCH 1/2] Add support for slicing with inclusive ranges Rust 1.26 added support for inclusive ranges, which can be created with syntax `start..=end` or `..=end`. This commit bumps the required Rust version to 1.27 because the `.start()` and `.end()` methods of `RangeInclusive` were added only in 1.27. --- .travis.yml | 2 +- README.rst | 3 +- src/lib.rs | 2 +- src/slice.rs | 77 ++++++++++++++++++++++++++++++++++++++++++++------ tests/array.rs | 8 ++++++ 5 files changed, 81 insertions(+), 11 deletions(-) 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..b9e684ba7 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. /// @@ -79,6 +80,18 @@ macro_rules! impl_slice_from_index_type { } } + impl From> for Slice { + #[inline] + fn from(r: RangeInclusive<$index>) -> Slice { + let end = *r.end() as isize; + Slice { + start: *r.start() as isize, + end: if end == -1 { None } else { Some(end + 1) }, + step: 1, + } + } + } + impl From> for Slice { #[inline] fn from(r: RangeFrom<$index>) -> Slice { @@ -100,7 +113,19 @@ macro_rules! impl_slice_from_index_type { } } } - } + + impl From> for Slice { + #[inline] + fn from(r: RangeToInclusive<$index>) -> Slice { + let end = r.end as isize; + Slice { + start: 0, + end: if end == -1 { None } else { Some(end + 1) }, + step: 1, + } + } + } + }; } impl_slice_from_index_type!(isize); @@ -144,9 +169,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, @@ -250,6 +275,18 @@ macro_rules! impl_sliceorindex_from_index_type { } } + impl From> for SliceOrIndex { + #[inline] + fn from(r: RangeInclusive<$index>) -> SliceOrIndex { + let end = *r.end() as isize; + SliceOrIndex::Slice { + start: *r.start() as isize, + end: if end == -1 { None } else { Some(end + 1) }, + step: 1, + } + } + } + impl From> for SliceOrIndex { #[inline] fn from(r: RangeFrom<$index>) -> SliceOrIndex { @@ -271,7 +308,19 @@ macro_rules! impl_sliceorindex_from_index_type { } } } - } + + impl From> for SliceOrIndex { + #[inline] + fn from(r: RangeToInclusive<$index>) -> SliceOrIndex { + let end = r.end as isize; + SliceOrIndex::Slice { + start: 0, + end: if end == -1 { None } else { Some(end + 1) }, + step: 1, + } + } + } + }; } impl_sliceorindex_from_index_type!(isize); @@ -453,6 +502,12 @@ impl SliceNextDim for Range { } } +impl SliceNextDim for RangeInclusive { + fn next_dim(&self, _: PhantomData) -> PhantomData { + PhantomData + } +} + impl SliceNextDim for RangeFrom { fn next_dim(&self, _: PhantomData) -> PhantomData { PhantomData @@ -465,6 +520,12 @@ impl SliceNextDim for RangeTo { } } +impl SliceNextDim for RangeToInclusive { + fn next_dim(&self, _: PhantomData) -> PhantomData { + PhantomData + } +} + impl SliceNextDim for RangeFull { fn next_dim(&self, _: PhantomData) -> PhantomData { PhantomData 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![]`. /// From 6ab3f1316a9033d212d793a7f9f5433c035ca1fc Mon Sep 17 00:00:00 2001 From: Jim Turner Date: Tue, 26 Jun 2018 14:31:12 -0400 Subject: [PATCH 2/2] Refactor slicing implementation macros --- src/slice.rs | 240 +++++++++++++++++---------------------------------- 1 file changed, 79 insertions(+), 161 deletions(-) diff --git a/src/slice.rs b/src/slice.rs index b9e684ba7..baa62fee7 100644 --- a/src/slice.rs +++ b/src/slice.rs @@ -67,82 +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: RangeInclusive<$index>) -> Slice { - let end = *r.end() as isize; - Slice { - start: *r.start() as isize, - end: if end == -1 { None } else { Some(end + 1) }, - 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 From> for Slice { - #[inline] - fn from(r: RangeToInclusive<$index>) -> Slice { - let end = r.end as isize; - Slice { - start: 0, - end: if end == -1 { None } else { Some(end + 1) }, - 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 @@ -244,30 +168,12 @@ 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) - } - } - - impl From> for SliceOrIndex { - #[inline] - fn from(r: Range<$index>) -> SliceOrIndex { - SliceOrIndex::Slice { + fn from(r: Range<$index>) -> $self { + $constructor { start: r.start as isize, end: Some(r.end as isize), step: 1, @@ -275,11 +181,11 @@ macro_rules! impl_sliceorindex_from_index_type { } } - impl From> for SliceOrIndex { + impl From> for $self { #[inline] - fn from(r: RangeInclusive<$index>) -> SliceOrIndex { + fn from(r: RangeInclusive<$index>) -> $self { let end = *r.end() as isize; - SliceOrIndex::Slice { + $constructor { start: *r.start() as isize, end: if end == -1 { None } else { Some(end + 1) }, step: 1, @@ -287,10 +193,10 @@ macro_rules! impl_sliceorindex_from_index_type { } } - 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, @@ -298,10 +204,10 @@ 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, @@ -309,11 +215,11 @@ macro_rules! impl_sliceorindex_from_index_type { } } - impl From> for SliceOrIndex { + impl From> for $self { #[inline] - fn from(r: RangeToInclusive<$index>) -> SliceOrIndex { + fn from(r: RangeToInclusive<$index>) -> $self { let end = r.end as isize; - SliceOrIndex::Slice { + $constructor { start: 0, end: if end == -1 { None } else { Some(end + 1) }, step: 1, @@ -322,10 +228,23 @@ macro_rules! impl_sliceorindex_from_index_type { } }; } +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] @@ -338,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 @@ -476,61 +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 RangeInclusive { - 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 RangeToInclusive { - 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. ///