use crate::{ f16::F16, prim::{PrimSInt, PrimUInt}, traits::{Bool, Compare, Context, ConvertFrom, Float, Int, Make, SInt, Select, UInt}, }; use core::ops::{ Add, AddAssign, BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Div, DivAssign, Mul, MulAssign, Neg, Not, Rem, RemAssign, Shl, ShlAssign, Shr, ShrAssign, Sub, SubAssign, }; #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Default)] pub struct Scalar; #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Default)] #[repr(transparent)] pub struct Value(pub T); macro_rules! impl_convert_from { ($first:ident $(, $ty:ident)*) => { $( impl ConvertFrom> for Value<$ty> { fn cvt_from(v: Value<$first>) -> Self { Value(ConvertFrom::cvt_from(v.0)) } } impl ConvertFrom> for Value<$first> { fn cvt_from(v: Value<$ty>) -> Self { Value(ConvertFrom::cvt_from(v.0)) } } )* impl_convert_from![$($ty),*]; }; () => { }; } impl_convert_from![u8, i8, u16, i16, F16, u32, i32, u64, i64, f32, f64]; macro_rules! impl_bit_ops { ($ty:ident) => { impl BitAnd for Value<$ty> { type Output = Self; fn bitand(self, rhs: Self) -> Self { Value(self.0 & rhs.0) } } impl BitOr for Value<$ty> { type Output = Self; fn bitor(self, rhs: Self) -> Self { Value(self.0 | rhs.0) } } impl BitXor for Value<$ty> { type Output = Self; fn bitxor(self, rhs: Self) -> Self { Value(self.0 ^ rhs.0) } } impl Not for Value<$ty> { type Output = Self; fn not(self) -> Self { Value(!self.0) } } impl BitAndAssign for Value<$ty> { fn bitand_assign(&mut self, rhs: Self) { self.0 &= rhs.0; } } impl BitOrAssign for Value<$ty> { fn bitor_assign(&mut self, rhs: Self) { self.0 |= rhs.0; } } impl BitXorAssign for Value<$ty> { fn bitxor_assign(&mut self, rhs: Self) { self.0 ^= rhs.0; } } }; } macro_rules! impl_wrapping_int_ops { ($ty:ident) => { impl Add for Value<$ty> { type Output = Self; fn add(self, rhs: Self) -> Self { Value(self.0.wrapping_add(rhs.0)) } } impl Sub for Value<$ty> { type Output = Self; fn sub(self, rhs: Self) -> Self { Value(self.0.wrapping_sub(rhs.0)) } } impl Mul for Value<$ty> { type Output = Self; fn mul(self, rhs: Self) -> Self { Value(self.0.wrapping_mul(rhs.0)) } } impl Div for Value<$ty> { type Output = Self; fn div(self, rhs: Self) -> Self { Value(self.0.wrapping_div(rhs.0)) } } impl Rem for Value<$ty> { type Output = Self; fn rem(self, rhs: Self) -> Self { Value(self.0.wrapping_rem(rhs.0)) } } impl Shl for Value<$ty> { type Output = Self; fn shl(self, rhs: Self) -> Self { Value(self.0.wrapping_shl(rhs.0 as u32)) } } impl Shr for Value<$ty> { type Output = Self; fn shr(self, rhs: Self) -> Self { Value(self.0.wrapping_shr(rhs.0 as u32)) } } impl Neg for Value<$ty> { type Output = Self; fn neg(self) -> Self { Value(self.0.wrapping_neg()) } } impl AddAssign for Value<$ty> { fn add_assign(&mut self, rhs: Self) { *self = self.add(rhs); } } impl SubAssign for Value<$ty> { fn sub_assign(&mut self, rhs: Self) { *self = self.sub(rhs); } } impl MulAssign for Value<$ty> { fn mul_assign(&mut self, rhs: Self) { *self = self.mul(rhs); } } impl DivAssign for Value<$ty> { fn div_assign(&mut self, rhs: Self) { *self = self.div(rhs); } } impl RemAssign for Value<$ty> { fn rem_assign(&mut self, rhs: Self) { *self = self.rem(rhs); } } impl ShlAssign for Value<$ty> { fn shl_assign(&mut self, rhs: Self) { *self = self.shl(rhs); } } impl ShrAssign for Value<$ty> { fn shr_assign(&mut self, rhs: Self) { *self = self.shr(rhs); } } }; } macro_rules! impl_int { ($ty:ident) => { impl_bit_ops!($ty); impl_wrapping_int_ops!($ty); impl Int for Value<$ty> { fn leading_zeros(self) -> Self { Value(self.0.leading_zeros() as $ty) } fn leading_ones(self) -> Self { Value(self.0.leading_ones() as $ty) } fn trailing_zeros(self) -> Self { Value(self.0.trailing_zeros() as $ty) } fn trailing_ones(self) -> Self { Value(self.0.trailing_ones() as $ty) } fn count_zeros(self) -> Self { Value(self.0.count_zeros() as $ty) } fn count_ones(self) -> Self { Value(self.0.count_ones() as $ty) } } }; } macro_rules! impl_uint { ($($ty:ident),*) => { $( impl_int!($ty); impl UInt for Value<$ty> { type PrimUInt = $ty; type SignedType = Value<<$ty as PrimUInt>::SignedType>; } )* }; } impl_uint![u8, u16, u32, u64]; macro_rules! impl_sint { ($($ty:ident),*) => { $( impl_int!($ty); impl SInt for Value<$ty> { type PrimSInt = $ty; type UnsignedType = Value<<$ty as PrimSInt>::UnsignedType>; } )* }; } impl_sint![i8, i16, i32, i64]; macro_rules! impl_float_ops { ($ty:ident) => { impl Add for Value<$ty> { type Output = Self; fn add(self, rhs: Self) -> Self { Value(self.0.add(rhs.0)) } } impl Sub for Value<$ty> { type Output = Self; fn sub(self, rhs: Self) -> Self { Value(self.0.sub(rhs.0)) } } impl Mul for Value<$ty> { type Output = Self; fn mul(self, rhs: Self) -> Self { Value(self.0.mul(rhs.0)) } } impl Div for Value<$ty> { type Output = Self; fn div(self, rhs: Self) -> Self { Value(self.0.div(rhs.0)) } } impl Rem for Value<$ty> { type Output = Self; fn rem(self, rhs: Self) -> Self { Value(self.0.rem(rhs.0)) } } impl Neg for Value<$ty> { type Output = Self; fn neg(self) -> Self { Value(self.0.neg()) } } impl AddAssign for Value<$ty> { fn add_assign(&mut self, rhs: Self) { *self = self.add(rhs); } } impl SubAssign for Value<$ty> { fn sub_assign(&mut self, rhs: Self) { *self = self.sub(rhs); } } impl MulAssign for Value<$ty> { fn mul_assign(&mut self, rhs: Self) { *self = self.mul(rhs); } } impl DivAssign for Value<$ty> { fn div_assign(&mut self, rhs: Self) { *self = self.div(rhs); } } impl RemAssign for Value<$ty> { fn rem_assign(&mut self, rhs: Self) { *self = self.rem(rhs); } } }; } impl_float_ops!(F16); macro_rules! impl_float { ($ty:ident, $bits:ty, $signed_bits:ty) => { impl_float_ops!($ty); impl Float for Value<$ty> { type PrimFloat = $ty; type BitsType = Value<$bits>; type SignedBitsType = Value<$signed_bits>; fn abs(self) -> Self { #[cfg(feature = "std")] return Value(self.0.abs()); #[cfg(not(feature = "std"))] return crate::algorithms::base::abs(Scalar, self); } fn copy_sign(self, sign: Self) -> Self { #[cfg(feature = "std")] return Value(self.0.copysign(sign.0)); #[cfg(not(feature = "std"))] return crate::algorithms::base::copy_sign(Scalar, self, sign); } fn trunc(self) -> Self { #[cfg(feature = "std")] return Value(self.0.trunc()); #[cfg(not(feature = "std"))] return crate::algorithms::base::trunc(Scalar, self); } fn ceil(self) -> Self { #[cfg(feature = "std")] return Value(self.0.ceil()); #[cfg(not(feature = "std"))] todo!(); } fn floor(self) -> Self { #[cfg(feature = "std")] return Value(self.0.floor()); #[cfg(not(feature = "std"))] todo!(); } fn round(self) -> Self { #[cfg(feature = "std")] return Value(self.0.round()); #[cfg(not(feature = "std"))] todo!(); } #[cfg(feature = "fma")] fn fma(self, a: Self, b: Self) -> Self { Value(self.0.mul_add(a.0, b.0)) } fn is_nan(self) -> Self::Bool { Value(self.0.is_nan()) } fn is_infinite(self) -> Self::Bool { Value(self.0.is_infinite()) } fn is_finite(self) -> Self::Bool { Value(self.0.is_finite()) } fn from_bits(v: Self::BitsType) -> Self { Value(<$ty>::from_bits(v.0)) } fn to_bits(self) -> Self::BitsType { Value(self.0.to_bits()) } } }; } impl_float!(f32, u32, i32); impl_float!(f64, u64, i64); macro_rules! impl_compare_using_partial_cmp { ($($ty:ty),*) => { $( impl Compare for Value<$ty> { type Bool = Value; fn eq(self, rhs: Self) -> Self::Bool { Value(self == rhs) } fn ne(self, rhs: Self) -> Self::Bool { Value(self != rhs) } fn lt(self, rhs: Self) -> Self::Bool { Value(self < rhs) } fn gt(self, rhs: Self) -> Self::Bool { Value(self > rhs) } fn le(self, rhs: Self) -> Self::Bool { Value(self <= rhs) } fn ge(self, rhs: Self) -> Self::Bool { Value(self >= rhs) } } )* }; } impl_compare_using_partial_cmp![bool, u8, i8, u16, i16, F16, u32, i32, f32, u64, i64, f64]; impl Bool for Value {} impl_bit_ops!(bool); impl Select> for Value { fn select(self, true_v: Value, false_v: Value) -> Value { if self.0 { true_v } else { false_v } } } macro_rules! impl_from { ($src:ident => [$($dest:ident),*]) => { $( impl From> for Value<$dest> { fn from(v: Value<$src>) -> Self { Value(v.0.into()) } } )* }; } impl_from!(u8 => [u16, i16, F16, u32, i32, f32, u64, i64, f64]); impl_from!(u16 => [u32, i32, f32, u64, i64, f64]); impl_from!(u32 => [u64, i64, f64]); impl_from!(i8 => [i16, F16, i32, f32, i64, f64]); impl_from!(i16 => [i32, f32, i64, f64]); impl_from!(i32 => [i64, f64]); impl_from!(F16 => [f32, f64]); impl_from!(f32 => [f64]); macro_rules! impl_context { ( impl Context for Scalar { $(type $name:ident = Value<$ty:ident>;)* #[vec] $(type $vec_name:ident = Value<$vec_ty:ident>;)* } ) => { impl Context for Scalar { $(type $name = Value<$ty>;)* $(type $vec_name = Value<$vec_ty>;)* } $( impl Make for Value<$ty> { type Prim = $ty; type Context = Scalar; fn ctx(self) -> Self::Context { Scalar } fn make(_ctx: Self::Context, v: Self::Prim) -> Self { Value(v) } } )* }; } impl_context! { impl Context for Scalar { type Bool = Value; type U8 = Value; type I8 = Value; type U16 = Value; type I16 = Value; type F16 = Value; type U32 = Value; type I32 = Value; type F32 = Value; type U64 = Value; type I64 = Value; type F64 = Value; #[vec] type VecBool8 = Value; type VecU8 = Value; type VecI8 = Value; type VecBool16 = Value; type VecU16 = Value; type VecI16 = Value; type VecF16 = Value; type VecBool32 = Value; type VecU32 = Value; type VecI32 = Value; type VecF32 = Value; type VecBool64 = Value; type VecU64 = Value; type VecI64 = Value; type VecF64 = Value; } }