use crate::dimension::Dimension;
use crate::index::ViewIndex;
use crate::layout::{DenseLayout, Layout, StridedLayout};
use crate::order::Order;
use crate::raw_vec::RawVec;
use crate::view::ViewBase;
use std::alloc::{Allocator, Global};
use std::marker::PhantomData;
use std::ops::{Deref, DerefMut, Index, IndexMut};
use std::{cmp, mem, ptr};
pub struct GridBase<T, B: Buffer<T, N, O>, const N: usize, O: Order> {
buffer: B,
_marker: PhantomData<(T, O)>,
}
pub trait Buffer<T, const N: usize, O: Order> {
type Layout: Layout<N, O>;
fn as_mut_ptr(&mut self) -> *mut T;
fn as_ptr(&self) -> *const T;
fn layout(&self) -> &Self::Layout;
}
pub struct DenseBuffer<T, const N: usize, O: Order, A: Allocator> {
vec: RawVec<T, A>,
layout: DenseLayout<N, O>,
}
pub struct StaticBuffer<T, D: Dimension<N>, const N: usize, O: Order>
where
[T; D::LEN]: ,
{
array: [T; D::LEN],
_marker: PhantomData<(D, O)>,
}
pub type DenseGrid<T, const N: usize, O, A = Global> = GridBase<T, DenseBuffer<T, N, O, A>, N, O>;
pub type StaticGrid<T, D, const N: usize, O> = GridBase<T, StaticBuffer<T, D, N, O>, N, O>;
impl<T, const N: usize, O: Order> DenseGrid<T, N, O, Global> {
pub fn new() -> Self {
Self::new_in(Global)
}
pub fn with_capacity(capacity: usize) -> Self {
Self::with_capacity_in(capacity, Global)
}
}
impl<T, const N: usize, O: Order, A: Allocator> DenseGrid<T, N, O, A> {
pub fn allocator(&self) -> &A {
self.buffer.vec.allocator()
}
pub fn capacity(&self) -> usize {
self.buffer.vec.capacity()
}
pub fn clear(&mut self) {
let len = self.len();
self.buffer.layout.resize([0; N], [0; 0]);
for i in 0..len {
unsafe {
ptr::read(self.buffer.vec.as_ptr().add(i));
}
}
}
pub fn new_in(alloc: A) -> Self {
assert!(mem::size_of::<T>() != 0);
Self {
buffer: DenseBuffer {
vec: RawVec::new_in(alloc),
layout: DenseLayout::new([0; N], [0; 0]),
},
_marker: PhantomData,
}
}
pub fn reshape<const M: usize>(self, shape: [usize; M]) -> DenseGrid<T, M, O, A> {
let len = shape
.iter()
.fold(1usize, |acc, &x| acc.checked_mul(x).unwrap());
assert_eq!(len, self.len());
let me = mem::ManuallyDrop::new(self);
DenseGrid {
buffer: DenseBuffer {
vec: unsafe { ptr::read(&me.buffer.vec) },
layout: DenseLayout::new(shape, [0; 0]),
},
_marker: PhantomData,
}
}
pub fn shrink_to(&mut self, min_capacity: usize) {
let capacity = cmp::max(min_capacity, self.len());
if capacity < self.capacity() {
self.buffer.vec.shrink(capacity);
}
}
pub fn shrink_to_fit(&mut self) {
if self.len() < self.capacity() {
self.buffer.vec.shrink(self.len());
}
}
pub fn with_capacity_in(capacity: usize, alloc: A) -> Self {
assert!(mem::size_of::<T>() != 0);
Self {
buffer: DenseBuffer {
vec: RawVec::with_capacity_in(capacity, alloc),
layout: DenseLayout::new([0; N], [0; 0]),
},
_marker: PhantomData,
}
}
}
impl<T: Clone, const N: usize, O: Order, A: Allocator> DenseGrid<T, N, O, A> {
pub fn resize(&mut self, shape: [usize; N], value: T) {
assert!(self.len() == 0);
let len = shape
.iter()
.fold(1usize, |acc, &x| acc.checked_mul(x).unwrap());
if len > self.capacity() {
self.buffer.vec.grow(len);
}
for i in 0..len {
unsafe {
ptr::write(self.buffer.vec.as_mut_ptr().add(i), value.clone());
}
}
self.buffer.layout.resize(shape, [0; 0]);
}
}
impl<T: Copy, D: Dimension<N>, const N: usize, O: Order> StaticGrid<T, D, N, O>
where
[(); D::LEN]: ,
{
pub fn new(value: T) -> Self {
assert!(mem::size_of::<T>() != 0);
Self {
buffer: StaticBuffer {
array: [value; D::LEN],
_marker: PhantomData,
},
_marker: PhantomData,
}
}
}
impl<T, D: Dimension<N>, const N: usize, O: Order> StaticBuffer<T, D, N, O>
where
[T; D::LEN]: ,
{
const LAYOUT: DenseLayout<N, O> = DenseLayout::new(D::SHAPE, [0; 0]);
}
impl<T, const N: usize, O: Order, A: Allocator> Buffer<T, N, O> for DenseBuffer<T, N, O, A> {
type Layout = DenseLayout<N, O>;
fn as_mut_ptr(&mut self) -> *mut T {
self.vec.as_mut_ptr()
}
fn as_ptr(&self) -> *const T {
self.vec.as_ptr()
}
fn layout(&self) -> &DenseLayout<N, O> {
&self.layout
}
}
impl<T, const N: usize, O: Order, D: Dimension<N>> Buffer<T, N, O> for StaticBuffer<T, D, N, O>
where
[(); D::LEN]: ,
{
type Layout = DenseLayout<N, O>;
fn as_mut_ptr(&mut self) -> *mut T {
self.array.as_mut_ptr()
}
fn as_ptr(&self) -> *const T {
self.array.as_ptr()
}
fn layout(&self) -> &DenseLayout<N, O> {
&Self::LAYOUT
}
}
impl<T, B: Buffer<T, N, O> + Clone, const N: usize, O: Order> Clone for GridBase<T, B, N, O> {
fn clone(&self) -> Self {
Self {
buffer: self.buffer.clone(),
_marker: PhantomData,
}
}
}
impl<T: Clone, const N: usize, O: Order, A: Allocator + Clone> Clone for DenseBuffer<T, N, O, A> {
fn clone(&self) -> Self {
let len = self.layout.shape().iter().product();
let mut vec = RawVec::<T, A>::with_capacity_in(len, self.vec.allocator().clone());
for i in 0..len {
unsafe {
ptr::write(vec.as_mut_ptr().add(i), (*self.vec.as_ptr().add(i)).clone());
}
}
Self {
vec,
layout: DenseLayout::new(self.layout.shape().clone(), [0; 0]),
}
}
}
impl<T: Clone, const N: usize, O: Order, D: Dimension<N>> Clone for StaticBuffer<T, D, N, O>
where
[(); D::LEN]: ,
{
fn clone(&self) -> Self {
Self {
array: self.array.clone(),
_marker: PhantomData,
}
}
}
impl<T, const N: usize, O: Order> Default for DenseGrid<T, N, O, Global> {
fn default() -> Self {
Self::new()
}
}
impl<T: Copy + Default, D: Dimension<N>, const N: usize, O: Order> Default
for StaticGrid<T, D, N, O>
where
[(); D::LEN]: ,
{
fn default() -> Self {
Self {
buffer: StaticBuffer {
array: [T::default(); D::LEN], _marker: PhantomData,
},
_marker: PhantomData,
}
}
}
impl<T, B: Buffer<T, N, O>, const N: usize, O: Order> Deref for GridBase<T, B, N, O> {
type Target = ViewBase<T, B::Layout, N, O>;
fn deref(&self) -> &Self::Target {
unsafe { ViewBase::from_raw_parts(self.buffer.as_ptr(), self.buffer.layout()) }
}
}
impl<T, B: Buffer<T, N, O>, const N: usize, O: Order> DerefMut for GridBase<T, B, N, O> {
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { ViewBase::from_raw_parts_mut(self.buffer.as_mut_ptr(), self.buffer.layout()) }
}
}
impl<T, const N: usize, O: Order, A: Allocator> Drop for DenseBuffer<T, N, O, A> {
fn drop(&mut self) {
for i in 0..self.layout.shape().iter().product() {
unsafe {
ptr::read(self.vec.as_ptr().add(i));
}
}
}
}
impl<I: ViewIndex<T, N, M, O>, T, B, const N: usize, const M: usize, O: Order> Index<I>
for GridBase<T, B, N, O>
where
B: Buffer<T, N, O, Layout = StridedLayout<N, M, O>>,
{
type Output = I::Output;
fn index(&self, index: I) -> &I::Output {
index.index(&**self)
}
}
impl<I: ViewIndex<T, N, M, O>, T, B, const N: usize, const M: usize, O: Order> IndexMut<I>
for GridBase<T, B, N, O>
where
B: Buffer<T, N, O, Layout = StridedLayout<N, M, O>>,
{
fn index_mut(&mut self, index: I) -> &mut I::Output {
index.index_mut(&mut **self)
}
}