1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
//! build calculations in the type system, for better locality of operations
//!
//! instead of calculating the whole result for each step of the operation
//! calculate all steps of the operation for each element of the result.
//!
//! this might lead to less memory bandwidth used, as data gets worked on in one go.
//! might also lead to less cache locality tough, as elements from all inputs are used
//! instead of all elements from one (two).
//! cache locality will be slightly mitigated, as operations will (soon (TM)) run on multiple data
//! at once.

//todo: add V type that wraps a Vector and implements virtual add/mul/sub/div, just at type to get
//your calculation started

//todo: add transpose/matrix multiplication, potentially switch from basing this off off ConstIndex
//to ConstIter

use crate::consts::{ConstIndex, ConstIterator};
use core::ops::*;

pub struct VAdd<T, L, R, LT, RT, const N: usize>
where
	// use Borrow maybe?
	// hard to abstract over lifetimes + owned/borrowd
	L: ConstIndex<LT, N> + Copy + Clone,
	R: ConstIndex<RT, N> + Copy + Clone,
	LT: Add<RT, Output = T>,
{
	l: L,
	r: R,
	m: core::marker::PhantomData<(T, LT, RT)>,
}

impl<T, L, R, LT, RT, const N: usize> Copy for VAdd<T, L, R, LT, RT, N>
where
	L: ConstIndex<LT, N> + Copy + Clone,
	R: ConstIndex<RT, N> + Copy + Clone,
	LT: Add<RT, Output = T>,
{
}

impl<T, L, R, LT, RT, const N: usize> Clone for VAdd<T, L, R, LT, RT, N>
where
	L: ConstIndex<LT, N> + Copy + Clone,
	R: ConstIndex<RT, N> + Copy + Clone,
	LT: Add<RT, Output = T>,
{
	fn clone(&self) -> Self { *self }
}

// this is safe because the underlying ConstIndex implementations are guaranteed to be safe
unsafe impl<T, L, R, LT, RT, const N: usize> ConstIndex<T, N> for VAdd<T, L, R, LT, RT, N>
where
	L: ConstIndex<LT, N> + Copy + Clone,
	R: ConstIndex<RT, N> + Copy + Clone,
	LT: Add<RT, Output = T>,
{
	#[inline]
	fn i(self, index: usize) -> T {
		let l = self.l.i(index);
		let r = self.r.i(index);
		l + r
	}
}

// this restricts other to const-Index to the same type as self
//
// this is not a necessary restriction, but rust type system does not allow for expressing anything
// more generic due to "unconstrained type parameters"
//
// this might be possible once GAT lands, allowing for stuff like (X,Y) + (Z,) = (X, Y, Z) or
// the like. like for example T + &T which is kinda important...
impl<T, L, R, LT, RT, O, NT, const N: usize> Add<O> for VAdd<T, L, R, LT, RT, N>
where
	L: ConstIndex<LT, N> + Copy + Clone,
	R: ConstIndex<RT, N> + Copy + Clone,
	LT: Add<RT, Output = T>,

	O: ConstIndex<T, N> + Copy + Clone,
	T: Add<T, Output = NT>,
{
	type Output = VAdd<NT, Self, O, T, T, N>;
	fn add(self, other: O) -> Self::Output {
		VAdd {
			l: self,
			r: other,
			m: Default::default(),
		}
	}
}

/*
// can't even specialize for vector, cause "downstream crates may implement ConstIndex
// except im already implementing that in this crate...
use crate::Vector;
impl<'o, T, L, R, LT, RT, NT, const N: usize> Add<&'o Vector<T, N>> for VAdd<T, L, R, LT, RT, N>
where
	L: ConstIndex<LT, N> + Copy + Clone,
	R: ConstIndex<RT, N> + Copy + Clone,
	LT: Add<RT, Output = T>,

	T: Add<&'o T, Output = NT>,
{
	type Output = VAdd<NT, Self, &'o Vector<T, N>, T, T, N>;
	fn add(self, other: &'o Vector<T, N>) -> Self::Output {
		VAdd {
			l: self,
			r: other,
			m: Default::default(),
		}
	}
}
*/
//
impl<T, L, R, LT, RT, const N: usize> VAdd<T, L, R, LT, RT, N>
where
	L: ConstIndex<LT, N> + Copy + Clone,
	R: ConstIndex<RT, N> + Copy + Clone,
	LT: Add<RT, Output = T>,
{
	pub fn new(l: L, r: R) -> Self {
		Self {
			l,
			r,
			m: Default::default(),
		}
	}

	pub fn realize(self) -> crate::Vector<T, N> { ConstIterator::from(self).collect() }
}

#[cfg(test)]
pub(crate) const TESTLEN: usize = 777usize;

#[test]
fn calc_chain() {
	use crate::Vector;
	use rand::{thread_rng, Rng};
	let mut rng = thread_rng();
	let a: Vector<f32, TESTLEN> = rng.gen();
	let b: Vector<f32, TESTLEN> = rng.gen();
	let c: Vector<f32, TESTLEN> = rng.gen();
	let d: Vector<f32, TESTLEN> = rng.gen();
	let e: Vector<f32, TESTLEN> = rng.gen();

	let ab = VAdd::new(a, b);
	let abc = ab + c;
	let abcd = abc + d;
	let abcde = abcd + e;

	let _res = abcde.realize();
}