use crate::{
dense::layout::{check_multi_index_in_bounds, col_major_stride_from_shape},
traits::{
accessors::{
RawAccess, RawAccessMut, StableRawAccessMut, UnsafeDisjointRandom1DAccessMut,
UnsafeRandom1DAccessByRef, UnsafeRandom1DAccessByValue, UnsafeRandom1DAccessMut,
UnsafeRandomAccessByRef, UnsafeRandomAccessByValue, UnsafeRandomAccessMut,
},
base_operations::{BaseItem, ResizeInPlace, Shape, Stride},
data_container::{
ContainerType, DataContainer, DisjointRefDataContainerMut,
MutableRawAccessDataContainer, RawAccessDataContainer, RefDataContainer,
RefDataContainerMut, ResizeableDataContainer, StableRawAccessDataContainer,
ValueDataContainer,
},
},
};
pub struct BaseArray<Data, const NDIM: usize> {
data: Data,
shape: [usize; NDIM],
}
impl<Data: ContainerType, const NDIM: usize> ContainerType for BaseArray<Data, NDIM> {
type Type = Data::Type;
}
impl<Data: DataContainer, const NDIM: usize> BaseArray<Data, NDIM> {
pub fn new(data: Data, shape: [usize; NDIM]) -> Self {
assert!(
NDIM > 0,
"BaseArray requires a positive rank; use ZeroDimArray for scalar storage"
);
assert_eq!(
data.number_of_elements(),
shape.iter().product::<usize>(),
"Expected {} elements but `data` has {} elements",
shape.iter().product::<usize>(),
data.number_of_elements()
);
Self { data, shape }
}
}
impl<Data, const NDIM: usize> Shape<NDIM> for BaseArray<Data, NDIM> {
#[inline(always)]
fn shape(&self) -> [usize; NDIM] {
self.shape
}
}
impl<Data: DataContainer, const NDIM: usize> BaseItem for BaseArray<Data, NDIM> {
type Item = Data::Item;
}
impl<Data: RefDataContainer, const NDIM: usize> UnsafeRandomAccessByRef<NDIM>
for BaseArray<Data, NDIM>
{
#[inline(always)]
unsafe fn get_unchecked(&self, multi_index: [usize; NDIM]) -> &Self::Item {
debug_assert!(check_multi_index_in_bounds(multi_index, self.shape()));
unsafe {
self.data
.get_unchecked(compute_col_major_index(multi_index, self.shape))
}
}
}
impl<Data: ValueDataContainer, const NDIM: usize> UnsafeRandom1DAccessByValue
for BaseArray<Data, NDIM>
{
#[inline(always)]
unsafe fn get_value_1d_unchecked(&self, index: usize) -> Self::Item {
unsafe { self.data.get_unchecked_value(index) }
}
}
impl<Data: RefDataContainer, const NDIM: usize> UnsafeRandom1DAccessByRef
for BaseArray<Data, NDIM>
{
#[inline(always)]
unsafe fn get_1d_unchecked(&self, index: usize) -> &Self::Item {
unsafe { self.data.get_unchecked(index) }
}
}
impl<Data: RefDataContainerMut, const NDIM: usize> UnsafeRandom1DAccessMut
for BaseArray<Data, NDIM>
{
#[inline(always)]
unsafe fn get_1d_unchecked_mut(&mut self, index: usize) -> &mut Self::Item {
unsafe { self.data.get_unchecked_mut(index) }
}
}
unsafe impl<Data: DisjointRefDataContainerMut, const NDIM: usize> UnsafeDisjointRandom1DAccessMut
for BaseArray<Data, NDIM>
{
}
impl<Data: ValueDataContainer, const NDIM: usize> UnsafeRandomAccessByValue<NDIM>
for BaseArray<Data, NDIM>
{
#[inline(always)]
unsafe fn get_value_unchecked(&self, multi_index: [usize; NDIM]) -> Self::Item {
debug_assert!(check_multi_index_in_bounds(multi_index, self.shape()));
unsafe {
self.data
.get_unchecked_value(compute_col_major_index(multi_index, self.shape))
}
}
}
impl<Data: RefDataContainerMut, const NDIM: usize> UnsafeRandomAccessMut<NDIM>
for BaseArray<Data, NDIM>
{
#[inline(always)]
unsafe fn get_unchecked_mut(&mut self, multi_index: [usize; NDIM]) -> &mut Self::Item {
debug_assert!(check_multi_index_in_bounds(multi_index, self.shape()));
unsafe {
self.data
.get_unchecked_mut(compute_col_major_index(multi_index, self.shape))
}
}
}
impl<Data: RawAccessDataContainer, const NDIM: usize> RawAccess for BaseArray<Data, NDIM> {
#[inline(always)]
fn data(&self) -> Option<&[Self::Item]> {
self.data.data()
}
}
unsafe impl<Data: StableRawAccessDataContainer, const NDIM: usize> StableRawAccessMut
for BaseArray<Data, NDIM>
{
}
impl<Data: MutableRawAccessDataContainer, const NDIM: usize> RawAccessMut
for BaseArray<Data, NDIM>
{
#[inline(always)]
fn data_mut(&mut self) -> Option<&mut [Self::Item]> {
self.data.data_mut()
}
}
impl<Data, const NDIM: usize> Stride<NDIM> for BaseArray<Data, NDIM> {
#[inline(always)]
fn stride(&self) -> [usize; NDIM] {
col_major_stride_from_shape(self.shape)
}
}
impl<Data: ResizeableDataContainer, const NDIM: usize> ResizeInPlace<NDIM>
for BaseArray<Data, NDIM>
{
#[inline(always)]
fn resize_in_place(&mut self, shape: [usize; NDIM]) {
let new_len = shape.iter().product();
self.data.resize(new_len);
self.shape = shape;
}
}
#[inline(always)]
fn compute_col_major_index<const NDIM: usize>(
multi_index: [usize; NDIM],
shape: [usize; NDIM],
) -> usize {
let mut acc = 0;
let mut shape_prod = 1;
for index in 0..NDIM {
acc += multi_index[index] * shape_prod;
shape_prod *= shape[index];
}
acc
}