Stack allocated vectors. A wrapper type machinery allows for vector arithmetic with operator chaining. The goal is ideal code generation: Better loop unrolling and dispense of bounds checks due to known length at compile time, no heap allocations and thus no cache fragmentation. The wrapper type functions should be chained at compile time by inlining.
use std::ops::{Add, Sub, Mul};
pub struct Vector<const N: usize>(pub [i32; N]);
pub struct Addition<A: Get, B: Get>(A, B);
pub struct ScalarMul<A: Get>(i32, A);
impl<const N: usize> Vector<N> {
pub fn set<A: Get>(&mut self, a: A) {
for (i, v) in self.0.iter_mut().enumerate() {
*v = a.get(i);
}
}
}
impl<const N: usize> std::fmt::Display for Vector<N> {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{:?}", self.0)
}
}
pub trait Get {
fn len(&self) -> usize;
fn get(&self, i: usize) -> i32;
}
impl<const N: usize> Get for &Vector<N> {
fn len(&self) -> usize {self.0.len()}
fn get(&self, i: usize) -> i32 {self.0[i]}
}
impl<A: Get, B: Get> Get for Addition<A, B> {
fn len(&self) -> usize {self.0.len()}
fn get(&self, i: usize) -> i32 {
self.0.get(i) + self.1.get(i)
}
}
impl<A: Get> Get for ScalarMul<A> {
fn len(&self) -> usize {self.1.len()}
fn get(&self, i: usize) -> i32 {
self.0*self.1.get(i)
}
}
impl<'a, B: Get, const N: usize> Add<B> for &'a Vector<N> {
type Output = Addition<&'a Vector<N>, B>;
fn add(self, b: B) -> Self::Output {
Addition(self, b)
}
}
impl<'a, B: Get, const N: usize> Sub<B> for &'a Vector<N> {
type Output = Addition<&'a Vector<N>, ScalarMul<B>>;
fn sub(self, b: B) -> Self::Output {
Addition(self, ScalarMul(-1, b))
}
}
impl<A0: Get, A1: Get, B: Get> Add<B> for Addition<A0, A1> {
type Output = Addition<Self, B>;
fn add(self, b: B) -> Self::Output {
Addition(self, b)
}
}
impl<A0: Get, A1: Get, B: Get> Sub<B> for Addition<A0, A1> {
type Output = Addition<Self, ScalarMul<B>>;
fn sub(self, b: B) -> Self::Output {
Addition(self, ScalarMul(-1, b))
}
}
impl<A: Get, B: Get> Add<B> for ScalarMul<A> {
type Output = Addition<Self, B>;
fn add(self, b: B) -> Self::Output {
Addition(self, b)
}
}
impl<A: Get, B: Get> Sub<B> for ScalarMul<A> {
type Output = Addition<Self, ScalarMul<B>>;
fn sub(self, b: B) -> Self::Output {
Addition(self, ScalarMul(-1, b))
}
}
impl<'a, const N: usize> Mul<&'a Vector<N>> for i32 {
type Output = ScalarMul<&'a Vector<N>>;
fn mul(self, a: &'a Vector<N>) -> Self::Output {
ScalarMul(self, a)
}
}
impl<A: Get, B: Get> Mul<Addition<A, B>> for i32 {
type Output = ScalarMul<Addition<A, B>>;
fn mul(self, a: Addition<A, B>) -> Self::Output {
ScalarMul(self, a)
}
}
impl<B: Get, const N: usize> Mul<B> for &Vector<N> {
type Output = i32;
fn mul(self, b: B) -> i32 {
let a = &self.0;
let mut acc = 0;
for (i, ai) in a.iter().enumerate() {
acc += ai*b.get(i);
}
acc
}
}
impl<A0: Get, A1: Get, B: Get> Mul<B> for Addition<A0, A1> {
type Output = i32;
fn mul(self, b: B) -> i32 {
let mut acc = 0;
for i in 0..self.len() {
acc += self.get(i)*b.get(i);
}
acc
}
}
fn main() {
let v = &Vector([1, 2]);
let w = &Vector([3, 4]);
let mut buf = Vector([0, 0]);
buf.set(2*v + 4*w + 5*(v - 2*w));
println!("{}", buf);
println!("{}", (v + w)*(v - w));
println!("{}", v*v - w*w);
}