use std::mem::MaybeUninit;
use std::iter::Iterator;
use crate::base::*;
use std::ops::{ Add, BitOr };
use typenum::{
IsLessOrEqual, Sum, LeEq, True, U1
};
#[cfg(doc)] use crate::algebra::*;
#[cfg(doc)] use crate::subspace::*;
pub struct DefaultAllocator;
pub type Allocate<M> = <DefaultAllocator as Alloc<M>>::Buffer;
pub type AllocateBlade<T,N,G> = <T as AllocBlade<N,G>>::Buffer;
pub type AllocateEven<T,N> = <T as AllocEven<N>>::Buffer;
pub type AllocateOdd<T,N> = <T as AllocOdd<N>>::Buffer;
pub type AllocateMultivector<T,N> = <T as AllocMultivector<N>>::Buffer;
pub trait Alloc<M> {
type Scalar: Sized;
type Shape: Copy;
type Buffer: Storage<Self::Scalar, Uninit=Self::Uninit>;
type Uninit: UninitStorage<Self::Scalar, Init=Self::Buffer>;
fn shape(this: &M) -> Self::Shape;
fn uninit(shape: Self::Shape) -> Self::Uninit;
unsafe fn assume_init(uninit: Self::Uninit) -> M;
}
pub trait AllocBlade<N:Dim,G:Dim>: Sized {
type Buffer: BladeStorage<Self,N,G>;
}
pub trait AllocEven<N:Dim>: Sized {
type Buffer: EvenStorage<Self,N>;
}
pub trait AllocOdd<N:Dim>: Sized {
type Buffer: OddStorage<Self,N>;
}
pub trait AllocVersor<N:Dim>: AllocEven<N> + AllocOdd<N> {}
impl<T:AllocEven<N>+AllocOdd<N>, N:Dim> AllocVersor<N> for T {}
pub trait AllocMultivector<N:Dim>: Sized {
type Buffer: MultivectorStorage<Self,N>;
}
pub trait AllocSimpleBlade<N:Dim,G:Dim>: AllocBlade<N,G> {}
impl<T:AllocBlade<Dyn,Const<0>>> AllocSimpleBlade<Dyn,Const<0>> for T {}
impl<T:AllocBlade<Dyn,Const<1>>> AllocSimpleBlade<Dyn,Const<1>> for T {}
impl<T:AllocBlade<N,G>,N:Dim,G:Dim> AllocSimpleBlade<N,G> for T where
N: DimName+ToTypenum,
G: DimName+ToTypenum,
G::Typenum: Add<U1> + IsLessOrEqual<U1>,
N::Typenum: IsLessOrEqual<Sum<G::Typenum,U1>>,
LeEq<G::Typenum, U1>: BitOr<LeEq<N::Typenum, Sum<G::Typenum,U1>>, Output=True>
{}
impl<T, const N: usize> AllocBlade<Const<N>, Dyn> for T {
type Buffer = DynBladeStorage<T, Const<N>, Dyn>;
}
impl<T, const G: usize> AllocBlade<Dyn, Const<G>> for T {
type Buffer = DynBladeStorage<T, Dyn, Const<G>>;
}
impl<T> AllocBlade<Dyn, Dyn> for T {
type Buffer = DynBladeStorage<T, Dyn, Dyn>;
}
impl<T> AllocEven<Dyn> for T {
type Buffer = DynEvenStorage<T, Dyn>;
}
impl<T> AllocOdd<Dyn> for T {
type Buffer = DynOddStorage<T, Dyn>;
}
impl<T> AllocMultivector<Dyn> for T {
type Buffer = DynMultivectorStorage<T, Dyn>;
}
#[inline(always)]
fn uninit_array<T, const L: usize>() -> [MaybeUninit<T>; L] {
unsafe {
MaybeUninit::uninit().assume_init()
}
}
#[inline(always)]
fn array_from_iter<T, I: IntoIterator<Item=T>, const L: usize>(iter:I, kind:&str) -> [T;L] {
let mut uninit: [MaybeUninit<T>;L] = uninit_array();
let mut count = 0;
for (i, x) in (0..L).zip(iter) {
uninit[i] = MaybeUninit::new(x);
count = i+1;
}
if count!=L {
panic!("Not enough elements to fill {}", kind);
}
unsafe { <[MaybeUninit<T>;L] as UninitStorage<T>>::assume_init(uninit) }
}
macro_rules! impl_alloc{
($n:literal $($N:literal)*; $($G:literal)*; @$cmd:ident $($pairs:tt)*) => {
impl_alloc!($($N)*; $($G)*; @$cmd $($pairs)* $(($n, $G))*);
impl_alloc!($n @$cmd);
};
($N:literal @tests) => {
assert_eq!(
std::mem::size_of::<AllocateEven<f32, Const<$N>>>(),
std::mem::size_of::<f32>() * even_elements($N)
);
assert_eq!(
std::mem::size_of::<AllocateOdd<f32, Const<$N>>>(),
std::mem::size_of::<f32>() * odd_elements($N)
);
assert_eq!(
std::mem::size_of::<AllocateMultivector<f32, Const<$N>>>(),
std::mem::size_of::<f32>() * 2usize.pow($N)
);
};
($N:literal @impl) => {
impl<T> AllocEven<Const<$N>> for T {
type Buffer = [T; even_elements($N)];
}
unsafe impl<T> EvenStorage<T, Const<$N>> for [T; even_elements($N) ] {
fn dim(&self) -> Const<$N> { Const::<$N> }
fn uninit(_: Const<$N>,) -> Self::Uninit { uninit_array() }
fn from_iterator<I:IntoIterator<Item=T>>(_: Const<$N>, iter: I) -> Self {
array_from_iter(iter, "value")
}
}
impl<T> AllocOdd<Const<$N>> for T {
type Buffer = [T; odd_elements($N)];
}
unsafe impl<T> OddStorage<T, Const<$N>> for [T; odd_elements($N) ] {
fn dim(&self) -> Const<$N> { Const::<$N> }
fn uninit(_: Const<$N>,) -> Self::Uninit { uninit_array() }
fn from_iterator<I:IntoIterator<Item=T>>(_: Const<$N>, iter: I) -> Self {
array_from_iter(iter, "value")
}
}
impl<T> AllocMultivector<Const<$N>> for T {
type Buffer = [T; 2usize.pow($N)];
}
unsafe impl<T> MultivectorStorage<T, Const<$N>> for [T; 2usize.pow($N)] {
fn dim(&self) -> Const<$N> { Const::<$N> }
fn uninit(_: Const<$N>,) -> Self::Uninit { uninit_array() }
fn from_iterator<I:IntoIterator<Item=T>>(_: Const<$N>, iter: I) -> Self {
array_from_iter(iter, "multivector")
}
}
};
(; $($_G:literal)*; @impl $(($N:literal, $G:literal))*) => {
$(
impl<T> AllocBlade<Const<$N>, Const<$G>> for T {
type Buffer = [T; binom($N, $G)];
}
unsafe impl<T> BladeStorage<T, Const<$N>, Const<$G>> for [T; binom($N, $G)] {
fn dim(&self) -> Const<$N> { Const::<$N> }
fn grade(&self) -> Const<$G> { Const::<$G> }
fn uninit(_: Const<$N>, _: Const<$G>) -> Self::Uninit { uninit_array() }
fn from_iterator<I:IntoIterator<Item=T>>(_: Const<$N>, _: Const<$G>, iter: I) -> Self {
array_from_iter(iter, "blade")
}
}
)*
};
(; $($_G:literal)*; @tests $(($N:literal, $G:literal))*) => {
$(
assert_eq!(
std::mem::size_of::<AllocateBlade<f32, Const<$N>, Const<$G>>>(),
std::mem::size_of::<f32>() * binom($N, $G)
);
)*
};
}
impl_alloc!(
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16; 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16; @impl
);
#[test]
#[cfg(test)]
fn buffer_sizes() {
impl_alloc!(
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16; 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16; @tests
);
}