use std::slice;
use super::{Si, Ix, Ixs};
#[inline]
pub fn stride_offset(n: Ix, stride: Ix) -> isize
{
(n as isize) * ((stride as Ixs) as isize)
}
pub unsafe trait Dimension : Clone + Eq {
fn ndim(&self) -> usize;
fn slice(&self) -> &[Ix] {
unsafe {
slice::from_raw_parts(self as *const _ as *const Ix, self.ndim())
}
}
fn slice_mut(&mut self) -> &mut [Ix] {
unsafe {
slice::from_raw_parts_mut(self as *mut _ as *mut Ix, self.ndim())
}
}
fn size(&self) -> usize {
self.slice().iter().fold(1, |s, &a| s * a as usize)
}
fn default_strides(&self) -> Self {
let mut strides = self.clone();
{
let mut it = strides.slice_mut().iter_mut().rev();
for rs in it.by_ref() {
*rs = 1;
break;
}
let mut cum_prod = 1;
for (rs, dim) in it.zip(self.slice().iter().rev()) {
cum_prod *= *dim;
*rs = cum_prod;
}
}
strides
}
#[inline]
fn first_index(&self) -> Option<Self>
{
for ax in self.slice().iter() {
if *ax == 0 {
return None
}
}
let mut index = self.clone();
for rr in index.slice_mut().iter_mut() {
*rr = 0;
}
Some(index)
}
#[inline]
fn next_for(&self, index: Self) -> Option<Self> {
let mut index = index;
let mut done = false;
for (&dim, ix) in self.slice().iter().rev()
.zip(index.slice_mut().iter_mut().rev())
{
*ix += 1;
if *ix == dim {
*ix = 0;
} else {
done = true;
break;
}
}
if done {
Some(index)
} else { None }
}
fn stride_offset(index: &Self, strides: &Self) -> isize
{
let mut offset = 0;
for (&i, &s) in index.slice().iter()
.zip(strides.slice().iter()) {
offset += stride_offset(i, s);
}
offset
}
fn stride_offset_checked(&self, strides: &Self, index: &Self) -> Option<isize>
{
let mut offset = 0;
for ((&d, &i), &s) in self.slice().iter()
.zip(index.slice().iter())
.zip(strides.slice().iter())
{
if i >= d {
return None;
}
offset += stride_offset(i, s);
}
Some(offset)
}
fn do_slices(dim: &mut Self, strides: &mut Self, slices: &[Si]) -> isize
{
let mut offset = 0;
assert!(slices.len() == dim.slice().len());
for ((dr, sr), &slc) in dim.slice_mut().iter_mut()
.zip(strides.slice_mut().iter_mut())
.zip(slices.iter())
{
let m = *dr;
let mi = m as Ixs;
let Si(b1, opt_e1, s1) = slc;
let e1 = opt_e1.unwrap_or(mi);
let b1 = abs_index(mi, b1);
let mut e1 = abs_index(mi, e1);
if e1 < b1 { e1 = b1; }
assert!(b1 <= m);
assert!(e1 <= m);
let m = e1 - b1;
let s = (*sr) as Ixs;
offset += stride_offset(b1, *sr);
assert!(s1 != 0);
if s1 < 0 {
offset += stride_offset(m - 1, *sr);
}
let s_prim = s * s1;
let d = m / s1.abs() as Ix;
let r = m % s1.abs() as Ix;
let m_prim = d + if r > 0 { 1 } else { 0 };
*dr = m_prim;
*sr = s_prim as Ix;
}
offset
}
}
fn abs_index(len: Ixs, index: Ixs) -> Ix {
if index < 0 {
(len + index) as Ix
} else { index as Ix }
}
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);
}
}
unsafe impl Dimension for () {
#[inline]
fn ndim(&self) -> usize { 0 }
fn slice(&self) -> &[Ix] { &[] }
fn slice_mut(&mut self) -> &mut [Ix] { &mut [] }
}
unsafe impl Dimension for Ix {
#[inline]
fn ndim(&self) -> usize { 1 }
#[inline]
fn size(&self) -> usize { *self as usize }
#[inline]
fn first_index(&self) -> Option<Ix> {
if *self != 0 {
Some(0)
} else { None }
}
#[inline]
fn next_for(&self, mut index: Ix) -> Option<Ix> {
index += 1;
if index < *self {
Some(index)
} else { None }
}
#[inline]
fn stride_offset(index: &Ix, stride: &Ix) -> isize
{
stride_offset(*index, *stride)
}
fn stride_offset_checked(&self, stride: &Ix, index: &Ix) -> Option<isize>
{
if *index < *self {
Some(stride_offset(*index, *stride))
} else {
None
}
}
}
unsafe impl Dimension for (Ix, Ix) {
#[inline]
fn ndim(&self) -> usize { 2 }
#[inline]
fn size(&self) -> usize { let (m, n) = *self; m as usize * n as usize }
#[inline]
fn first_index(&self) -> Option<(Ix, Ix)> {
let (m, n) = *self;
if m != 0 && n != 0 {
Some((0, 0))
} else { None }
}
#[inline]
fn next_for(&self, index: (Ix, Ix)) -> Option<(Ix, Ix)> {
let (mut i, mut j) = index;
let (imax, jmax) = *self;
j += 1;
if j == jmax {
j = 0;
i += 1;
if i == imax {
return None;
}
}
Some((i, j))
}
#[inline]
fn stride_offset(index: &(Ix, Ix), strides: &(Ix, Ix)) -> isize
{
let (i, j) = *index;
let (s, t) = *strides;
stride_offset(i, s) + stride_offset(j, t)
}
fn stride_offset_checked(&self, strides: &(Ix, Ix), index: &(Ix, Ix)) -> Option<isize>
{
let (m, n) = *self;
let (i, j) = *index;
let (s, t) = *strides;
if i < m && j < n {
Some(stride_offset(i, s) + stride_offset(j, t))
} else {
None
}
}
}
unsafe impl Dimension for (Ix, Ix, Ix) {
#[inline]
fn ndim(&self) -> usize { 3 }
#[inline]
fn size(&self) -> usize { let (m, n, o) = *self; m as usize * n as usize * o as usize }
#[inline]
fn next_for(&self, index: (Ix, Ix, Ix)) -> Option<(Ix, Ix, Ix)> {
let (mut i, mut j, mut k) = index;
let (imax, jmax, kmax) = *self;
k += 1;
if k == kmax {
k = 0;
j += 1;
if j == jmax {
j = 0;
i += 1;
if i == imax {
return None;
}
}
}
Some((i, j, k))
}
#[inline]
fn stride_offset(index: &(Ix, Ix, Ix), strides: &(Ix, Ix, Ix)) -> isize
{
let (i, j, k) = *index;
let (s, t, u) = *strides;
stride_offset(i, s) + stride_offset(j, t) + stride_offset(k, u)
}
}
unsafe impl Dimension for (Ix, Ix, Ix, Ix) { fn ndim(&self) -> usize { 4 } }
unsafe impl Dimension for (Ix, Ix, Ix, Ix, Ix) { fn ndim(&self) -> usize { 5 } }
unsafe impl Dimension for (Ix, Ix, Ix, Ix, Ix, Ix) { fn ndim(&self) -> usize { 6 } }
unsafe impl Dimension for (Ix, Ix, Ix, Ix, Ix, Ix, Ix) { fn ndim(&self) -> usize { 7 } }
unsafe impl Dimension for (Ix, Ix, Ix, Ix, Ix, Ix, Ix, Ix) { fn ndim(&self) -> usize { 8 } }
unsafe impl Dimension for (Ix, Ix, Ix, Ix, Ix, Ix, Ix, Ix, Ix) { fn ndim(&self) -> usize { 9 } }
unsafe impl Dimension for (Ix, Ix, Ix, Ix, Ix, Ix, Ix, Ix, Ix, Ix) { fn ndim(&self) -> usize { 10 } }
unsafe impl Dimension for (Ix, Ix, Ix, Ix, Ix, Ix, Ix, Ix, Ix, Ix, Ix) { fn ndim(&self) -> usize { 11 } }
unsafe impl Dimension for (Ix, Ix, Ix, Ix, Ix, Ix, Ix, Ix, Ix, Ix, Ix, Ix) { fn ndim(&self) -> usize { 12 } }
unsafe impl Dimension for Vec<Ix>
{
fn ndim(&self) -> usize { self.len() }
fn slice(&self) -> &[Ix] { self }
fn slice_mut(&mut self) -> &mut [Ix] { self }
}
pub trait RemoveAxis : Dimension {
type Smaller: Dimension;
fn remove_axis(&self, axis: usize) -> Self::Smaller;
}
macro_rules! impl_shrink(
($from:ident, $($more:ident,)*) => (
impl RemoveAxis for ($from $(,$more)*)
{
type Smaller = ($($more),*);
#[allow(unused_parens)]
fn remove_axis(&self, axis: usize) -> ($($more),*) {
let mut tup = ($(0 as $more),*);
{
let mut it = tup.slice_mut().iter_mut();
for (i, &d) in self.slice().iter().enumerate() {
if i == axis {
continue;
}
for rr in it.by_ref() {
*rr = d;
break
}
}
}
tup
}
}
)
);
macro_rules! impl_shrink_recursive(
($ix:ident, ) => (impl_shrink!($ix,););
($ix1:ident, $($ix:ident,)*) => (
impl_shrink_recursive!($($ix,)*);
impl_shrink!($ix1, $($ix,)*);
)
);
impl_shrink_recursive!(Ix, Ix, Ix, Ix, Ix, Ix, Ix, Ix, Ix, Ix, Ix, Ix,);
impl RemoveAxis for Vec<Ix>
{
type Smaller = Vec<Ix>;
fn remove_axis(&self, axis: usize) -> Vec<Ix>
{
let mut res = self.clone();
res.remove(axis);
res
}
}