Skip to content

Commit a1621f3

Browse files
authored
Merge pull request rust-ndarray#467 from jturner314/slice-inclusive-ranges
Add support for slicing with inclusive ranges
2 parents 822034e + 6ab3f13 commit a1621f3

File tree

5 files changed

+115
-127
lines changed

5 files changed

+115
-127
lines changed

.travis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ sudo: required
44
dist: trusty
55
matrix:
66
include:
7-
- rust: 1.26.0
7+
- rust: 1.27.0
88
env:
99
- FEATURES='test docs'
1010
- rust: stable

README.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,9 +92,10 @@ Recent Changes (ndarray)
9292

9393
- Add ``var_axis`` method for computing variance by @LukeMathWalker.
9494
- Add support for 128-bit integer scalars (``i128`` and ``u128``).
95+
- Add support for slicing with inclusive ranges (``start..=end`` and ``..=end``).
9596
- Bump ``num-traits`` and ``num-complex`` to version ``0.2``.
9697
- Bump ``blas-src`` to version ``0.2``.
97-
- Bump minimum required Rust version to 1.26.
98+
- Bump minimum required Rust version to 1.27.
9899
- Additional contributors to this release: @ExpHP, @jturner314, @alexbool, @messense, @danmack, @nbro
99100

100101
- 0.11.2

src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@
5353
//! + Efficient floating point matrix multiplication even for very large
5454
//! matrices; can optionally use BLAS to improve it further.
5555
//! + See also the [`ndarray-parallel`] crate for integration with rayon.
56-
//! - **Requires Rust 1.26**
56+
//! - **Requires Rust 1.27**
5757
//!
5858
//! [`ndarray-parallel`]: https://docs.rs/ndarray-parallel
5959
//!

src/slice.rs

Lines changed: 103 additions & 124 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,16 @@
66
// option. This file may not be copied, modified, or distributed
77
// except according to those terms.
88
use error::{ShapeError, ErrorKind};
9-
use std::ops::{Deref, Range, RangeFrom, RangeFull, RangeTo};
9+
use std::ops::{Deref, Range, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive};
1010
use std::fmt;
1111
use std::marker::PhantomData;
1212
use super::Dimension;
1313

1414
/// A slice (range with step size).
1515
///
16-
/// Negative `begin` or `end` indexes are counted from the back of the axis. If
17-
/// `end` is `None`, the slice extends to the end of the axis.
16+
/// `end` is an exclusive index. Negative `begin` or `end` indexes are counted
17+
/// from the back of the axis. If `end` is `None`, the slice extends to the end
18+
/// of the axis.
1819
///
1920
/// See also the [`s![]`](macro.s.html) macro.
2021
///
@@ -66,58 +67,6 @@ impl Slice {
6667
}
6768
}
6869

69-
macro_rules! impl_slice_from_index_type {
70-
($index:ty) => {
71-
impl From<Range<$index>> for Slice {
72-
#[inline]
73-
fn from(r: Range<$index>) -> Slice {
74-
Slice {
75-
start: r.start as isize,
76-
end: Some(r.end as isize),
77-
step: 1,
78-
}
79-
}
80-
}
81-
82-
impl From<RangeFrom<$index>> for Slice {
83-
#[inline]
84-
fn from(r: RangeFrom<$index>) -> Slice {
85-
Slice {
86-
start: r.start as isize,
87-
end: None,
88-
step: 1,
89-
}
90-
}
91-
}
92-
93-
impl From<RangeTo<$index>> for Slice {
94-
#[inline]
95-
fn from(r: RangeTo<$index>) -> Slice {
96-
Slice {
97-
start: 0,
98-
end: Some(r.end as isize),
99-
step: 1,
100-
}
101-
}
102-
}
103-
}
104-
}
105-
106-
impl_slice_from_index_type!(isize);
107-
impl_slice_from_index_type!(usize);
108-
impl_slice_from_index_type!(i32);
109-
110-
impl From<RangeFull> for Slice {
111-
#[inline]
112-
fn from(_: RangeFull) -> Slice {
113-
Slice {
114-
start: 0,
115-
end: None,
116-
step: 1,
117-
}
118-
}
119-
}
120-
12170
/// A slice (range with step) or an index.
12271
///
12372
/// See also the [`s![]`](macro.s!.html) macro for a convenient way to create a
@@ -144,9 +93,9 @@ impl From<RangeFull> for Slice {
14493
/// The macro equivalent is `s![a..;-1]`.
14594
#[derive(Debug, PartialEq, Eq, Hash)]
14695
pub enum SliceOrIndex {
147-
/// A range with step size. Negative `begin` or `end` indexes are counted
148-
/// from the back of the axis. If `end` is `None`, the slice extends to the
149-
/// end of the axis.
96+
/// A range with step size. `end` is an exclusive index. Negative `begin`
97+
/// or `end` indexes are counted from the back of the axis. If `end` is
98+
/// `None`, the slice extends to the end of the axis.
15099
Slice {
151100
start: isize,
152101
end: Option<isize>,
@@ -219,64 +168,83 @@ impl fmt::Display for SliceOrIndex {
219168
}
220169
}
221170

222-
impl From<Slice> for SliceOrIndex {
223-
#[inline]
224-
fn from(s: Slice) -> SliceOrIndex {
225-
SliceOrIndex::Slice {
226-
start: s.start,
227-
end: s.end,
228-
step: s.step,
229-
}
230-
}
231-
}
232-
233-
macro_rules! impl_sliceorindex_from_index_type {
234-
($index:ty) => {
235-
impl From<$index> for SliceOrIndex {
171+
macro_rules! impl_slice_variant_from_range {
172+
($self:ty, $constructor:path, $index:ty) => {
173+
impl From<Range<$index>> for $self {
236174
#[inline]
237-
fn from(r: $index) -> SliceOrIndex {
238-
SliceOrIndex::Index(r as isize)
175+
fn from(r: Range<$index>) -> $self {
176+
$constructor {
177+
start: r.start as isize,
178+
end: Some(r.end as isize),
179+
step: 1,
180+
}
239181
}
240182
}
241183

242-
impl From<Range<$index>> for SliceOrIndex {
184+
impl From<RangeInclusive<$index>> for $self {
243185
#[inline]
244-
fn from(r: Range<$index>) -> SliceOrIndex {
245-
SliceOrIndex::Slice {
246-
start: r.start as isize,
247-
end: Some(r.end as isize),
186+
fn from(r: RangeInclusive<$index>) -> $self {
187+
let end = *r.end() as isize;
188+
$constructor {
189+
start: *r.start() as isize,
190+
end: if end == -1 { None } else { Some(end + 1) },
248191
step: 1,
249192
}
250193
}
251194
}
252195

253-
impl From<RangeFrom<$index>> for SliceOrIndex {
196+
impl From<RangeFrom<$index>> for $self {
254197
#[inline]
255-
fn from(r: RangeFrom<$index>) -> SliceOrIndex {
256-
SliceOrIndex::Slice {
198+
fn from(r: RangeFrom<$index>) -> $self {
199+
$constructor {
257200
start: r.start as isize,
258201
end: None,
259202
step: 1,
260203
}
261204
}
262205
}
263206

264-
impl From<RangeTo<$index>> for SliceOrIndex {
207+
impl From<RangeTo<$index>> for $self {
265208
#[inline]
266-
fn from(r: RangeTo<$index>) -> SliceOrIndex {
267-
SliceOrIndex::Slice {
209+
fn from(r: RangeTo<$index>) -> $self {
210+
$constructor {
268211
start: 0,
269212
end: Some(r.end as isize),
270213
step: 1,
271214
}
272215
}
273216
}
274-
}
217+
218+
impl From<RangeToInclusive<$index>> for $self {
219+
#[inline]
220+
fn from(r: RangeToInclusive<$index>) -> $self {
221+
let end = r.end as isize;
222+
$constructor {
223+
start: 0,
224+
end: if end == -1 { None } else { Some(end + 1) },
225+
step: 1,
226+
}
227+
}
228+
}
229+
};
275230
}
231+
impl_slice_variant_from_range!(Slice, Slice, isize);
232+
impl_slice_variant_from_range!(Slice, Slice, usize);
233+
impl_slice_variant_from_range!(Slice, Slice, i32);
234+
impl_slice_variant_from_range!(SliceOrIndex, SliceOrIndex::Slice, isize);
235+
impl_slice_variant_from_range!(SliceOrIndex, SliceOrIndex::Slice, usize);
236+
impl_slice_variant_from_range!(SliceOrIndex, SliceOrIndex::Slice, i32);
276237

277-
impl_sliceorindex_from_index_type!(isize);
278-
impl_sliceorindex_from_index_type!(usize);
279-
impl_sliceorindex_from_index_type!(i32);
238+
impl From<RangeFull> for Slice {
239+
#[inline]
240+
fn from(_: RangeFull) -> Slice {
241+
Slice {
242+
start: 0,
243+
end: None,
244+
step: 1,
245+
}
246+
}
247+
}
280248

281249
impl From<RangeFull> for SliceOrIndex {
282250
#[inline]
@@ -289,6 +257,31 @@ impl From<RangeFull> for SliceOrIndex {
289257
}
290258
}
291259

260+
impl From<Slice> for SliceOrIndex {
261+
#[inline]
262+
fn from(s: Slice) -> SliceOrIndex {
263+
SliceOrIndex::Slice {
264+
start: s.start,
265+
end: s.end,
266+
step: s.step,
267+
}
268+
}
269+
}
270+
271+
macro_rules! impl_sliceorindex_from_index {
272+
($index:ty) => {
273+
impl From<$index> for SliceOrIndex {
274+
#[inline]
275+
fn from(r: $index) -> SliceOrIndex {
276+
SliceOrIndex::Index(r as isize)
277+
}
278+
}
279+
};
280+
}
281+
impl_sliceorindex_from_index!(isize);
282+
impl_sliceorindex_from_index!(usize);
283+
impl_sliceorindex_from_index!(i32);
284+
292285
/// Represents all of the necessary information to perform a slice.
293286
///
294287
/// The type `T` is typically `[SliceOrIndex; n]`, `[SliceOrIndex]`, or
@@ -427,49 +420,35 @@ pub trait SliceNextDim<D1, D2> {
427420
fn next_dim(&self, PhantomData<D1>) -> PhantomData<D2>;
428421
}
429422

430-
impl<D1: Dimension> SliceNextDim<D1, D1::Larger> for Slice {
431-
fn next_dim(&self, _: PhantomData<D1>) -> PhantomData<D1::Larger> {
432-
PhantomData
433-
}
434-
}
435-
436-
macro_rules! impl_slicenextdim_for_index_type {
437-
($index:ty) => {
438-
impl<D1: Dimension> SliceNextDim<D1, D1> for $index {
423+
macro_rules! impl_slicenextdim_equal {
424+
($self:ty) => {
425+
impl<D1: Dimension> SliceNextDim<D1, D1> for $self {
439426
fn next_dim(&self, _: PhantomData<D1>) -> PhantomData<D1> {
440427
PhantomData
441428
}
442429
}
443430
}
444431
}
445-
446-
impl_slicenextdim_for_index_type!(isize);
447-
impl_slicenextdim_for_index_type!(usize);
448-
impl_slicenextdim_for_index_type!(i32);
449-
450-
impl<D1: Dimension, T> SliceNextDim<D1, D1::Larger> for Range<T> {
451-
fn next_dim(&self, _: PhantomData<D1>) -> PhantomData<D1::Larger> {
452-
PhantomData
453-
}
454-
}
455-
456-
impl<D1: Dimension, T> SliceNextDim<D1, D1::Larger> for RangeFrom<T> {
457-
fn next_dim(&self, _: PhantomData<D1>) -> PhantomData<D1::Larger> {
458-
PhantomData
459-
}
460-
}
461-
462-
impl<D1: Dimension, T> SliceNextDim<D1, D1::Larger> for RangeTo<T> {
463-
fn next_dim(&self, _: PhantomData<D1>) -> PhantomData<D1::Larger> {
464-
PhantomData
465-
}
466-
}
467-
468-
impl<D1: Dimension> SliceNextDim<D1, D1::Larger> for RangeFull {
469-
fn next_dim(&self, _: PhantomData<D1>) -> PhantomData<D1::Larger> {
470-
PhantomData
432+
impl_slicenextdim_equal!(isize);
433+
impl_slicenextdim_equal!(usize);
434+
impl_slicenextdim_equal!(i32);
435+
436+
macro_rules! impl_slicenextdim_larger {
437+
(($($generics:tt)*), $self:ty) => {
438+
impl<D1: Dimension, $($generics),*> SliceNextDim<D1, D1::Larger> for $self {
439+
fn next_dim(&self, _: PhantomData<D1>) -> PhantomData<D1::Larger> {
440+
PhantomData
441+
}
442+
}
471443
}
472444
}
445+
impl_slicenextdim_larger!((T), Range<T>);
446+
impl_slicenextdim_larger!((T), RangeInclusive<T>);
447+
impl_slicenextdim_larger!((T), RangeFrom<T>);
448+
impl_slicenextdim_larger!((T), RangeTo<T>);
449+
impl_slicenextdim_larger!((T), RangeToInclusive<T>);
450+
impl_slicenextdim_larger!((), RangeFull);
451+
impl_slicenextdim_larger!((), Slice);
473452

474453
/// Slice argument constructor.
475454
///

tests/array.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,14 @@ fn test_slice()
8282
assert!(vi.iter().zip(A.iter()).all(|(a, b)| a == b));
8383
}
8484

85+
#[test]
86+
fn test_slice_inclusive_range() {
87+
let arr = array![[1, 2, 3], [4, 5, 6]];
88+
assert_eq!(arr.slice(s![1..=1, 1..=2]), array![[5, 6]]);
89+
assert_eq!(arr.slice(s![1..=-1, -2..=2;-1]), array![[6, 5]]);
90+
assert_eq!(arr.slice(s![0..=-1, 0..=2;2]), array![[1, 3], [4, 6]]);
91+
}
92+
8593
/// Test that the compiler can infer a type for a sliced array from the
8694
/// arguments to `s![]`.
8795
///

0 commit comments

Comments
 (0)