mod layoutfmt;
#[doc(hidden)]
#[derive(Copy, Clone)]
pub struct Layout(u32);
impl Layout {
pub(crate) const CORDER: u32 = 0b01;
pub(crate) const FORDER: u32 = 0b10;
pub(crate) const CPREFER: u32 = 0b0100;
pub(crate) const FPREFER: u32 = 0b1000;
#[inline(always)]
pub(crate) fn is(self, flag: u32) -> bool {
self.0 & flag != 0
}
#[inline(always)]
pub(crate) fn intersect(self, other: Layout) -> Layout {
Layout(self.0 & other.0)
}
#[inline(always)]
pub(crate) fn also(self, other: Layout) -> Layout {
Layout(self.0 | other.0)
}
#[inline(always)]
pub(crate) fn one_dimensional() -> Layout {
Layout::c().also(Layout::f())
}
#[inline(always)]
pub(crate) fn c() -> Layout {
Layout(Layout::CORDER | Layout::CPREFER)
}
#[inline(always)]
pub(crate) fn f() -> Layout {
Layout(Layout::FORDER | Layout::FPREFER)
}
#[inline(always)]
pub(crate) fn cpref() -> Layout {
Layout(Layout::CPREFER)
}
#[inline(always)]
pub(crate) fn fpref() -> Layout {
Layout(Layout::FPREFER)
}
#[inline(always)]
pub(crate) fn none() -> Layout {
Layout(0)
}
#[inline]
pub(crate) fn tendency(self) -> i32 {
(self.is(Layout::CORDER) as i32 - self.is(Layout::FORDER) as i32) +
(self.is(Layout::CPREFER) as i32 - self.is(Layout::FPREFER) as i32)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::imp_prelude::*;
use crate::NdProducer;
type M = Array2<f32>;
type M1 = Array1<f32>;
type M0 = Array0<f32>;
macro_rules! assert_layouts {
($mat:expr, $($layout:ident),*) => {{
let layout = $mat.view().layout();
$(
assert!(layout.is(Layout::$layout),
"Assertion failed: array {:?} is not layout {}",
$mat,
stringify!($layout));
)*
}}
}
macro_rules! assert_not_layouts {
($mat:expr, $($layout:ident),*) => {{
let layout = $mat.view().layout();
$(
assert!(!layout.is(Layout::$layout),
"Assertion failed: array {:?} show not have layout {}",
$mat,
stringify!($layout));
)*
}}
}
#[test]
fn contig_layouts() {
let a = M::zeros((5, 5));
let b = M::zeros((5, 5).f());
let ac = a.view().layout();
let af = b.view().layout();
assert!(ac.is(Layout::CORDER) && ac.is(Layout::CPREFER));
assert!(!ac.is(Layout::FORDER) && !ac.is(Layout::FPREFER));
assert!(!af.is(Layout::CORDER) && !af.is(Layout::CPREFER));
assert!(af.is(Layout::FORDER) && af.is(Layout::FPREFER));
}
#[test]
fn contig_cf_layouts() {
let a = M::zeros((5, 1));
let b = M::zeros((1, 5).f());
assert_layouts!(a, CORDER, CPREFER, FORDER, FPREFER);
assert_layouts!(b, CORDER, CPREFER, FORDER, FPREFER);
let a = M1::zeros(5);
let b = M1::zeros(5.f());
assert_layouts!(a, CORDER, CPREFER, FORDER, FPREFER);
assert_layouts!(b, CORDER, CPREFER, FORDER, FPREFER);
let a = M0::zeros(());
assert_layouts!(a, CORDER, CPREFER, FORDER, FPREFER);
let a = M::zeros((5, 5));
let b = M::zeros((5, 5).f());
let arow = a.slice(s![..1, ..]);
let bcol = b.slice(s![.., ..1]);
assert_layouts!(arow, CORDER, CPREFER, FORDER, FPREFER);
assert_layouts!(bcol, CORDER, CPREFER, FORDER, FPREFER);
let acol = a.slice(s![.., ..1]);
let brow = b.slice(s![..1, ..]);
assert_not_layouts!(acol, CORDER, CPREFER, FORDER, FPREFER);
assert_not_layouts!(brow, CORDER, CPREFER, FORDER, FPREFER);
}
#[test]
fn stride_layouts() {
let a = M::zeros((5, 5));
{
let v1 = a.slice(s![1.., ..]).layout();
let v2 = a.slice(s![.., 1..]).layout();
assert!(v1.is(Layout::CORDER) && v1.is(Layout::CPREFER));
assert!(!v1.is(Layout::FORDER) && !v1.is(Layout::FPREFER));
assert!(!v2.is(Layout::CORDER) && v2.is(Layout::CPREFER));
assert!(!v2.is(Layout::FORDER) && !v2.is(Layout::FPREFER));
}
let b = M::zeros((5, 5).f());
{
let v1 = b.slice(s![1.., ..]).layout();
let v2 = b.slice(s![.., 1..]).layout();
assert!(!v1.is(Layout::CORDER) && !v1.is(Layout::CPREFER));
assert!(!v1.is(Layout::FORDER) && v1.is(Layout::FPREFER));
assert!(!v2.is(Layout::CORDER) && !v2.is(Layout::CPREFER));
assert!(v2.is(Layout::FORDER) && v2.is(Layout::FPREFER));
}
}
#[test]
fn no_layouts() {
let a = M::zeros((5, 5));
let b = M::zeros((5, 5).f());
let arow = a.slice(s![0..1, ..]);
let acol = a.slice(s![.., 0..1]);
let brow = b.slice(s![0..1, ..]);
let bcol = b.slice(s![.., 0..1]);
assert_layouts!(arow, CORDER, FORDER);
assert_not_layouts!(acol, CORDER, CPREFER, FORDER, FPREFER);
assert_layouts!(bcol, CORDER, FORDER);
assert_not_layouts!(brow, CORDER, CPREFER, FORDER, FPREFER);
for &axis in &[Axis(0), Axis(1)] {
let arow = a.slice(s![0, ..]).insert_axis(axis);
let acol = a.slice(s![.., 0]).insert_axis(axis);
let brow = b.slice(s![0, ..]).insert_axis(axis);
let bcol = b.slice(s![.., 0]).insert_axis(axis);
assert_layouts!(arow, CORDER, FORDER);
assert_not_layouts!(acol, CORDER, CPREFER, FORDER, FPREFER);
assert_layouts!(bcol, CORDER, FORDER);
assert_not_layouts!(brow, CORDER, CPREFER, FORDER, FPREFER);
}
}
#[test]
fn skip_layouts() {
let a = M::zeros((5, 5));
{
let v1 = a.slice(s![..;2, ..]).layout();
let v2 = a.slice(s![.., ..;2]).layout();
assert!(!v1.is(Layout::CORDER) && v1.is(Layout::CPREFER));
assert!(!v1.is(Layout::FORDER) && !v1.is(Layout::FPREFER));
assert!(!v2.is(Layout::CORDER) && !v2.is(Layout::CPREFER));
assert!(!v2.is(Layout::FORDER) && !v2.is(Layout::FPREFER));
}
let b = M::zeros((5, 5).f());
{
let v1 = b.slice(s![..;2, ..]).layout();
let v2 = b.slice(s![.., ..;2]).layout();
assert!(!v1.is(Layout::CORDER) && !v1.is(Layout::CPREFER));
assert!(!v1.is(Layout::FORDER) && !v1.is(Layout::FPREFER));
assert!(!v2.is(Layout::CORDER) && !v2.is(Layout::CPREFER));
assert!(!v2.is(Layout::FORDER) && v2.is(Layout::FPREFER));
}
}
}