use std::mem::ManuallyDrop;
use std::ptr::{self, NonNull};
use std::marker::PhantomData;
use std::{fmt, mem, slice};
pub struct MdArray<T, const DIM: usize> {
ptr: NonNull<T>,
dim: [usize; DIM],
_phantom: PhantomData<Box<[T]>>,
}
unsafe impl<T: Send, const DIM: usize> Send for MdArray<T, DIM> { }
unsafe impl<T: Sync, const DIM: usize> Sync for MdArray<T, DIM> { }
impl<T, const DIM: usize> MdArray<T, DIM> {
#[inline]
pub unsafe fn from_boxed_slice_unchecked(slice: Box<[T]>, dim: [usize; DIM]) -> Self {
Self {
ptr: unsafe { NonNull::new_unchecked(Box::into_raw(slice) as *mut T) },
dim,
_phantom: PhantomData
}
}
pub fn try_from_boxed_slice<S: Into<Box<[T]>>>(slice: S, dim: [usize; DIM]) -> Option<Self> {
let len = array_len(&dim)?;
let slice = slice.into();
if slice.len() != len {
return None;
}
Some(unsafe { Self::from_boxed_slice_unchecked(slice, dim) })
}
#[inline]
pub fn into_boxed_slice(self: Self) -> Box<[T]> {
unsafe {
let this = ManuallyDrop::new(self);
let len = array_len(&this.dim).unwrap_unchecked();
let ptr = ptr::slice_from_raw_parts_mut(this.ptr.as_ptr(), len);
Box::from_raw(ptr)
}
}
#[inline]
pub fn as_view(&self) -> MdView<'_, T, DIM> {
MdView {
ptr: self.ptr,
dim: self.dim,
_phantom: PhantomData,
}
}
#[inline]
pub fn is_empty(self) -> bool {
self.as_view().is_empty()
}
#[inline]
pub fn raw_len(&self) -> usize {
self.as_view().raw_len()
}
#[inline]
pub fn as_raw_slice(&self) -> &[T] {
self.as_view().as_raw_slice()
}
#[inline]
pub fn as_raw_slice_mut(&mut self) -> &mut [T] {
let len = self.raw_len();
unsafe { slice::from_raw_parts_mut(self.ptr.as_ptr(), len) }
}
#[inline]
pub fn len(&self, dim_index: usize) -> usize {
self.dim[dim_index]
}
#[inline]
pub fn get(&self, index: [usize; DIM]) -> Option<&T> {
self.as_view().get(index)
}
#[inline]
pub fn get_mut(&mut self, index: [usize; DIM]) -> Option<&mut T> {
let index = array_index(&self.dim, &index)?;
unsafe { Some(&mut *self.ptr.add(index).as_ptr()) }
}
#[inline]
pub fn map<R, F: FnMut(T) -> R>(self, func: F) -> MdArray<R, DIM> {
let dim = self.dim;
let new_slice = Self::into_boxed_slice(self)
.into_iter()
.map(func)
.collect::<Box<[R]>>();
unsafe { MdArray::from_boxed_slice_unchecked(new_slice, dim) }
}
#[inline]
pub fn map_to_owned<'a, U, F: FnMut(&'a T) -> U>(&'a self, func: F) -> MdArray<U, DIM> {
self.as_view().map_to_owned(func)
}
#[inline]
pub fn as_shape<const NEW_DIM: usize>(&self, new_dim: [usize; NEW_DIM]) -> Option<MdView<'_, T, NEW_DIM>> {
self.as_view().as_shape(new_dim)
}
#[inline]
pub fn into_shape<const NEW_DIM: usize>(self, new_dim: [usize; NEW_DIM]) -> Result<MdArray<T, NEW_DIM>, Self> {
if array_len(&new_dim) != Some(self.raw_len()) {
return Err(self);
}
Ok(MdArray {
ptr: self.ptr,
dim: new_dim,
_phantom: PhantomData,
})
}
}
impl<T, const DIM: usize> Drop for MdArray<T, DIM> {
fn drop(&mut self) {
drop(mem::replace(self, Self {
ptr: NonNull::dangling(),
dim: [0; DIM],
_phantom: PhantomData,
}).into_boxed_slice())
}
}
impl<T: Clone, const DIM: usize> Clone for MdArray<T, DIM> {
fn clone(&self) -> Self {
self.as_view().to_owned()
}
}
impl<T: fmt::Debug, const DIM: usize> fmt::Debug for MdArray<T, DIM> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_fmt(format_args!("MdArray"))?;
fmt::Debug::fmt(&self.as_view(), f)
}
}
impl<T> From<T> for MdArray<T, 0> {
#[inline]
fn from(value: T) -> Self {
unsafe {
Self::from_boxed_slice_unchecked(Box::new([value]), [])
}
}
}
impl<T> From<Box<[T]>> for MdArray<T, 1> {
#[inline]
fn from(value: Box<[T]>) -> Self {
unsafe {
let len = value.len();
Self::from_boxed_slice_unchecked(value, [len])
}
}
}
impl<T> From<Vec<T>> for MdArray<T, 1> {
#[inline]
fn from(value: Vec<T>) -> Self {
value.into_boxed_slice().into()
}
}
impl<T, const N: usize> From<[T; N]> for MdArray<T, 1> {
#[inline]
fn from(value: [T; N]) -> Self {
Box::<[T]>::from(value).into()
}
}
pub struct MdView<'a, T: 'a, const DIM: usize> {
ptr: NonNull<T>,
dim: [usize; DIM],
_phantom: PhantomData<&'a [T]>,
}
unsafe impl<'a, T: Send, const DIM: usize> Send for MdView<'a, T, DIM> { }
unsafe impl<'a, T: Sync, const DIM: usize> Sync for MdView<'a, T, DIM> { }
impl<'a, T, const DIM: usize> MdView<'a, T, DIM> {
#[inline]
pub unsafe fn from_slice_unchecked(slice: &[T], dim: [usize; DIM]) -> Self {
Self {
ptr: NonNull::from_ref(&slice[0]),
dim,
_phantom: PhantomData
}
}
pub fn try_from_slice<S: AsRef<[T]>>(slice: S, dim: [usize; DIM]) -> Option<Self> {
let len = array_len(&dim)?;
let slice = slice.as_ref();
if slice.len() != len {
return None;
}
Some(unsafe { Self::from_slice_unchecked(slice, dim) })
}
#[inline]
pub fn is_empty(self) -> bool {
self.raw_len() == 0
}
#[inline]
pub fn raw_len(self) -> usize {
unsafe { array_len(&self.dim).unwrap_unchecked() }
}
#[inline]
pub fn as_raw_slice(self) -> &'a [T] {
let len = self.raw_len();
unsafe { slice::from_raw_parts(self.ptr.as_ptr(), len) }
}
#[inline]
pub fn to_owned(self) -> MdArray<T, DIM>
where
T: Clone,
{
let slice = Box::<[T]>::from(self.as_raw_slice());
unsafe {
MdArray::from_boxed_slice_unchecked(slice, self.dim)
}
}
#[inline]
pub fn len(self, dim_index: usize) -> usize {
self.dim[dim_index]
}
#[inline]
pub fn get(self, index: [usize; DIM]) -> Option<&'a T> {
let index = array_index(&self.dim, &index)?;
unsafe {
Some(&*self.ptr.add(index).as_ptr())
}
}
#[inline]
pub fn map_to_owned<U, F: FnMut(&'a T) -> U>(self, func: F) -> MdArray<U, DIM> {
let dim = self.dim;
let new_slice = self.as_raw_slice()
.into_iter()
.map(func)
.collect::<Box<[U]>>();
unsafe { MdArray::from_boxed_slice_unchecked(new_slice, dim) }
}
#[inline]
pub fn as_shape<const NEW_DIM: usize>(self, new_dim: [usize; NEW_DIM]) -> Option<MdView<'a, T, NEW_DIM>> {
if array_len(&new_dim) != Some(self.raw_len()) {
return None;
}
Some(MdView {
ptr: self.ptr,
dim: new_dim,
_phantom: PhantomData,
})
}
}
impl<'a, T, const DIM: usize> Clone for MdView<'a, T, DIM> {
#[inline]
fn clone(&self) -> Self {
Self {
ptr: self.ptr,
dim: self.dim,
_phantom: PhantomData,
}
}
}
impl<'a, T, const DIM: usize> Copy for MdView<'a, T, DIM> { }
impl<'a, T: fmt::Debug, const DIM: usize> fmt::Debug for MdView<'a, T, DIM> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_fmt(format_args!("<{DIM}>"))?;
let mut counter = [0; DIM];
for val in self.as_raw_slice() {
let mut open_count = 0;
while open_count < DIM && counter[open_count] == 0 {
open_count += 1;
}
if counter != [0; DIM] {
f.write_str(", ")?;
if open_count != 0 && f.alternate() {
f.write_str("\n")?;
}
}
for i in (0..open_count).rev() {
f.write_str("[")?;
if i != 0 && f.alternate() {
f.write_str("\n")?;
}
}
f.write_fmt(format_args!("{val:?}"))?;
counter[0] += 1;
for i in 0..DIM {
if counter[i] == self.dim[i] {
f.write_str("]")?;
if let Some(next_count) = counter.get_mut(i + 1) {
*next_count += 1;
}
counter[i] = 0;
}
}
}
Ok(())
}
}
impl<'a, T> From<&'a T> for MdView<'a, T, 0> {
#[inline]
fn from(value: &'a T) -> Self {
unsafe {
Self::from_slice_unchecked(slice::from_ref(value), [])
}
}
}
impl<'a, T> From<&'a [T]> for MdView<'a, T, 1> {
#[inline]
fn from(value: &'a [T]) -> Self {
unsafe {
let len = value.len();
Self::from_slice_unchecked(value, [len])
}
}
}
fn array_len<const DIM: usize>(dim: &[usize; DIM]) -> Option<usize> {
let mut flat = 1usize;
for &val in dim {
flat = flat.checked_mul(val)?;
}
Some(flat)
}
fn array_index<const DIM: usize>(dim: &[usize; DIM], index: &[usize; DIM]) -> Option<usize> {
let mut flat = 0;
for i in (0..DIM).rev() {
if index[i] >= dim[i] {
return None;
}
flat *= dim[i];
flat += index[i];
}
Some(flat)
}