use std::ptr::NonNull;
use crate::SimdVector;
const fn compute_align<S>() -> usize {
let base_align = std::mem::align_of::<S>();
let min_align = if cfg!(target_arch = "x86_64") {
32usize
} else {
1usize
};
if base_align > min_align {
base_align
} else {
min_align
}
}
#[derive(Debug, Clone)]
pub struct SimpleGrid<S> {
width: usize,
height: usize,
offset: usize,
buf: Vec<S>,
}
impl<S: Default + Clone> SimpleGrid<S> {
const ALIGN: usize = compute_align::<S>();
pub fn new(width: usize, height: usize) -> Self {
let len = width * height;
let mut buf = vec![S::default(); len];
let extra = buf.as_ptr() as usize & (Self::ALIGN - 1);
let offset = (Self::ALIGN - extra) % Self::ALIGN;
buf.resize(buf.len() + offset, S::default());
Self {
width,
height,
offset,
buf,
}
}
}
impl<S> SimpleGrid<S> {
#[inline]
pub fn width(&self) -> usize {
self.width
}
#[inline]
pub fn height(&self) -> usize {
self.height
}
#[inline]
pub fn get(&self, x: usize, y: usize) -> Option<&S> {
if x >= self.width || y >= self.height {
return None;
}
Some(&self.buf[y * self.width + x + self.offset])
}
#[inline]
pub fn get_mut(&mut self, x: usize, y: usize) -> Option<&mut S> {
if x >= self.width || y >= self.height {
return None;
}
Some(&mut self.buf[y * self.width + x + self.offset])
}
#[inline]
pub fn buf(&self) -> &[S] {
&self.buf[self.offset..]
}
#[inline]
pub fn buf_mut(&mut self) -> &mut [S] {
&mut self.buf[self.offset..]
}
#[inline]
pub(crate) fn into_buf_iter(self) -> impl Iterator<Item = S> {
self.buf.into_iter().skip(self.offset)
}
}
#[derive(Debug)]
pub struct CutGrid<'g, V: Copy = f32> {
ptr: NonNull<V>,
width: usize,
height: usize,
stride: usize,
_marker: std::marker::PhantomData<&'g mut [V]>,
}
impl<'g, V: Copy> CutGrid<'g, V> {
pub unsafe fn new(ptr: NonNull<V>, width: usize, height: usize, stride: usize) -> Self {
Self {
ptr,
width,
height,
stride,
_marker: Default::default(),
}
}
pub fn from_buf(buf: &'g mut [V], width: usize, height: usize, stride: usize) -> Self {
assert!(width > 0);
assert!(height > 0);
assert!(width <= stride);
assert!(buf.len() >= stride * (height - 1) + width);
unsafe {
Self::new(
NonNull::new(buf.as_mut_ptr()).unwrap(),
width,
height,
stride,
)
}
}
#[inline]
pub fn width(&self) -> usize {
self.width
}
#[inline]
pub fn height(&self) -> usize {
self.height
}
#[inline]
fn get_ptr(&self, x: usize, y: usize) -> *mut V {
if x >= self.width || y >= self.height {
panic!(
"Coordinate out of range: ({}, {}) not in {}x{}",
x, y, self.width, self.height
);
}
unsafe {
let offset = y * self.stride + x;
self.ptr.as_ptr().add(offset)
}
}
#[inline]
pub fn get(&self, x: usize, y: usize) -> V {
let ptr = self.get_ptr(x, y);
unsafe { *ptr }
}
#[inline]
pub fn get_row(&self, row: usize) -> &[V] {
let ptr = self.get_ptr(0, row);
unsafe { std::slice::from_raw_parts(ptr as *const _, self.width) }
}
#[inline]
pub fn get_mut(&mut self, x: usize, y: usize) -> &mut V {
let ptr = self.get_ptr(x, y);
unsafe { ptr.as_mut().unwrap() }
}
#[inline]
pub fn get_row_mut(&mut self, row: usize) -> &mut [V] {
let ptr = self.get_ptr(0, row);
unsafe { std::slice::from_raw_parts_mut(ptr, self.width) }
}
#[inline]
pub fn swap(&mut self, (ax, ay): (usize, usize), (bx, by): (usize, usize)) {
let a = self.get_ptr(ax, ay);
let b = self.get_ptr(bx, by);
if std::ptr::eq(a, b) {
return;
}
unsafe {
std::ptr::swap(a, b);
}
}
}
impl<'g> CutGrid<'g, f32> {
pub fn as_vectored<V: SimdVector>(&mut self) -> Option<CutGrid<'_, V>> {
let mask = V::SIZE - 1;
let align_mask = std::mem::align_of::<V>() - 1;
(self.ptr.as_ptr() as usize & align_mask == 0
&& self.width & mask == 0
&& self.stride & mask == 0)
.then(|| CutGrid {
ptr: self.ptr.cast::<V>(),
width: self.width / V::SIZE,
height: self.height,
stride: self.stride / V::SIZE,
_marker: Default::default(),
})
}
}
#[derive(Debug, Clone)]
pub struct PaddedGrid<S: Clone> {
pub grid: SimpleGrid<S>,
padding: usize,
}
impl<S: Default + Clone> PaddedGrid<S> {
pub fn new(width: usize, height: usize, padding: usize) -> Self {
Self {
grid: SimpleGrid::new(width + padding * 2, height + padding * 2),
padding,
}
}
}
impl<S: Clone> PaddedGrid<S> {
#[inline]
pub fn width(&self) -> usize {
self.grid.width - self.padding * 2
}
#[inline]
pub fn height(&self) -> usize {
self.grid.height - self.padding * 2
}
#[inline]
pub fn padding(&self) -> usize {
self.padding
}
#[inline]
pub fn buf_padded(&self) -> &[S] {
self.grid.buf()
}
#[inline]
pub fn buf_padded_mut(&mut self) -> &mut [S] {
self.grid.buf_mut()
}
pub fn mirror_edges_padding(&mut self) {
let padding = self.padding;
let stride = self.grid.width();
let height = self.grid.height() - padding * 2;
let buf = self.grid.buf_mut();
for y in padding..height + padding {
for x in 0..padding {
buf[y * stride + x] = buf[y * stride + padding * 2 - x - 1].clone();
buf[(y + 1) * stride - x - 1] = buf[(y + 1) * stride - padding * 2 + x].clone();
}
}
let (out_chunk, in_chunk) = buf.split_at_mut(stride * padding);
let in_chunk = &in_chunk[..stride * padding];
for (out_row, in_row) in out_chunk.chunks_exact_mut(stride).zip(in_chunk.chunks_exact(stride).rev()) {
out_row.clone_from_slice(in_row);
}
let (in_chunk, out_chunk) = buf.split_at_mut(stride * (height + padding));
for (out_row, in_row) in out_chunk.chunks_exact_mut(stride).zip(in_chunk.chunks_exact(stride).rev()) {
out_row.clone_from_slice(in_row);
}
}
}