use crate::domain::error::{LetoError, Result};
use crate::domain::layout::kernels;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct LayoutDyn {
pub shape: Box<[usize]>,
pub strides: Box<[isize]>,
pub offset: usize,
}
impl LayoutDyn {
pub fn new(shape: Box<[usize]>, strides: Box<[isize]>, offset: usize) -> Result<Self> {
if shape.len() != strides.len() {
return Err(LetoError::StorageError {
reason: format!(
"dynamic layout shape rank {} does not match stride rank {}",
shape.len(),
strides.len()
),
});
}
Ok(Self {
shape,
strides,
offset,
})
}
pub fn c_contiguous(shape: &[usize]) -> Result<Self> {
let mut strides = vec![0isize; shape.len()];
kernels::c_contiguous_strides(shape, &mut strides)?;
Ok(Self {
shape: shape.to_vec().into_boxed_slice(),
strides: strides.into_boxed_slice(),
offset: 0,
})
}
#[inline]
pub fn ndim(&self) -> usize {
self.shape.len()
}
#[inline]
pub fn size(&self) -> usize {
self.checked_size()
.expect("layout shape product must fit in usize")
}
#[inline]
pub fn checked_size(&self) -> Result<usize> {
kernels::shape_size(&self.shape)
}
#[inline]
pub fn checked_min_max_offsets(&self) -> Result<(usize, usize)> {
kernels::min_max_offsets(&self.shape, &self.strides, self.offset)
}
#[inline]
pub fn is_injective(&self) -> Result<bool> {
kernels::is_injective(&self.shape, &self.strides)
}
pub fn broadcast(&self, target_shape: &[usize]) -> Result<Self> {
let mut output_strides = vec![0isize; target_shape.len()];
kernels::broadcast_strides(
&self.shape,
&self.strides,
target_shape,
&mut output_strides,
)?;
Self::new(
target_shape.to_vec().into_boxed_slice(),
output_strides.into_boxed_slice(),
self.offset,
)
}
#[inline]
pub fn offset_of(&self, index: &[usize]) -> Result<usize> {
kernels::physical_offset(&self.shape, &self.strides, self.offset, index)
}
#[inline]
pub fn validate_storage_len(&self, storage_len: usize) -> Result<()> {
kernels::validate_storage(&self.shape, &self.strides, self.offset, storage_len)
}
pub fn is_c_contiguous(&self) -> bool {
if self.offset != 0 {
return false;
}
let mut expected = vec![0isize; self.ndim()];
match kernels::c_contiguous_strides(&self.shape, &mut expected) {
Ok(()) => {}
Err(_) => return false,
}
self.strides.as_ref() == expected.as_slice()
}
}