use core::marker::PhantomData;
use super::error::TensorError;
use super::layout::{ColMajor, Layout, RowMajor};
use super::strides::{compute_offset, row_major_strides};
mod rank_ops;
mod simd_bridge;
pub struct TensorView<'a, T: 'a, const N: usize, Layout = RowMajor, Ref = &'a [T]> {
pub(super) ptr: *mut [T],
pub(super) shape: [usize; N],
pub(super) strides: [usize; N],
pub(super) _layout: PhantomData<(&'a T, Layout, Ref)>,
}
unsafe impl<'a, T, const N: usize, Layout, Ref> Send for TensorView<'a, T, N, Layout, Ref> where
Ref: Send
{
}
unsafe impl<'a, T, const N: usize, Layout, Ref> Sync for TensorView<'a, T, N, Layout, Ref> where
Ref: Sync
{
}
impl<'a, T, const N: usize, Layout> Clone for TensorView<'a, T, N, Layout, &'a [T]> {
#[inline(always)]
fn clone(&self) -> Self {
*self
}
}
impl<'a, T, const N: usize, Layout> Copy for TensorView<'a, T, N, Layout, &'a [T]> {}
impl<'a, 'b, T, const N: usize> TensorView<'a, T, N, RowMajor, &'b [T]> {
#[inline]
pub fn new(data: &'b [T], shape: [usize; N]) -> Result<Self, TensorError> {
let elem_count = shape.iter().product::<usize>();
if elem_count > data.len() {
return Err(TensorError::ShapeMismatch);
}
let strides = row_major_strides(shape);
Ok(Self {
ptr: data as *const [T] as *mut [T],
shape,
strides,
_layout: PhantomData,
})
}
}
impl<'a, 'b, T, const N: usize> TensorView<'a, T, N, RowMajor, &'b mut [T]> {
#[inline]
pub fn new_mut(data: &'b mut [T], shape: [usize; N]) -> Result<Self, TensorError> {
let elem_count = shape.iter().product::<usize>();
if elem_count > data.len() {
return Err(TensorError::ShapeMismatch);
}
let strides = row_major_strides(shape);
Ok(Self {
ptr: data as *mut [T],
shape,
strides,
_layout: PhantomData,
})
}
}
impl<'a, 'b, T, const N: usize, L: Layout> TensorView<'a, T, N, L, &'b [T]> {
#[inline]
pub fn with_strides(
data: &'b [T],
shape: [usize; N],
strides: [usize; N],
) -> Result<Self, TensorError> {
let elem_count = shape.iter().product::<usize>();
if elem_count > data.len() {
return Err(TensorError::ShapeMismatch);
}
Ok(Self {
ptr: data as *const [T] as *mut [T],
shape,
strides,
_layout: PhantomData,
})
}
}
impl<'a, 'b, T, const N: usize, L: Layout> TensorView<'a, T, N, L, &'b mut [T]> {
#[inline]
pub fn with_strides_mut(
data: &'b mut [T],
shape: [usize; N],
strides: [usize; N],
) -> Result<Self, TensorError> {
let elem_count = shape.iter().product::<usize>();
if elem_count > data.len() {
return Err(TensorError::ShapeMismatch);
}
Ok(Self {
ptr: data as *mut [T],
shape,
strides,
_layout: PhantomData,
})
}
#[inline(always)]
pub fn downgrade(self) -> TensorView<'a, T, N, L, &'b [T]> {
TensorView {
ptr: self.ptr,
shape: self.shape,
strides: self.strides,
_layout: PhantomData,
}
}
}
impl<'a, 'b, T> TensorView<'a, T, 2, ColMajor, &'b [T]> {
#[inline]
pub fn new_col_major(data: &'b [T], shape: [usize; 2]) -> Result<Self, TensorError> {
let elem_count = shape[0] * shape[1];
if elem_count > data.len() {
return Err(TensorError::ShapeMismatch);
}
let strides = [1, shape[0]];
Ok(Self {
ptr: data as *const [T] as *mut [T],
shape,
strides,
_layout: PhantomData,
})
}
}
impl<'a, T, const N: usize, L, Ref> TensorView<'a, T, N, L, Ref> {
#[inline(always)]
pub fn shape(&self) -> [usize; N] {
self.shape
}
#[inline(always)]
pub fn strides(&self) -> [usize; N] {
self.strides
}
#[inline]
pub fn num_elements(&self) -> usize {
self.shape.iter().product()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.num_elements() == 0
}
#[inline]
pub fn is_contiguous(&self) -> bool {
let expected = row_major_strides(self.shape);
self.strides == expected
}
#[inline(always)]
pub fn as_slice(&self) -> &[T] {
unsafe { &*self.ptr }
}
#[inline]
pub fn get(&self, idx: [usize; N]) -> Result<T, TensorError>
where
T: Copy,
{
for i in 0..N {
if idx[i] >= self.shape[i] {
return Err(TensorError::IndexOutOfBounds);
}
}
let offset = compute_offset(&idx, &self.strides);
Ok(self.as_slice()[offset])
}
#[inline(always)]
pub unsafe fn get_unchecked(&self, idx: [usize; N]) -> T
where
T: Copy,
{
let offset = compute_offset(&idx, &self.strides);
*self.as_slice().get_unchecked(offset)
}
#[inline]
pub fn reshape<const M: usize>(
self,
new_shape: [usize; M],
) -> Result<TensorView<'a, T, M, RowMajor, Ref>, TensorError> {
if !self.is_contiguous() {
return Err(TensorError::NotContiguous);
}
let old_count: usize = self.shape.iter().product();
let new_count: usize = new_shape.iter().product();
if old_count != new_count {
return Err(TensorError::ShapeMismatch);
}
let strides = row_major_strides(new_shape);
Ok(TensorView {
ptr: self.ptr,
shape: new_shape,
strides,
_layout: PhantomData,
})
}
}
impl<'a, 'b, T, const N: usize, L> TensorView<'a, T, N, L, &'b mut [T]> {
#[inline(always)]
pub fn as_slice_mut(&mut self) -> &mut [T] {
unsafe { &mut *self.ptr }
}
#[inline]
pub fn set(&mut self, idx: [usize; N], val: T) -> Result<(), TensorError> {
for i in 0..N {
if idx[i] >= self.shape[i] {
return Err(TensorError::IndexOutOfBounds);
}
}
let offset = compute_offset(&idx, &self.strides);
self.as_slice_mut()[offset] = val;
Ok(())
}
#[inline(always)]
pub unsafe fn set_unchecked(&mut self, idx: [usize; N], val: T) {
let offset = compute_offset(&idx, &self.strides);
*self.as_slice_mut().get_unchecked_mut(offset) = val;
}
}