use std::marker::PhantomData;
use crate::strides::Strides;
pub type CircularArrayVec<const N: usize, T> = CircularArray<N, Vec<T>, T>;
pub type CircularArrayBox<const N: usize, T> = CircularArray<N, Box<[T]>, T>;
pub struct CircularArray<const N: usize, A, T> {
pub(crate) array: A,
pub(crate) shape: [usize; N],
pub(crate) strides: Strides<N>,
pub(crate) offset: [usize; N],
_phantom: PhantomData<T>,
}
impl<const N: usize, A, T> CircularArray<N, A, T>
where
A: AsRef<[T]>,
{
pub fn new(shape: [usize; N], array: A) -> CircularArray<N, A, T> {
Self::new_offset(shape, [0; N], array)
}
pub fn new_offset(shape: [usize; N], offset: [usize; N], array: A) -> CircularArray<N, A, T> {
assert!(
array.as_ref().len() == shape.iter().product(),
"Element length does not match shape"
);
let array = array;
let strides = Strides::new(&shape);
CircularArray {
array,
strides,
shape,
offset,
_phantom: PhantomData,
}
}
pub fn shape(&self) -> &[usize; N] {
&self.shape
}
#[cfg(feature = "strides")]
pub fn strides(&self) -> &Strides<N> {
&self.strides
}
pub fn offset(&self) -> &[usize; N] {
&self.offset
}
pub fn offset_mut(&mut self) -> &mut [usize; N] {
&mut self.offset
}
pub fn len(&self) -> usize {
self.shape.iter().product()
}
pub fn slice_len(&self, axis: usize) -> usize {
self.shape
.iter()
.enumerate()
.fold(1, |acc, (i, sh)| if i == axis { acc } else { acc * sh })
}
pub fn take(self) -> A {
self.array
}
pub fn data(&self) -> &A {
&self.array
}
pub fn data_mut(&mut self) -> &mut A {
&mut self.array
}
}
impl<const N: usize, T> CircularArray<N, Vec<T>, T> {
pub fn from_iter(shape: [usize; N], iter: impl Iterator<Item = T>) -> Self {
let array = iter.collect::<Vec<T>>();
Self::new_offset(shape, [0; N], array)
}
pub fn from_iter_offset(
shape: [usize; N],
offset: [usize; N],
iter: impl Iterator<Item = T>,
) -> Self {
let array = iter.collect::<Vec<T>>();
Self::new_offset(shape, offset, array)
}
}
impl<const N: usize, T> CircularArray<N, Box<[T]>, T> {
pub fn from_iter(shape: [usize; N], iter: impl Iterator<Item = T>) -> Self {
let array = iter.collect::<Vec<T>>().into_boxed_slice();
Self::new_offset(shape, [0; N], array)
}
pub fn from_iter_offset(
shape: [usize; N],
iter: impl Iterator<Item = T>,
offset: [usize; N],
) -> Self {
let array = iter.collect::<Vec<T>>().into_boxed_slice();
Self::new_offset(shape, offset, array)
}
}