use {Ix, Ixs};
use error::{from_kind, ErrorKind, ShapeError};
use {zipsl, ZipExt};
pub use self::dim::*;
pub use self::axis::Axis;
pub use self::conversion::IntoDimension;
pub use self::dimension_trait::Dimension;
pub use self::ndindex::NdIndex;
pub use self::remove_axis::RemoveAxis;
#[macro_use] mod macros;
mod axis;
mod conversion;
pub mod dim;
mod dimension_trait;
mod ndindex;
mod remove_axis;
pub trait DimPrivate<I> {
fn new(index: I) -> Self;
fn ix(&self) -> &I;
fn ixm(&mut self) -> &mut I;
}
#[inline(always)]
pub fn stride_offset(n: Ix, stride: Ix) -> isize {
(n as isize) * ((stride as Ixs) as isize)
}
pub fn dim_stride_overlap<D: Dimension>(dim: &D, strides: &D) -> bool {
let order = strides._fastest_varying_stride_order();
let dim = dim.slice();
let strides = strides.slice();
let mut prev_offset = 1;
for &index in order.slice() {
let d = dim[index];
let s = strides[index];
if d != 1 && (s as isize) < prev_offset {
return true;
}
prev_offset = stride_offset(d, s);
}
false
}
pub fn can_index_slice<A, D: Dimension>(data: &[A], dim: &D, strides: &D)
-> Result<(), ShapeError>
{
let len = match dim.size_checked() {
Some(l) => l,
None => return Err(from_kind(ErrorKind::OutOfBounds)),
};
for &s in strides.slice() {
let s = s as Ixs;
if s < 1 && (len != 0 || s < 0) {
return Err(from_kind(ErrorKind::Unsupported));
}
}
if len == 0 {
return Ok(());
}
let mut last_index = dim.clone();
for mut index in last_index.slice_mut().iter_mut() {
*index -= 1;
}
if let Some(offset) = stride_offset_checked_arithmetic(dim,
strides,
&last_index)
{
if (offset as usize) >= data.len() {
return Err(from_kind(ErrorKind::OutOfBounds));
}
if dim_stride_overlap(dim, strides) {
return Err(from_kind(ErrorKind::Unsupported));
}
} else {
return Err(from_kind(ErrorKind::OutOfBounds));
}
Ok(())
}
fn stride_offset_checked_arithmetic<D>(dim: &D, strides: &D, index: &D)
-> Option<isize>
where D: Dimension
{
let mut offset = 0;
for (&d, &i, &s) in zipsl(dim.slice(), index.slice()).zip_cons(strides.slice()) {
if i >= d {
return None;
}
if let Some(offset_) = (i as isize)
.checked_mul((s as Ixs) as isize)
.and_then(|x| x.checked_add(offset)) {
offset = offset_;
} else {
return None;
}
}
Some(offset)
}
pub fn stride_offset_checked(dim: &[Ix], strides: &[Ix], index: &[Ix]) -> Option<isize> {
if index.len() != dim.len() {
return None;
}
let mut offset = 0;
for (&d, &i, &s) in zipsl(dim, index).zip_cons(strides)
{
if i >= d {
return None;
}
offset += stride_offset(i, s);
}
Some(offset)
}
pub trait DimensionExt {
#[inline]
fn axis(&self, axis: Axis) -> Ix;
#[inline]
fn set_axis(&mut self, axis: Axis, value: Ix);
}
impl<D> DimensionExt for D
where D: Dimension
{
#[inline]
fn axis(&self, axis: Axis) -> Ix {
self[axis.axis()]
}
#[inline]
fn set_axis(&mut self, axis: Axis, value: Ix) {
self[axis.axis()] = value;
}
}
impl<'a> DimensionExt for [Ix]
{
#[inline]
fn axis(&self, axis: Axis) -> Ix {
self[axis.axis()]
}
#[inline]
fn set_axis(&mut self, axis: Axis, value: Ix) {
self[axis.axis()] = value;
}
}
pub fn do_sub<A, D: Dimension>(dims: &mut D, ptr: &mut *mut A, strides: &D,
axis: usize, index: Ix) {
let dim = dims.slice()[axis];
let stride = strides.slice()[axis];
assert!(index < dim);
dims.slice_mut()[axis] = 1;
let off = stride_offset(index, stride);
unsafe {
*ptr = ptr.offset(off);
}
}
#[cfg(test)]
mod test {
use super::Dimension;
use error::{from_kind, ErrorKind};
#[test]
fn slice_indexing_uncommon_strides() {
let v: Vec<_> = (0..12).collect();
let dim = (2, 3, 2);
let strides = (1, 2, 6);
assert!(super::can_index_slice(&v, &dim, &strides).is_ok());
let strides = (2, 4, 12);
assert_eq!(super::can_index_slice(&v, &dim, &strides),
Err(from_kind(ErrorKind::OutOfBounds)));
}
#[test]
fn overlapping_strides_dim() {
let dim = (2, 3, 2);
let strides = (5, 2, 1);
assert!(super::dim_stride_overlap(&dim, &strides));
let strides = (6, 2, 1);
assert!(!super::dim_stride_overlap(&dim, &strides));
let strides = (6, 0, 1);
assert!(super::dim_stride_overlap(&dim, &strides));
}
}