Fix matrix naming stuff so it's not so confusing no more

This commit is contained in:
rexy712 2020-08-16 08:20:32 -07:00
parent 932335bdc5
commit c7d5978d6d
2 changed files with 132 additions and 133 deletions

View File

@ -26,11 +26,11 @@
namespace math{ namespace math{
template<typename T, size_t W, size_t H> template<typename T, size_t R, size_t C>
class matrix_base class matrix_base
{ {
static_assert(W > 0, "Cannot have 0 columns matrix"); static_assert(C > 0, "Cannot have 0 columns matrix");
static_assert(H > 0, "Cannot have 0 rows matrix"); static_assert(R > 0, "Cannot have 0 rows matrix");
public: public:
using value_type = T; using value_type = T;
using size_type = size_t; using size_type = size_t;
@ -39,11 +39,11 @@ namespace math{
using reference = value_type&; using reference = value_type&;
using const_reference = const value_type&; using const_reference = const value_type&;
static constexpr size_type Columns = W; static constexpr size_type Columns = C;
static constexpr size_type Rows = H; static constexpr size_type Rows = R;
protected: protected:
value_type m_data[W*H]; value_type m_data[R*C];
protected: protected:
template<size_t... Ss> template<size_t... Ss>
@ -92,11 +92,11 @@ namespace math{
}; };
template<typename T, size_t W, size_t H> template<typename T, size_t R, size_t C>
class matrix : public matrix_base<T,W,H> class matrix : public matrix_base<T,R,C>
{ {
private: private:
using base = matrix_base<T,W,H>; using base = matrix_base<T,R,C>;
public: public:
using value_type = typename base::value_type; using value_type = typename base::value_type;
using size_type = typename base::size_type; using size_type = typename base::size_type;
@ -116,14 +116,14 @@ namespace math{
constexpr matrix& operator=(const matrix&) = default; constexpr matrix& operator=(const matrix&) = default;
constexpr matrix& operator=(matrix&&) = default; constexpr matrix& operator=(matrix&&) = default;
template<typename U> template<typename U>
constexpr matrix& operator=(const matrix<U,W,H>& m); constexpr matrix& operator=(const matrix<U,R,C>& m);
}; };
template<typename T, size_t W> template<typename T, size_t R>
class matrix<T,W,W> : public matrix_base<T,W,W> class matrix<T,R,R> : public matrix_base<T,R,R>
{ {
private: private:
using base = matrix_base<T,W,W>; using base = matrix_base<T,R,R>;
public: public:
using value_type = typename base::value_type; using value_type = typename base::value_type;
using size_type = typename base::size_type; using size_type = typename base::size_type;
@ -144,7 +144,7 @@ namespace math{
constexpr matrix& operator=(const matrix&) = default; constexpr matrix& operator=(const matrix&) = default;
constexpr matrix& operator=(matrix&&) = default; constexpr matrix& operator=(matrix&&) = default;
template<typename U> template<typename U>
constexpr matrix& operator=(const matrix<U,W,W>& m); constexpr matrix& operator=(const matrix<U,R,R>& m);
//square matrix arithmetic operations //square matrix arithmetic operations
constexpr value_type determinate()const; constexpr value_type determinate()const;
@ -191,8 +191,8 @@ namespace math{
template<typename T> template<typename T>
struct is_matrix_helper { struct is_matrix_helper {
template<typename U, size_t W, size_t H> template<typename U, size_t R, size_t C>
static std::true_type test(matrix<U,W,H>*); static std::true_type test(matrix_base<U,R,C>*);
static std::false_type test(void*); static std::false_type test(void*);
static constexpr bool value = std::is_same<std::true_type,decltype(test(static_cast<std::decay_t<T>*>(nullptr)))>::value; static constexpr bool value = std::is_same<std::true_type,decltype(test(static_cast<std::decay_t<T>*>(nullptr)))>::value;
@ -221,36 +221,36 @@ namespace math{
} }
template<typename T, typename U, size_t W, size_t H> template<typename T, typename U, size_t R, size_t C>
constexpr bool operator==(const matrix<T,W,H>& left, const matrix<U,W,H> right); constexpr bool operator==(const matrix_base<T,R,C>& left, const matrix_base<U,R,C> right);
template<typename T, typename U, size_t W, size_t H> template<typename T, typename U, size_t R, size_t C>
constexpr bool operator!=(const matrix<T,W,H>& left, const matrix<U,W,H> right); constexpr bool operator!=(const matrix_base<T,R,C>& left, const matrix_base<U,R,C> right);
template<typename T, typename U, size_t R1, size_t C1, size_t C2> template<typename T, typename U, size_t R1, size_t C1, size_t R2>
constexpr auto operator*(const matrix<T,C1,R1>& left, const matrix<U,C2,C1>& right); constexpr auto operator*(const matrix<T,R1,C1>& left, const matrix<U,C1,R2>& right);
template<typename T, typename U, size_t C, size_t R, std::enable_if_t<!is_matrix<U>::value,int> = 0>
constexpr auto operator*(const matrix<T,R,C>& left, U&& right);
template<typename T, typename U, size_t C, size_t R, std::enable_if_t<!is_matrix<U>::value,int> = 0>
constexpr auto operator*(U&& left, const matrix<T,R,C>& right);
template<typename T, typename U, size_t C, size_t R, std::enable_if_t<!is_matrix<U>::value,int> = 0>
constexpr auto operator/(const matrix<T,R,C>& left, U&& right);
template<typename T, typename U, size_t C, size_t R> template<typename T, typename U, size_t C, size_t R>
constexpr auto operator*(const matrix<T,C,R>& left, U&& right); constexpr auto operator+(const matrix<T,R,C>& left, const matrix<U,R,C>& right);
template<typename T, typename U, size_t C, size_t R> template<typename T, typename U, size_t C, size_t R>
constexpr auto operator*(U&& left, const matrix<T,C,R>& right); constexpr auto operator-(const matrix<T,R,C>& left, const matrix<U,R,C>& right);
template<typename T, typename U, size_t C, size_t R> template<typename T, typename U, size_t C, size_t R>
constexpr auto operator/(const matrix<T,C,R>& left, U&& right); constexpr auto operator-(const matrix<T,R,C>& left);
template<typename T, typename U, size_t C, size_t R>
constexpr auto operator+(const matrix<T,C,R>& left, const matrix<U,C,R>& right);
template<typename T, typename U, size_t C, size_t R>
constexpr auto operator-(const matrix<T,C,R>& left, const matrix<U,C,R>& right);
template<typename T, typename U, size_t C, size_t R>
constexpr auto operator-(const matrix<T,C,R>& left);
template<typename T, typename U, size_t R1, size_t C1, size_t C2> template<typename T, typename U, size_t R>
constexpr decltype(auto) operator*=(matrix<T,C1,R1>& left, const matrix<U,C2,C1>& right); constexpr decltype(auto) operator*=(matrix<T,R,R>& left, const matrix<U,R,R>& right);
template<typename T, typename U, size_t C, size_t R, std::enable_if_t<!is_matrix<U>::value,int> = 0>
constexpr decltype(auto) operator*=(matrix<T,R,C>& left, U&& right);
template<typename T, typename U, size_t C, size_t R, std::enable_if_t<!is_matrix<U>::value,int> = 0>
constexpr decltype(auto) operator/=(matrix<T,R,C>& left, U&& right);
template<typename T, typename U, size_t C, size_t R> template<typename T, typename U, size_t C, size_t R>
constexpr decltype(auto) operator*=(matrix<T,C,R>& left, U&& right); constexpr decltype(auto) operator+=(matrix<T,R,C>& left, const matrix<U,R,C>& right);
template<typename T, typename U, size_t C, size_t R> template<typename T, typename U, size_t C, size_t R>
constexpr decltype(auto) operator/=(matrix<T,C,R>& left, U&& right); constexpr decltype(auto) operator-=(matrix<T,R,C>& left, const matrix<U,R,C>& right);
template<typename T, typename U, size_t C, size_t R>
constexpr decltype(auto) operator+=(matrix<T,C,R>& left, const matrix<U,C,R>& right);
template<typename T, typename U, size_t C, size_t R>
constexpr decltype(auto) operator-=(matrix<T,C,R>& left, const matrix<U,C,R>& right);
} }

View File

@ -26,42 +26,42 @@
namespace math{ namespace math{
template<typename T, size_t W, size_t H> template<typename T, size_t R, size_t C>
template<size_t... Ss> template<size_t... Ss>
constexpr matrix_base<T,W,H>::matrix_base(std::integer_sequence<size_type,Ss...>): constexpr matrix_base<T,R,C>::matrix_base(std::integer_sequence<size_type,Ss...>):
m_data{Ss...}{} m_data{Ss...}{}
template<typename T, size_t W, size_t H> template<typename T, size_t R, size_t C>
constexpr matrix_base<T,W,H>::matrix_base(): constexpr matrix_base<T,R,C>::matrix_base():
matrix_base(typename detail::default_initialization_matrix<Columns,Rows>::tuple{}){} matrix_base(typename detail::default_initialization_matrix<Columns,Rows>::tuple{}){}
template<typename T, size_t W, size_t H> template<typename T, size_t R, size_t C>
constexpr matrix_base<T,W,H>::matrix_base(detail::zero_initialize_t): constexpr matrix_base<T,R,C>::matrix_base(detail::zero_initialize_t):
m_data{}{} m_data{}{}
template<typename T, size_t W, size_t H> template<typename T, size_t R, size_t C>
constexpr matrix_base<T,W,H>::matrix_base(detail::no_initialize_t){} constexpr matrix_base<T,R,C>::matrix_base(detail::no_initialize_t){}
template<typename T, size_t W, size_t H> template<typename T, size_t R, size_t C>
constexpr matrix_base<T,W,H>::matrix_base(value_type v){ constexpr matrix_base<T,R,C>::matrix_base(value_type v){
for(size_type i = 0;i < Columns*Rows;++i) for(size_type i = 0;i < Columns*Rows;++i)
m_data[i] = v; m_data[i] = v;
} }
template<typename T, size_t W, size_t H> template<typename T, size_t R, size_t C>
template<typename... Args> template<typename... Args>
constexpr matrix_base<T,W,H>::matrix_base(Args&&... args): constexpr matrix_base<T,R,C>::matrix_base(Args&&... args):
m_data{std::forward<Args>(args)...}{} m_data{std::forward<Args>(args)...}{}
template<typename T, size_t W, size_t H> template<typename T, size_t R, size_t C>
template<typename U> template<typename U>
constexpr matrix_base<T,W,H>::matrix_base(const matrix_base<U,Columns,Rows>& m){ constexpr matrix_base<T,R,C>::matrix_base(const matrix_base<U,Columns,Rows>& m){
using mat = decltype(m); using mat = decltype(m);
for(typename mat::size_type i = 0;i < mat::Columns*mat::Rows;++i) for(typename mat::size_type i = 0;i < mat::Columns*mat::Rows;++i)
m_data[i] = m.get(i); m_data[i] = m.get(i);
} }
template<typename T, size_t W, size_t H> template<typename T, size_t R, size_t C>
template<typename U> template<typename U>
constexpr matrix_base<T,W,H>& matrix_base<T,W,H>::operator=(const matrix_base<U,Columns,Rows>& m){ constexpr matrix_base<T,R,C>& matrix_base<T,R,C>::operator=(const matrix_base<U,Columns,Rows>& m){
using mat = decltype(m); using mat = decltype(m);
for(typename mat::size_type i = 0;i < mat::Columns*mat::Rows;++i) for(typename mat::size_type i = 0;i < mat::Columns*mat::Rows;++i)
m_data[i] = m.get(i); m_data[i] = m.get(i);
@ -69,101 +69,101 @@ namespace math{
} }
template<typename T, size_t W, size_t H> template<typename T, size_t R, size_t C>
constexpr auto matrix_base<T,W,H>::operator[](size_type x){ constexpr auto matrix_base<T,R,C>::operator[](size_type x){
return detail::mat_ref_obj<value_type,Rows>{m_data, x}; return detail::mat_ref_obj<value_type,Rows>{m_data, x};
} }
template<typename T, size_t W, size_t H> template<typename T, size_t R, size_t C>
constexpr auto matrix_base<T,W,H>::operator[](size_type x)const{ constexpr auto matrix_base<T,R,C>::operator[](size_type x)const{
return detail::mat_ref_obj<const value_type,Rows>{m_data, x}; return detail::mat_ref_obj<const value_type,Rows>{m_data, x};
} }
template<typename T, size_t W, size_t H> template<typename T, size_t R, size_t C>
constexpr auto matrix_base<T,W,H>::get(size_type x, size_type y) -> reference{ constexpr auto matrix_base<T,R,C>::get(size_type x, size_type y) -> reference{
return m_data[x+(y*Rows)]; return m_data[x+(y*Rows)];
} }
template<typename T, size_t W, size_t H> template<typename T, size_t R, size_t C>
constexpr auto matrix_base<T,W,H>::get(size_type x, size_type y)const -> const_reference{ constexpr auto matrix_base<T,R,C>::get(size_type x, size_type y)const -> const_reference{
return m_data[x+(y*Rows)]; return m_data[x+(y*Rows)];
} }
template<typename T, size_t W, size_t H> template<typename T, size_t R, size_t C>
constexpr auto matrix_base<T,W,H>::get(size_type i) -> reference{ constexpr auto matrix_base<T,R,C>::get(size_type i) -> reference{
return m_data[i]; return m_data[i];
} }
template<typename T, size_t W, size_t H> template<typename T, size_t R, size_t C>
constexpr auto matrix_base<T,W,H>::get(size_type i)const -> const_reference{ constexpr auto matrix_base<T,R,C>::get(size_type i)const -> const_reference{
return m_data[i]; return m_data[i];
} }
template<typename T, size_t W, size_t H> template<typename T, size_t R, size_t C>
constexpr auto matrix_base<T,W,H>::columns()const -> size_type{ constexpr auto matrix_base<T,R,C>::columns()const -> size_type{
return Columns; return Columns;
} }
template<typename T, size_t W, size_t H> template<typename T, size_t R, size_t C>
constexpr auto matrix_base<T,W,H>::rows()const -> size_type{ constexpr auto matrix_base<T,R,C>::rows()const -> size_type{
return Rows; return Rows;
} }
template<typename T, size_t W, size_t H> template<typename T, size_t R, size_t C>
constexpr auto matrix_base<T,W,H>::size()const -> size_type{ constexpr auto matrix_base<T,R,C>::size()const -> size_type{
return Columns*Rows; return Columns*Rows;
} }
template<typename T, size_t W, size_t H> template<typename T, size_t R, size_t C>
constexpr auto matrix_base<T,W,H>::raw() -> pointer{ constexpr auto matrix_base<T,R,C>::raw() -> pointer{
return m_data; return m_data;
} }
template<typename T, size_t W, size_t H> template<typename T, size_t R, size_t C>
constexpr auto matrix_base<T,W,H>::raw()const -> const_pointer{ constexpr auto matrix_base<T,R,C>::raw()const -> const_pointer{
return m_data; return m_data;
} }
template<typename T, size_t W, size_t H> template<typename T, size_t R, size_t C>
constexpr matrix_base<T,W,H>::operator pointer(){ constexpr matrix_base<T,R,C>::operator pointer(){
return m_data; return m_data;
} }
template<typename T, size_t W, size_t H> template<typename T, size_t R, size_t C>
constexpr matrix_base<T,W,H>::operator const_pointer()const{ constexpr matrix_base<T,R,C>::operator const_pointer()const{
return m_data; return m_data;
} }
template<typename T, size_t W, size_t H> template<typename T, size_t R, size_t C>
template<typename U> template<typename U>
constexpr matrix<T,W,H>& matrix<T,W,H>::operator=(const matrix<U,W,H>& m){ constexpr matrix<T,R,C>& matrix<T,R,C>::operator=(const matrix<U,R,C>& m){
base::operator=(m); base::operator=(m);
return *this; return *this;
} }
template<typename T, size_t W> template<typename T, size_t R>
constexpr matrix<T,W,W>::matrix(detail::id_initialize_t): constexpr matrix<T,R,R>::matrix(detail::id_initialize_t):
base(){} base(){}
template<typename T, size_t W> template<typename T, size_t R>
template<typename U> template<typename U>
constexpr matrix<T,W,W>& matrix<T,W,W>::operator=(const matrix<U,W,W>& m){ constexpr matrix<T,R,R>& matrix<T,R,R>::operator=(const matrix<U,R,R>& m){
base::operator=(m); base::operator=(m);
return *this; return *this;
} }
template<typename T, size_t W> template<typename T, size_t R>
constexpr auto matrix<T,W,W>::determinate()const -> value_type{ constexpr auto matrix<T,R,R>::determinate()const -> value_type{
return math::determinate(*this); return math::determinate(*this);
} }
template<typename T, size_t W> template<typename T, size_t R>
constexpr auto matrix<T,W,W>::trace()const -> value_type{ constexpr auto matrix<T,R,R>::trace()const -> value_type{
value_type sum = 0; value_type sum = 0;
for(size_type i = 0;i < W;++i){ for(size_type i = 0;i < R;++i){
sum += get(i, i); sum += get(i, i);
} }
} }
template<typename T, size_t W> template<typename T, size_t R>
constexpr matrix<T,W,W> matrix<T,W,W>::transpose()const{ constexpr matrix<T,R,R> matrix<T,R,R>::transpose()const{
matrix m(no_initialize); matrix m(no_initialize);
for(size_type i = 0;i < W;++i){ for(size_type i = 0;i < R;++i){
for(size_type j = 0;j < W;++j){ for(size_type j = 0;j < R;++j){
m.get(j, i) = get(i, j); m.get(j, i) = get(i, j);
} }
} }
return m; return m;
} }
template<typename T, size_t W> template<typename T, size_t R>
constexpr matrix<T,W,W> matrix<T,W,W>::inverse()const{ constexpr matrix<T,R,R> matrix<T,R,R>::inverse()const{
return math::inverse(*this); return math::inverse(*this);
} }
@ -261,83 +261,82 @@ namespace math{
} }
template<typename T, typename U, size_t W, size_t H> template<typename T, typename U, size_t R, size_t C>
constexpr bool operator==(const matrix<T,W,H>& left, const matrix<U,W,H> right){ constexpr bool operator==(const matrix_base<T,R,C>& left, const matrix_base<U,R,C> right){
for(size_t i = 0;i < left.size();++i){ for(size_t i = 0;i < left.size();++i){
if(left.get(i) != right.get(i)) if(left.get(i) != right.get(i))
return false; return false;
} }
return true; return true;
} }
template<typename T, typename U, size_t W, size_t H> template<typename T, typename U, size_t R, size_t C>
constexpr bool operator!=(const matrix<T,W,H>& left, const matrix<U,W,H> right){ constexpr bool operator!=(const matrix_base<T,R,C>& left, const matrix_base<U,R,C> right){
return !(left == right); return !(left == right);
} }
template<typename T, typename U, size_t R1, size_t C1, size_t C2> template<typename T, typename U, size_t R1, size_t C1, size_t C2>
constexpr auto operator*(const matrix<T,C1,R1>& left, const matrix<U,C2,C1>& right){ constexpr auto operator*(const matrix<T,R1,C1>& left, const matrix<U,C1,C2>& right){
using res_t = decltype(std::declval<T>() * std::declval<U>()); using res_t = decltype(std::declval<T>() * std::declval<U>());
matrix<res_t,C2,R1> res(no_initialize); matrix<res_t,R1,C2> res(zero_initialize);
size_t index = 0; size_t index = 0;
for(size_t i = 0;i < right.rows();++i){ for(size_t i = 0;i < left.rows();++i){
for(size_t j = 0;j < left.rows();++j){ for(size_t j = 0;j < right.columns();++j){
for(size_t k = 0;k < left.columns();++k){ for(size_t k = 0;k < right.rows();++k){
res.get(index) += left[j][k] * right[i][k]; res.get(index) += left[i][k] * right[k][j];
} }
++index; ++index;
} }
} }
return res;
} }
template<typename T, typename U, size_t C, size_t R> template<typename T, typename U, size_t C, size_t R, std::enable_if_t<!is_matrix<U>::value,int>>
constexpr auto operator*(const matrix<T,C,R>& left, U&& right){ constexpr auto operator*(const matrix<T,R,C>& left, U&& right){
using res_t = decltype(std::declval<T>() * std::declval<U>()); using res_t = decltype(std::declval<T>() * std::declval<U>());
matrix<res_t,C,R> res(no_initialize); matrix<res_t,R,C> res(no_initialize);
for(size_t i = 0;i < left.size();++i){ for(size_t i = 0;i < left.size();++i){
res.get(i) = left.get(i) * std::forward<U>(right); res.get(i) = left.get(i) * std::forward<U>(right);
} }
return res; return res;
} }
template<typename T, typename U, size_t C, size_t R> template<typename T, typename U, size_t C, size_t R, std::enable_if_t<!is_matrix<U>::value,int>>
constexpr auto operator*(U&& left, const matrix<T,C,R>& right){ constexpr auto operator*(U&& left, const matrix<T,R,C>& right){
using res_t = decltype(std::declval<T>() * std::declval<U>()); using res_t = decltype(std::declval<T>() * std::declval<U>());
matrix<res_t,C,R> res(no_initialize); matrix<res_t,R,C> res(no_initialize);
for(size_t i = 0;i < right.size();++i){ for(size_t i = 0;i < right.size();++i){
res.get(i) = std::forward<U>(left) * right.get(i); res.get(i) = std::forward<U>(left) * right.get(i);
} }
return res; return res;
} }
template<typename T, typename U, size_t C, size_t R> template<typename T, typename U, size_t C, size_t R, std::enable_if_t<!is_matrix<U>::value,int>>
constexpr auto operator/(const matrix<T,C,R>& left, U&& right){ constexpr auto operator/(const matrix<T,R,C>& left, U&& right){
using res_t = decltype(std::declval<T>() / std::declval<U>()); using res_t = decltype(std::declval<T>() / std::declval<U>());
matrix<res_t,C,R> res(no_initialize); matrix<res_t,R,C> res(no_initialize);
for(size_t i = 0;i < left.size();++i){ for(size_t i = 0;i < left.size();++i){
res.get(i) = left.get(i) / std::forward<U>(right); res.get(i) = left.get(i) / std::forward<U>(right);
} }
return res; return res;
} }
template<typename T, typename U, size_t C, size_t R> template<typename T, typename U, size_t C, size_t R>
constexpr auto operator+(const matrix<T,C,R>& left, const matrix<U,C,R>& right){ constexpr auto operator+(const matrix<T,R,C>& left, const matrix<U,R,C>& right){
using res_t = decltype(std::declval<T>() + std::declval<U>()); using res_t = decltype(std::declval<T>() + std::declval<U>());
matrix<res_t,C,R> res(no_initialize); matrix<res_t,R,C> res(no_initialize);
for(size_t i = 0;i < left.size();++i){ for(size_t i = 0;i < left.size();++i){
res.get(i) = left.get(i) + right.get(i); res.get(i) = left.get(i) + right.get(i);
} }
return res; return res;
} }
template<typename T, typename U, size_t C, size_t R> template<typename T, typename U, size_t C, size_t R>
constexpr auto operator-(const matrix<T,C,R>& left, const matrix<U,C,R>& right){ constexpr auto operator-(const matrix<T,R,C>& left, const matrix<U,R,C>& right){
using res_t = decltype(std::declval<T>() - std::declval<U>()); using res_t = decltype(std::declval<T>() - std::declval<U>());
matrix<res_t,C,R> res(no_initialize); matrix<res_t,R,C> res(no_initialize);
for(size_t i = 0;i < left.size();++i){ for(size_t i = 0;i < left.size();++i){
res.get(i) = left.get(i) - right.get(i); res.get(i) = left.get(i) - right.get(i);
} }
return res; return res;
} }
template<typename T, typename U, size_t C, size_t R> template<typename T, typename U, size_t C, size_t R>
constexpr auto operator-(const matrix<T,C,R>& left){ constexpr auto operator-(const matrix<T,R,C>& left){
using res_t = decltype(std::declval<T>() - std::declval<U>()); using res_t = decltype(-std::declval<U>());
matrix<res_t,C,R> res(no_initialize); matrix<res_t,R,C> res(no_initialize);
for(size_t i = 0;i < left.size();++i){ for(size_t i = 0;i < left.size();++i){
res.get(i) = -left.get(i); res.get(i) = -left.get(i);
} }
@ -345,35 +344,35 @@ namespace math{
} }
template<typename T, typename U, size_t R1, size_t C1, size_t C2> template<typename T, typename U, size_t R>
constexpr decltype(auto) operator*=(matrix<T,C1,R1>& left, const matrix<U,C2,C1>& right){ constexpr decltype(auto) operator*=(matrix<T,R,R>& left, const matrix<U,R,R>& right){
//have to evaluate entire expression first since matrix multiplication depends on reusing many elements //have to evaluate entire expression first since matrix multiplication depends on reusing many elements
//cannot be expression templatized, TODO //cannot be expression templatized, TODO
return (left = (left * right)); return (left = (left * right));
} }
template<typename T, typename U, size_t C, size_t R> template<typename T, typename U, size_t C, size_t R, std::enable_if_t<!is_matrix<U>::value,int>>
constexpr decltype(auto) operator*=(matrix<T,C,R>& left, U&& right){ constexpr decltype(auto) operator*=(matrix<T,R,C>& left, U&& right){
for(size_t i = 0;i < left.size();++i){ for(size_t i = 0;i < left.size();++i){
left.get(i) = left.get(i) * std::forward<U>(right); left.get(i) = left.get(i) * std::forward<U>(right);
} }
return left; return left;
} }
template<typename T, typename U, size_t C, size_t R> template<typename T, typename U, size_t C, size_t R, std::enable_if_t<!is_matrix<U>::value,int>>
constexpr decltype(auto) operator/=(matrix<T,C,R>& left, U&& right){ constexpr decltype(auto) operator/=(matrix<T,R,C>& left, U&& right){
for(size_t i = 0;i < left.size();++i){ for(size_t i = 0;i < left.size();++i){
left.get(i) = left.get(i) / std::forward<U>(right); left.get(i) = left.get(i) / std::forward<U>(right);
} }
return left; return left;
} }
template<typename T, typename U, size_t C, size_t R> template<typename T, typename U, size_t C, size_t R>
constexpr decltype(auto) operator+=(matrix<T,C,R>& left, const matrix<U,C,R>& right){ constexpr decltype(auto) operator+=(matrix<T,R,C>& left, const matrix<U,R,C>& right){
for(size_t i = 0;i < left.size();++i){ for(size_t i = 0;i < left.size();++i){
left.get(i) = left.get(i) + right.get(i); left.get(i) = left.get(i) + right.get(i);
} }
return left; return left;
} }
template<typename T, typename U, size_t C, size_t R> template<typename T, typename U, size_t C, size_t R>
constexpr decltype(auto) operator-=(matrix<T,C,R>& left, const matrix<U,C,R>& right){ constexpr decltype(auto) operator-=(matrix<T,R,C>& left, const matrix<U,R,C>& right){
for(size_t i = 0;i < left.size();++i){ for(size_t i = 0;i < left.size();++i){
left.get(i) = left.get(i) - right.get(i); left.get(i) = left.get(i) - right.get(i);
} }