use std::ops::AddAssign;
use std::ops::SubAssign;
use std::ops::MulAssign;
use std::ops::DivAssign;
use std::ops::RemAssign;
use std::ops::BitAndAssign;
use std::ops::BitOrAssign;
use std::ops::BitXorAssign;
use std::ops::Shr;
use std::ops::ShrAssign;
use std::ops::Shl;
use std::ops::ShlAssign;
use std::ops::Index;
use std::ops::IndexMut;
use std::ops::Deref;
use std::ops::DerefMut;
use std::ops::{Add, Sub, Mul, Div, Rem, BitOr, BitXor, BitAnd, Not, Neg};
use std::slice::SliceIndex;
use crate::NumericTrait;
use crate::SerialNumericTrait;
use super::LossyFrom;
pub const VECTOR_SIZE: usize = 8;
#[derive(Default, Debug, Copy, Clone, PartialOrd, PartialEq, Hash)]
pub struct NumericVector<T, const SEQ: bool>([T; VECTOR_SIZE]);
impl<T: Copy, const SEQ: bool> From<T> for NumericVector<T, SEQ> {
fn from(value: T) -> Self {
Self([value; VECTOR_SIZE])
}
}
impl<T: Copy, const SEQ: bool> NumericVector<T, SEQ> {
pub fn get(self, index: usize) -> T {
unsafe { std::hint::assert_unchecked(index < VECTOR_SIZE) }
self.0[index]
}
pub fn set(self, value: T, index: usize) -> Self {
unsafe { std::hint::assert_unchecked(index < VECTOR_SIZE) }
let mut s = self;
s.0[index] = value;
s
}
}
macro_rules! basic_ops {
($(impl $trait:ident $call:ident $assign_trait:ident $call_assign:ident)*) => {
$(
impl<T: $trait<Output = T> + Copy, const SEQ: bool> $trait for NumericVector<T, SEQ> {
type Output = NumericVector<T, SEQ>;
fn $call(self, rhs: Self) -> Self {
Self(core::array::from_fn(|i| self.0[i].$call(rhs.0[i])))
}
}
impl<T: $assign_trait + Copy, const SEQ: bool> $assign_trait for NumericVector<T, SEQ> {
fn $call_assign(&mut self, rhs: Self) {
for i in 0..VECTOR_SIZE {
self.0[i].$call_assign(rhs.0[i]);
}
}
}
)*
};
}
basic_ops! {
impl Add add AddAssign add_assign
impl Sub sub SubAssign sub_assign
impl Mul mul MulAssign mul_assign
impl Div div DivAssign div_assign
impl Rem rem RemAssign rem_assign
impl BitOr bitor BitOrAssign bitor_assign
impl BitAnd bitand BitAndAssign bitand_assign
impl BitXor bitxor BitXorAssign bitxor_assign
impl Shl shl ShlAssign shl_assign
impl Shr shr ShrAssign shr_assign
}
impl<T: Not<Output = T> + Copy, const SEQ: bool> Not for NumericVector<T, SEQ> {
type Output = NumericVector<T, SEQ>;
fn not(self) -> Self::Output {
Self(core::array::from_fn(|i| self.0[i].not()))
}
}
impl<T: Neg<Output = T> + Copy, const SEQ: bool> Neg for NumericVector<T, SEQ> {
type Output = NumericVector<T, SEQ>;
fn neg(self) -> Self::Output {
Self(core::array::from_fn(|i| self.0[i].neg()))
}
}
impl<T, const SEQ: bool> AsMut<[T]> for NumericVector<T, SEQ> {
fn as_mut(&mut self) -> &mut [T] {
&mut self.0[..]
}
}
impl<T, const SEQ: bool> AsRef<[T]> for NumericVector<T, SEQ> {
fn as_ref(&self) -> &[T] {
&self.0[..]
}
}
impl<T, const SEQ: bool> Deref for NumericVector<T, SEQ> {
type Target = [T];
fn deref(&self) -> &[T] {
&self.0[..]
}
}
impl<T, const SEQ: bool> DerefMut for NumericVector<T, SEQ> {
fn deref_mut(&mut self) -> &mut [T] {
&mut self.0[..]
}
}
impl<T, I: SliceIndex<[T]>, const SEQ: bool> Index<I> for NumericVector<T, SEQ> {
type Output = I::Output;
fn index(&self, index: I) -> &Self::Output {
Index::index(&self.0, index)
}
}
impl<T, I: SliceIndex<[T]>, const SEQ: bool> IndexMut<I> for NumericVector<T, SEQ> {
fn index_mut(&mut self, index: I) -> &mut I::Output {
IndexMut::index_mut(&mut self.0, index)
}
}
pub type FloatVector = NumericVector<f32, false>;
pub type IntegerVector = NumericVector<i32, false>;
pub type ContigousIntegerVector = NumericVector<i32, true>;
#[macro_export]
macro_rules! impl_vectorizable_trait {
($x:ty, $y:ty) => {
impl VectorizableTrait<$y> for $x {
fn into_vector(self) -> $y { <$y>::from(self as i32) }
fn from_vector(v: &$y, index: usize) -> Self { v.get(index) as Self }
}
};
}
impl_vectorizable_trait!(u8, IntegerVector);
impl_vectorizable_trait!(u16, IntegerVector);
impl_vectorizable_trait!(u32, IntegerVector);
impl_vectorizable_trait!(u64, IntegerVector);
impl_vectorizable_trait!(i8, IntegerVector);
impl_vectorizable_trait!(i16, IntegerVector);
impl_vectorizable_trait!(i32, IntegerVector);
impl_vectorizable_trait!(i64, IntegerVector);
impl VectorizableTrait<FloatVector> for f32 {
fn into_vector(self) -> FloatVector { FloatVector::from(self) }
fn from_vector(v: &FloatVector, index: usize) -> Self { v.get(index) }
}
pub trait VectorizableTrait<T> {
fn into_vector(self) -> T;
fn from_vector(v: &T, index: usize) -> Self;
}
pub trait ParameterSerialTrait
where
Self: SerialNumericTrait + LossyFrom<u16> + PartialEq
{
}
impl ParameterSerialTrait for u8 {}
impl ParameterSerialTrait for u16 {}
impl ParameterSerialTrait for u32 {}
impl ParameterSerialTrait for u64 {}
impl ParameterSerialTrait for i8 {}
impl ParameterSerialTrait for i16 {}
impl ParameterSerialTrait for i32 {}
impl ParameterSerialTrait for i64 {}
impl ParameterSerialTrait for f32 {}
impl ParameterSerialTrait for f64 {}
pub trait ParameterVectorTrait
where
Self: Sized + NumericTrait + From<Self::SerialType>,
Self::SerialType: ParameterSerialTrait,
{
type SerialType = i32;
#[inline]
fn compose<F: FnMut(usize) -> Self::SerialType>(mut self, mut f: F) -> Self {
for index in 0..VECTOR_SIZE {
self = self.insert(f(index), index);
}
self
}
#[inline]
fn compose_with<F: FnMut(Self::SerialType) -> Self::SerialType>(mut self, mut f: F) -> Self {
for index in 0..VECTOR_SIZE {
self = self.insert(f(self.extract(index)), index);
}
self
}
#[inline]
fn compose_map<T, F>(self, mut f: F) -> T
where
F: FnMut(Self::SerialType) -> T::SerialType,
T: ParameterVectorTrait + Default
{
let mut v = T::default();
for index in 0..VECTOR_SIZE {
v = v.insert(f(self.extract(index)), index);
}
v
}
#[inline]
fn decompose<F: FnMut(usize)>(self, mut f: F) {
for index in 0..VECTOR_SIZE {
f(index);
}
}
#[inline]
fn decompose_with<F: FnMut(Self::SerialType)>(self, mut f: F) {
for index in 0..VECTOR_SIZE {
f(self.extract(index));
}
}
fn extract(self, index: usize) -> Self::SerialType;
fn insert(self, value: Self::SerialType, index: usize) -> Self;
fn seq(v: Self::SerialType) -> Self::SerialType { v }
}
impl ParameterVectorTrait for IntegerVector where Self: NumericTrait {
type SerialType = i32;
#[inline]
fn extract(self, index: usize) -> i32 { self.get(index) }
#[inline]
fn insert(self, value: i32, index: usize) -> Self { self.set(value, index) }
#[inline]
fn seq(v: Self::SerialType) -> Self::SerialType {
v + 1
}
}
impl ParameterVectorTrait for ContigousIntegerVector where Self: NumericTrait {
type SerialType = i32;
#[inline]
fn compose<F: FnMut(usize) -> Self::SerialType>(self, _: F) -> Self {
unsafe { std::hint::unreachable_unchecked() }
}
#[inline]
fn compose_with<F: FnMut(Self::SerialType) -> Self::SerialType>(self, _: F) -> Self {
unsafe { std::hint::unreachable_unchecked() }
}
#[inline]
fn compose_map<T, F>(self, _: F) -> T
where
F: FnMut(Self::SerialType) -> T::SerialType,
T: ParameterVectorTrait
{
unsafe { std::hint::unreachable_unchecked() }
}
#[inline]
fn extract(self, index: usize) -> i32 {
let base = self[0] + index as i32;
unsafe { std::hint::assert_unchecked(self[index] == base); }
base
}
#[inline]
fn insert(self, value: i32, index: usize) -> Self { self.set(value, index) }
#[inline]
fn seq(v: Self::SerialType) -> Self::SerialType {
v + 1
}
}
impl ParameterVectorTrait for FloatVector where Self: NumericTrait {
type SerialType = f32;
#[inline]
fn extract(self, index: usize) -> f32 { self[index] }
#[inline]
fn insert(self, value: f32, index: usize) -> Self { self.set(value, index) }
}
impl<T: ParameterSerialTrait + From<u16> + Into<i32> + Default + Index<usize>> ParameterVectorTrait for T where Self: NumericTrait {
type SerialType = T;
#[inline]
fn extract(self, _: usize) -> T { self }
#[inline]
fn insert(self, value: T, _: usize) -> Self { value }
}
pub trait ResultVectorTrait
where
Self: ParameterVectorTrait
+ Not<Output = Self>
+ BitOr<Output = Self>
+ BitAnd<Output = Self>
{
fn to_mask_vector(self) -> Self;
fn from_bool(cond: bool) -> Self;
fn from_bool_to_serial(cond: bool) -> Self::SerialType;
}
impl ResultVectorTrait for NumericVector<i32, false> {
fn to_mask_vector(self) -> Self { self }
fn from_bool(cond: bool) -> Self { Self::from(cond as i32) }
fn from_bool_to_serial(cond: bool) -> Self::SerialType {
Self::SerialType::from(cond as i32)
}
}
pub trait ComposeTupleUnpackerTrait<T, U> {
fn lambda<F: Fn(T) -> U>(&self, _: F, _: usize) -> U;
}
macro_rules! impl_compose_tuple_extract {
($s:tt, $index:ident $($element:ident)*) => {
{
let ($($element,)*) = $s;
($($element.extract($index),)*)
}
};
}
macro_rules! impl_compose_tuple_unpacker {
() => {};
($head:ident $($tail:ident)*) => {
impl<O: ParameterSerialTrait, $head: ParameterVectorTrait + Copy, $($tail: ParameterVectorTrait + Copy),*> ComposeTupleUnpackerTrait<($head::SerialType, $($tail::SerialType),*), O> for ($head, $($tail),*) {
fn lambda<F: Fn(($head::SerialType, $($tail::SerialType),*)) -> O>(&self, f: F, index: usize) -> O {
f(impl_compose_tuple_extract!(self, index $head $($tail)*))
}
}
impl_compose_tuple_unpacker!($($tail)*);
};
}
impl_compose_tuple_unpacker!(A B C D E);
pub trait ComposeTupleParameterTrait {}
macro_rules! impl_compose_tuple_generic {
() => {};
($head:ident $($tail:ident)*) => {
impl<$head, $($tail),*> ComposeTupleParameterTrait for ($head, $($tail),*) {}
impl_compose_tuple_generic!($($tail)*);
};
}
impl_compose_tuple_generic!(A B C D E);
#[inline]
pub fn compose_vector<O: ResultVectorTrait + Default, A: ComposeTupleUnpackerTrait<U, O::SerialType>, U: ComposeTupleParameterTrait, F: Fn(U) -> O::SerialType + Copy>(tags: A, lambda: F) -> O {
O::default().compose(|index| tags.lambda(lambda, index))
}