pub unsafe trait ScalarBackend<const N: usize, A: Alignment>where
Length<N>: SupportedLength,{
type VectorRepr: Copy;
Show 14 methods
// Provided methods
fn vec_eq(vec: &Vector<N, Self, A>, other: &Vector<N, Self, A>) -> bool
where Self: Scalar + PartialEq { ... }
fn vec_ne(vec: &Vector<N, Self, A>, other: &Vector<N, Self, A>) -> bool
where Self: Scalar + PartialEq { ... }
fn vec_neg(vec: Vector<N, Self, A>) -> Vector<N, Self, A>
where Self: Scalar + Neg<Output = Self> { ... }
fn vec_not(vec: Vector<N, Self, A>) -> Vector<N, Self, A>
where Self: Scalar + Not<Output = Self> { ... }
fn vec_add(
vec: Vector<N, Self, A>,
rhs: Vector<N, Self, A>,
) -> Vector<N, Self, A>
where Self: Scalar + Add<Output = Self> { ... }
fn vec_sub(
vec: Vector<N, Self, A>,
rhs: Vector<N, Self, A>,
) -> Vector<N, Self, A>
where Self: Scalar + Sub<Output = Self> { ... }
fn vec_mul(
vec: Vector<N, Self, A>,
rhs: Vector<N, Self, A>,
) -> Vector<N, Self, A>
where Self: Scalar + Mul<Output = Self> { ... }
fn vec_div(
vec: Vector<N, Self, A>,
rhs: Vector<N, Self, A>,
) -> Vector<N, Self, A>
where Self: Scalar + Div<Output = Self> { ... }
fn vec_rem(
vec: Vector<N, Self, A>,
rhs: Vector<N, Self, A>,
) -> Vector<N, Self, A>
where Self: Scalar + Rem<Output = Self> { ... }
fn vec_shl(
vec: Vector<N, Self, A>,
rhs: Vector<N, Self, A>,
) -> Vector<N, Self, A>
where Self: Scalar + Shl<Output = Self> { ... }
fn vec_shr(
vec: Vector<N, Self, A>,
rhs: Vector<N, Self, A>,
) -> Vector<N, Self, A>
where Self: Scalar + Shr<Output = Self> { ... }
fn vec_bitand(
vec: Vector<N, Self, A>,
rhs: Vector<N, Self, A>,
) -> Vector<N, Self, A>
where Self: Scalar + BitAnd<Output = Self> { ... }
fn vec_bitor(
vec: Vector<N, Self, A>,
rhs: Vector<N, Self, A>,
) -> Vector<N, Self, A>
where Self: Scalar + BitOr<Output = Self> { ... }
fn vec_bitxor(
vec: Vector<N, Self, A>,
rhs: Vector<N, Self, A>,
) -> Vector<N, Self, A>
where Self: Scalar + BitXor<Output = Self> { ... }
}Expand description
A trait to control the implementation of math types.
More specifically, this trait controls the internal representation and
function implementations of math types with N as their length, Self as
their scalar type, and A as their alignment.
This trait is generic over N and A (length and alignment). This means
that it can be implemented either seperately for each length and alignment,
or using one implementation that is generic over length and alignment.
The ScalarDefault trait offers a default implementation for
ScalarBackend that is useful when SIMD optimizations are unneeded or
impossible.
§Safety
The ScalarBackend::VectorRepr type must respect the memory-layout
requirements of Vector<N, Self, A>.
§SIMD
SIMD optimizations can be made the hard way or the easy way.
The hard way is using intrinsics. For each target architecture you want to support you’d need to:
- Implement
ScalarBackend<2, Aligned>using intrinsics. - Implement
ScalarBackend<3, Aligned>using intrinsics. - Implement
ScalarBackend<4, Aligned>using intrinsics. - Write an empty implementation for
ScalarBackend<..., Unaligned>.
The easy way is using existing math types.
For example, if your scalar type is a wrapper around f32, you could use
Vector<N, f32, A> as the internal representation for
Vector<N, { your scalar }, A>, then convert between the two in
function implementations.
§Example
Lets define a custom scalar type that is a wrapper around f32:
use ggmath::Scalar;
#[repr(transparent)]
#[derive(Clone, Copy)]
struct Foo(f32);
impl Scalar for Foo {}
// This needs to be replaced with a manual implementation.
impl ggmath::ScalarDefault for Foo {}We got a compile error because ScalarBackend isn’t implemented. Lets
implement it using Vector<N, f32, A> as our VectorRepr:
use ggmath::{Alignment, Length, ScalarBackend, SupportedLength, Vector};
// SAFETY: Because `Foo` is a wrapper around `f32`, any internal
// representation that `Vector<N, f32, A>` may use is also a valid
// representation for `Vector<N, Foo, A>`.
unsafe impl<const N: usize, A: Alignment> ScalarBackend<N, A> for Foo
where
Length<N>: SupportedLength,
{
type VectorRepr = Vector<N, f32, A>;
}Now whenever f32 vectors have SIMD alignment, our vectors have the same
alignment too.
Lets implement addition for Foo by adding up the internal f32s:
use core::ops::Add;
impl Add for Foo {
type Output = Self;
#[inline]
fn add(self, rhs: Self) -> Self::Output {
Self(self.0 + rhs.0)
}
}An implementation of vector addition that is consistant with Foo addition
should add up the internal f32 vectors just like Foo addition adds up
the internal f32s.
To implement optimized vector addition we need functions for converting
between Foo vectors and f32 vectors. The builtin functions for
conversions are Vector::repr and Vector::from_repr. The latter is an
unsafe function because the internal representation of a vector might have
less memory safety guarantees than the outer vector.
Lets make an extension method for f32 vectors that converts them to Foo
vectors:
trait ToFoo {
type Output;
fn to_foo(self) -> Self::Output;
}
impl<const N: usize, A: Alignment> ToFoo for Vector<N, f32, A>
where
Length<N>: SupportedLength,
{
type Output = Vector<N, Foo, A>;
#[inline]
fn to_foo(self) -> Self::Output {
// SAFETY: Any value of `f32` is a valid value of `Foo`, so any
// value of an `f32` vector is a valid value of a `Foo` vector.
unsafe { Vector::from_repr(self) }
}
}Now that everything is ready lets implement ScalarBackend::vec_add which
controls the implementation for vector addition:
// SAFETY: Because `Foo` is a wrapper around `f32`, any internal
// representation that `Vector<N, f32, A>` may use is also a valid
// representation for `Vector<N, Foo, A>`.
unsafe impl<const N: usize, A: Alignment> ScalarBackend<N, A> for Foo
where
Length<N>: SupportedLength,
{
type VectorRepr = Vector<N, f32, A>;
#[inline]
fn vec_add(vec: Vector<N, Self, A>, rhs: Vector<N, Self, A>) -> Vector<N, Self, A> {
(vec.repr() + rhs.repr()).to_foo()
}
}Now Foo vector addition has whatever SIMD optimizations f32 vectors
have. This pattern can be expanded for all operators and for any
extension-trait Foo vectors implement.
Required Associated Types§
Sourcetype VectorRepr: Copy
type VectorRepr: Copy
The internal representation of Vector<N, Self, A>.
This type must respect the memory layout requirements of
Vector<N, Self, A>.
Provided Methods§
Sourcefn vec_eq(vec: &Vector<N, Self, A>, other: &Vector<N, Self, A>) -> bool
fn vec_eq(vec: &Vector<N, Self, A>, other: &Vector<N, Self, A>) -> bool
Overridable implementation of the == operator for vectors.
Sourcefn vec_ne(vec: &Vector<N, Self, A>, other: &Vector<N, Self, A>) -> bool
fn vec_ne(vec: &Vector<N, Self, A>, other: &Vector<N, Self, A>) -> bool
Overridable implementation of the != operator for vectors.
Sourcefn vec_neg(vec: Vector<N, Self, A>) -> Vector<N, Self, A>
fn vec_neg(vec: Vector<N, Self, A>) -> Vector<N, Self, A>
Overridable implementation of the - operator for vectors.
Sourcefn vec_not(vec: Vector<N, Self, A>) -> Vector<N, Self, A>
fn vec_not(vec: Vector<N, Self, A>) -> Vector<N, Self, A>
Overridable implementation of the ! operator for vectors.
Sourcefn vec_add(
vec: Vector<N, Self, A>,
rhs: Vector<N, Self, A>,
) -> Vector<N, Self, A>
fn vec_add( vec: Vector<N, Self, A>, rhs: Vector<N, Self, A>, ) -> Vector<N, Self, A>
Overridable implementation of the + operator for vectors.
Sourcefn vec_sub(
vec: Vector<N, Self, A>,
rhs: Vector<N, Self, A>,
) -> Vector<N, Self, A>
fn vec_sub( vec: Vector<N, Self, A>, rhs: Vector<N, Self, A>, ) -> Vector<N, Self, A>
Overridable implementation of the - operator for vectors.
Sourcefn vec_mul(
vec: Vector<N, Self, A>,
rhs: Vector<N, Self, A>,
) -> Vector<N, Self, A>
fn vec_mul( vec: Vector<N, Self, A>, rhs: Vector<N, Self, A>, ) -> Vector<N, Self, A>
Overridable implementation of the * operator for vectors.
Sourcefn vec_div(
vec: Vector<N, Self, A>,
rhs: Vector<N, Self, A>,
) -> Vector<N, Self, A>
fn vec_div( vec: Vector<N, Self, A>, rhs: Vector<N, Self, A>, ) -> Vector<N, Self, A>
Overridable implementation of the / operator for vectors.
Sourcefn vec_rem(
vec: Vector<N, Self, A>,
rhs: Vector<N, Self, A>,
) -> Vector<N, Self, A>
fn vec_rem( vec: Vector<N, Self, A>, rhs: Vector<N, Self, A>, ) -> Vector<N, Self, A>
Overridable implementation of the % operator for vectors.
Sourcefn vec_shl(
vec: Vector<N, Self, A>,
rhs: Vector<N, Self, A>,
) -> Vector<N, Self, A>
fn vec_shl( vec: Vector<N, Self, A>, rhs: Vector<N, Self, A>, ) -> Vector<N, Self, A>
Overridable implementation of the << operator for vectors.
Sourcefn vec_shr(
vec: Vector<N, Self, A>,
rhs: Vector<N, Self, A>,
) -> Vector<N, Self, A>
fn vec_shr( vec: Vector<N, Self, A>, rhs: Vector<N, Self, A>, ) -> Vector<N, Self, A>
Overridable implementation of the >> operator for vectors.
Sourcefn vec_bitand(
vec: Vector<N, Self, A>,
rhs: Vector<N, Self, A>,
) -> Vector<N, Self, A>
fn vec_bitand( vec: Vector<N, Self, A>, rhs: Vector<N, Self, A>, ) -> Vector<N, Self, A>
Overridable implementation of the & operator for vectors.