use crate::error::{LatticeError, Result};
use crate::geometry::Geometry;
use crate::layout::Layout;
use crate::mask::Mask;
use crate::shape::Shape;
#[derive(Clone)]
pub struct PaddedTileLattice<T> {
geom: Geometry,
shape: Shape,
layout: Layout,
mask: Mask,
data: Vec<T>,
}
impl<T> PaddedTileLattice<T> {
#[inline]
pub fn geometry(&self) -> &Geometry {
&self.geom
}
#[inline]
pub fn shape(&self) -> &Shape {
&self.shape
}
#[inline]
pub fn layout(&self) -> &Layout {
&self.layout
}
#[inline]
pub fn mask(&self) -> &Mask {
&self.mask
}
#[inline]
pub fn rows(&self) -> usize {
self.shape.rows
}
#[inline]
pub fn cols(&self) -> usize {
self.shape.cols
}
#[inline]
pub fn len(&self) -> usize {
self.shape.logical_len()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.shape.logical_len() == 0
}
#[inline]
pub fn padded_len(&self) -> usize {
self.shape.padded_len()
}
#[inline]
pub fn num_tiles(&self) -> usize {
(self.shape.padded_rows / self.geom.sublanes) * (self.shape.padded_cols / self.geom.lanes)
}
#[inline]
pub fn as_storage_slice(&self) -> &[T] {
&self.data
}
#[inline]
pub fn as_storage_slice_mut(&mut self) -> &mut [T] {
&mut self.data
}
#[inline]
pub fn get(&self, row: usize, col: usize) -> Option<&T> {
if !self.shape.contains(row, col) {
return None;
}
Some(&self.data[self.layout.offset(row, col)])
}
#[inline]
pub fn get_mut(&mut self, row: usize, col: usize) -> Option<&mut T> {
if !self.shape.contains(row, col) {
return None;
}
let off = self.layout.offset(row, col);
Some(&mut self.data[off])
}
pub fn set(&mut self, row: usize, col: usize, value: T) -> Result<()> {
if !self.shape.contains(row, col) {
return Err(LatticeError::IndexOutOfBounds { row, col });
}
let off = self.layout.offset(row, col);
self.data[off] = value;
Ok(())
}
}
impl<T: Clone + Default> PaddedTileLattice<T> {
pub fn zeroed(rows: usize, cols: usize, geom: Geometry) -> Result<Self> {
if geom.sublanes == 0 || geom.lanes == 0 || geom.mxu == 0 {
return Err(LatticeError::ZeroTileDimension);
}
let shape = Shape::new(rows, cols, &geom);
let layout = Layout::new(&shape, &geom);
let mask = Mask::from_shape(&shape);
let data = vec![T::default(); shape.padded_len()];
Ok(PaddedTileLattice {
geom,
shape,
layout,
mask,
data,
})
}
pub fn from_dense(rows: usize, cols: usize, dense: &[T], geom: Geometry) -> Result<Self> {
if dense.len() != rows * cols {
return Err(LatticeError::BufferLengthMismatch {
expected: rows * cols,
actual: dense.len(),
});
}
let mut lattice = PaddedTileLattice::zeroed(rows, cols, geom)?;
for row in 0..rows {
for col in 0..cols {
let off = lattice.layout.offset(row, col);
lattice.data[off] = dense[row * cols + col].clone();
}
}
Ok(lattice)
}
pub fn to_dense(&self) -> Vec<T> {
let mut out = Vec::with_capacity(self.shape.logical_len());
for row in 0..self.shape.rows {
for col in 0..self.shape.cols {
out.push(self.data[self.layout.offset(row, col)].clone());
}
}
out
}
pub fn fill_padding(&mut self, value: T) {
for off in 0..self.data.len() {
let (row, col) = self.layout.coord(off);
if !self.shape.contains(row, col) {
self.data[off] = value.clone();
}
}
}
}
impl<T> core::fmt::Debug for PaddedTileLattice<T> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("PaddedTileLattice")
.field("shape", &self.shape)
.field("geometry", &self.geom)
.field("tiles", &self.num_tiles())
.finish()
}
}