Skip to content

Commit af2cd32

Browse files
committed
Fix can_index_slice for arrays with no elements
1 parent 200d398 commit af2cd32

File tree

2 files changed

+50
-28
lines changed

2 files changed

+50
-28
lines changed

src/dimension.rs

Lines changed: 31 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,6 @@ pub fn stride_offset(n: Ix, stride: Ix) -> isize {
2020
(n as isize) * ((stride as Ixs) as isize)
2121
}
2222

23-
/// Check whether `stride` is strictly positive
24-
#[inline]
25-
fn stride_is_positive(stride: Ix) -> bool {
26-
(stride as Ixs) > 0
27-
}
28-
2923
/// Check whether the given `dim` and `stride` lead to overlapping indices
3024
///
3125
/// There is overlap if, when iterating through the dimensions in the order
@@ -61,33 +55,42 @@ pub fn dim_stride_overlap<D: Dimension>(dim: &D, strides: &D) -> bool {
6155
pub fn can_index_slice<A, D: Dimension>(data: &[A], dim: &D, strides: &D)
6256
-> Result<(), ShapeError>
6357
{
64-
if strides.slice().iter().cloned().all(stride_is_positive) {
65-
if dim.size_checked().is_none() {
58+
// check lengths of axes.
59+
let len = match dim.size_checked() {
60+
Some(l) => l,
61+
None => return Err(from_kind(ErrorKind::OutOfBounds)),
62+
};
63+
// check if strides are strictly positive (zero ok for len 0)
64+
for &s in strides.slice() {
65+
let s = s as Ixs;
66+
if s < 1 && (len != 0 || s < 0) {
67+
return Err(from_kind(ErrorKind::Unsupported));
68+
}
69+
}
70+
if len == 0 {
71+
return Ok(());
72+
}
73+
// check that the maximum index is in bounds
74+
let mut last_index = dim.clone();
75+
for mut index in last_index.slice_mut().iter_mut() {
76+
*index -= 1;
77+
}
78+
if let Some(offset) = stride_offset_checked_arithmetic(dim,
79+
strides,
80+
&last_index)
81+
{
82+
// offset is guaranteed to be positive so no issue converting
83+
// to usize here
84+
if (offset as usize) >= data.len() {
6685
return Err(from_kind(ErrorKind::OutOfBounds));
6786
}
68-
let mut last_index = dim.clone();
69-
for mut index in last_index.slice_mut().iter_mut() {
70-
*index -= 1;
71-
}
72-
if let Some(offset) = stride_offset_checked_arithmetic(dim,
73-
strides,
74-
&last_index)
75-
{
76-
// offset is guaranteed to be positive so no issue converting
77-
// to usize here
78-
if (offset as usize) >= data.len() {
79-
return Err(from_kind(ErrorKind::OutOfBounds));
80-
}
81-
if dim_stride_overlap(dim, strides) {
82-
return Err(from_kind(ErrorKind::Unsupported));
83-
}
84-
} else {
85-
return Err(from_kind(ErrorKind::OutOfBounds));
87+
if dim_stride_overlap(dim, strides) {
88+
return Err(from_kind(ErrorKind::Unsupported));
8689
}
87-
Ok(())
8890
} else {
89-
return Err(from_kind(ErrorKind::Unsupported));
91+
return Err(from_kind(ErrorKind::OutOfBounds));
9092
}
93+
Ok(())
9194
}
9295

9396
/// Return stride offset for this dimension and index.

tests/array.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -511,6 +511,25 @@ fn from_vec_dim_stride_2d_6() {
511511
assert_matches!(OwnedArray::from_vec_dim_stride(d, s, a.to_vec()), Ok(_));
512512
}
513513

514+
#[test]
515+
fn from_vec_dim_stride_2d_7() {
516+
// empty arrays can have 0 strides
517+
let a: [f32; 0] = [];
518+
// [[]] shape=[4, 0], strides=[0, 1]
519+
let d = (4, 0);
520+
let s = (0, 1);
521+
assert_matches!(OwnedArray::from_vec_dim_stride(d, s, a.to_vec()), Ok(_));
522+
}
523+
524+
#[test]
525+
fn from_vec_dim_stride_2d_8() {
526+
// strides must be strictly positive (nonzero)
527+
let a = [1.];
528+
let d = (1, 1);
529+
let s = (0, 1);
530+
assert_matches!(OwnedArray::from_vec_dim_stride(d, s, a.to_vec()), Err(_));
531+
}
532+
514533
#[test]
515534
fn from_vec_dim_stride_2d_rejects() {
516535
let two = [1., 2.];

0 commit comments

Comments
 (0)