Skip to content

Commit 5de94ef

Browse files
committed
Add .slice_axis*()
1 parent d2750d1 commit 5de94ef

File tree

4 files changed

+143
-77
lines changed

4 files changed

+143
-77
lines changed

src/dimension/dimension_trait.rs

Lines changed: 0 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -239,69 +239,6 @@ pub trait Dimension : Clone + Eq + Debug + Send + Sync + Default +
239239
self.slice_mut()[nd - 1] = i;
240240
}
241241

242-
#[doc(hidden)]
243-
/// Modify dimension, strides and return data pointer offset
244-
///
245-
/// **Panics** if `slices` does not correspond to the number of axes,
246-
/// if any stride is 0, or if any index is out of bounds.
247-
fn do_slices(dim: &mut Self, strides: &mut Self, slices: &Self::SliceArg) -> isize {
248-
let slices = slices.as_ref();
249-
let mut offset = 0;
250-
ndassert!(slices.len() == dim.slice().len(),
251-
"SliceArg {:?}'s length does not match dimension {:?}",
252-
slices, dim);
253-
for (dr, sr, &slc) in izip!(dim.slice_mut(), strides.slice_mut(), slices) {
254-
let m = *dr;
255-
let mi = m as Ixs;
256-
let Si(b1, opt_e1, s1) = slc;
257-
let e1 = opt_e1.unwrap_or(mi);
258-
259-
let b1 = abs_index(mi, b1);
260-
let mut e1 = abs_index(mi, e1);
261-
if e1 < b1 { e1 = b1; }
262-
263-
ndassert!(b1 <= m,
264-
concat!("Slice begin {} is past end of axis of length {}",
265-
" (for SliceArg {:?})"),
266-
b1, m, slices);
267-
ndassert!(e1 <= m,
268-
concat!("Slice end {} is past end of axis of length {}",
269-
" (for SliceArg {:?})"),
270-
e1, m, slices);
271-
272-
let m = e1 - b1;
273-
// stride
274-
let s = (*sr) as Ixs;
275-
276-
// Data pointer offset
277-
offset += stride_offset(b1, *sr);
278-
// Adjust for strides
279-
ndassert!(s1 != 0,
280-
concat!("Slice stride must not be none",
281-
"(for SliceArg {:?})"),
282-
slices);
283-
// How to implement negative strides:
284-
//
285-
// Increase start pointer by
286-
// old stride * (old dim - 1)
287-
// to put the pointer completely in the other end
288-
if s1 < 0 {
289-
offset += stride_offset(m - 1, *sr);
290-
}
291-
292-
let s_prim = s * s1;
293-
294-
let d = m / s1.abs() as Ix;
295-
let r = m % s1.abs() as Ix;
296-
let m_prim = d + if r > 0 { 1 } else { 0 };
297-
298-
// Update dimension and stride coordinate
299-
*dr = m_prim;
300-
*sr = s_prim as Ix;
301-
}
302-
offset
303-
}
304-
305242
#[doc(hidden)]
306243
fn is_contiguous(dim: &Self, strides: &Self) -> bool {
307244
let defaults = dim.default_strides();
@@ -398,18 +335,6 @@ pub trait Dimension : Clone + Eq + Debug + Send + Sync + Default +
398335
private_decl!{}
399336
}
400337

401-
// utility functions
402-
403-
#[inline]
404-
fn abs_index(len: Ixs, index: Ixs) -> Ix {
405-
if index < 0 {
406-
(len + index) as Ix
407-
} else {
408-
index as Ix
409-
}
410-
}
411-
412-
413338
// Dimension impls
414339

415340
macro_rules! impl_insert_axis_array(

src/dimension/mod.rs

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,77 @@ pub fn do_sub<A, D: Dimension>(dims: &mut D, ptr: &mut *mut A, strides: &D,
212212
}
213213
}
214214

215+
/// Compute the equivalent unsigned index given the axis length and signed index.
216+
#[inline]
217+
fn abs_index(len: Ix, index: Ixs) -> Ix {
218+
if index < 0 {
219+
len - (-index as Ix)
220+
} else {
221+
index as Ix
222+
}
223+
}
224+
225+
/// Modify dimension, stride and return data pointer offset
226+
///
227+
/// **Panics** if stride is 0 or if any index is out of bounds.
228+
pub fn do_slice(
229+
dim: &mut Ix,
230+
stride: &mut Ix,
231+
start: Ixs,
232+
end: Option<Ixs>,
233+
step: Ixs,
234+
) -> isize {
235+
let mut offset = 0;
236+
237+
let axis_len = *dim;
238+
let start = abs_index(axis_len, start);
239+
let mut end = abs_index(axis_len, end.unwrap_or(axis_len as Ixs));
240+
if end < start {
241+
end = start;
242+
}
243+
244+
ndassert!(
245+
start <= axis_len,
246+
"Slice begin {} is past end of axis of length {}",
247+
start,
248+
axis_len,
249+
);
250+
ndassert!(
251+
end <= axis_len,
252+
"Slice end {} is past end of axis of length {}",
253+
end,
254+
axis_len,
255+
);
256+
257+
let m = end - start;
258+
// stride
259+
let s = (*stride) as Ixs;
260+
261+
// Data pointer offset
262+
offset += stride_offset(start, *stride);
263+
// Adjust for strides
264+
ndassert!(step != 0, "Slice stride must not be zero");
265+
// How to implement negative strides:
266+
//
267+
// Increase start pointer by
268+
// old stride * (old dim - 1)
269+
// to put the pointer completely in the other end
270+
if step < 0 {
271+
offset += stride_offset(m - 1, *stride);
272+
}
273+
274+
let s_prim = s * step;
275+
276+
let d = m / step.abs() as Ix;
277+
let r = m % step.abs() as Ix;
278+
let m_prim = d + if r > 0 { 1 } else { 0 };
279+
280+
// Update dimension and stride coordinate
281+
*dim = m_prim;
282+
*stride = s_prim as Ix;
283+
284+
offset
285+
}
215286

216287
pub fn merge_axes<D>(dim: &mut D, strides: &mut D, take: Axis, into: Axis) -> bool
217288
where D: Dimension,

src/impl_methods.rs

Lines changed: 65 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use dimension;
1919
use iterators;
2020
use error::{self, ShapeError, ErrorKind};
2121
use dimension::IntoDimension;
22-
use dimension::{axes_of, Axes, merge_axes, stride_offset};
22+
use dimension::{axes_of, Axes, do_slice, merge_axes, stride_offset};
2323
use iterators::{
2424
new_lanes,
2525
new_lanes_mut,
@@ -31,6 +31,7 @@ use zip::Zip;
3131

3232
use {
3333
NdIndex,
34+
Si,
3435
};
3536
use iter::{
3637
AxisChunksIter,
@@ -246,7 +247,69 @@ impl<A, S, D> ArrayBase<S, D> where S: Data<Elem=A>, D: Dimension
246247
/// **Panics** if an index is out of bounds or stride is zero.<br>
247248
/// (**Panics** if `D` is `IxDyn` and `indexes` does not match the number of array axes.)
248249
pub fn slice_inplace(&mut self, indexes: &D::SliceArg) {
249-
let offset = D::do_slices(&mut self.dim, &mut self.strides, indexes);
250+
let indexes: &[Si] = indexes.as_ref();
251+
assert_eq!(indexes.len(), self.ndim());
252+
indexes
253+
.iter()
254+
.enumerate()
255+
.for_each(|(axis, &Si(start, end, step))| {
256+
self.slice_axis_inplace(Axis(axis), start, end, step)
257+
});
258+
}
259+
260+
/// Return a view of the array, sliced along the specified axis.
261+
///
262+
/// **Panics** if an index is out of bounds or step size is zero.<br>
263+
/// **Panics** if `axis` is out of bounds.
264+
pub fn slice_axis(
265+
&self,
266+
axis: Axis,
267+
start: Ixs,
268+
end: Option<Ixs>,
269+
step: Ixs,
270+
) -> ArrayView<A, D> {
271+
let mut view = self.view();
272+
view.slice_axis_inplace(axis, start, end, step);
273+
view
274+
}
275+
276+
/// Return a mutable view of the array, sliced along the specified axis.
277+
///
278+
/// **Panics** if an index is out of bounds or step size is zero.<br>
279+
/// **Panics** if `axis` is out of bounds.
280+
pub fn slice_axis_mut(
281+
&mut self,
282+
axis: Axis,
283+
start: Ixs,
284+
end: Option<Ixs>,
285+
step: Ixs,
286+
) -> ArrayViewMut<A, D>
287+
where
288+
S: DataMut,
289+
{
290+
let mut view_mut = self.view_mut();
291+
view_mut.slice_axis_inplace(axis, start, end, step);
292+
view_mut
293+
}
294+
295+
/// Slice the array in place along the specified axis.
296+
///
297+
/// **Panics** if an index is out of bounds or step size is zero.<br>
298+
/// **Panics** if `axis` is out of bounds.
299+
pub fn slice_axis_inplace(
300+
&mut self,
301+
axis: Axis,
302+
start: Ixs,
303+
end: Option<Ixs>,
304+
step: Ixs,
305+
) {
306+
let offset = do_slice(
307+
&mut self.dim.slice_mut()[axis.index()],
308+
&mut self.strides.slice_mut()[axis.index()],
309+
start,
310+
end,
311+
step,
312+
);
250313
unsafe {
251314
self.ptr = self.ptr.offset(offset);
252315
}

tests/array.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,13 @@ fn slice_oob()
8282
let _vi = a.slice(&[Si(0, Some(10), 1), S]);
8383
}
8484

85+
#[should_panic]
86+
#[test]
87+
fn slice_axis_oob() {
88+
let a = RcArray::<i32, _>::zeros((3, 4));
89+
let _vi = a.slice_axis(Axis(0), 0, Some(10), 1);
90+
}
91+
8592
#[should_panic]
8693
#[test]
8794
fn slice_wrong_dim()

0 commit comments

Comments
 (0)