From 71489dcca4f2278a517a6f6ae784aa0913f1cdfe Mon Sep 17 00:00:00 2001 From: rexy712 Date: Sat, 15 Aug 2020 13:56:43 -0700 Subject: [PATCH] Add basic matrix stuff --- include/detail/math.hpp | 19 ++++ include/detail/matrix.hpp | 190 +++++++++++++++++++++++++++++++ include/mat.hpp | 227 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 436 insertions(+) create mode 100644 include/detail/math.hpp create mode 100644 include/detail/matrix.hpp create mode 100644 include/mat.hpp diff --git a/include/detail/math.hpp b/include/detail/math.hpp new file mode 100644 index 0000000..5423df9 --- /dev/null +++ b/include/detail/math.hpp @@ -0,0 +1,19 @@ +#ifndef REXY_DETAIL_MATH_HPP +#define REXY_DETAIL_MATH_HPP + +namespace math{ + + namespace detail{ + struct zero_initialize_t{}; + struct no_initialize_t{}; + struct id_initialize_t{}; + + } + + static inline constexpr detail::zero_initialize_t zero_initialize; + static inline constexpr detail::no_initialize_t no_initialize; + static inline constexpr detail::id_initialize_t id_initialize; + +} + +#endif diff --git a/include/detail/matrix.hpp b/include/detail/matrix.hpp new file mode 100644 index 0000000..ec7e492 --- /dev/null +++ b/include/detail/matrix.hpp @@ -0,0 +1,190 @@ +#ifndef REXY_DETAIL_MATRIX_HPP +#define REXY_DETAIL_MATRIX_HPP + +#include //size_t +#include //integer_sequence + +namespace math::detail{ + + template + struct gen_id_tup{ + using tup = typename gen_id_tup::tup; + }; + template + struct gen_id_tup{ + using tup = typename gen_id_tup::tup; + }; + template + struct gen_id_tup{ + using tup = typename gen_id_tup::tup; + }; + template + struct gen_id_tup{ + using tup = std::integer_sequence; + }; + + + template + struct gen_zero_tup{ + using tup = typename gen_zero_tup::tup; + }; + template + struct gen_zero_tup<0,Args...>{ + using tup = std::integer_sequence; + }; + + template + struct id_initialization_matrix{ + using tuple = typename gen_id_tup::tup; + }; + + + template + struct default_initialization_matrix{ + using tuple = typename gen_zero_tup::tup; + }; + template + struct default_initialization_matrix{ + using tuple = typename id_initialization_matrix::tuple; + }; + + template + class mat_ref_obj + { + public: + using size_type = size_t; + + protected: + T* m_data = nullptr; + public: + constexpr mat_ref_obj(T* d, size_type i): + m_data(d+i){} + + constexpr T& operator[](size_type i){ + return m_data[i*R]; + } + constexpr const T& operator[](size_type i)const{ + return m_data[i*R]; + } + }; + + template + class matrix_base + { + static_assert(W > 0, "Cannot have 0 columns matrix"); + static_assert(H > 0, "Cannot have 0 rows matrix"); + public: + using value_type = T; + using size_type = size_t; + using pointer = value_type*; + using const_pointer = const value_type*; + using reference = value_type&; + using const_reference = const value_type&; + + static constexpr size_type Columns = W; + static constexpr size_type Rows = H; + + protected: + value_type m_data[W*H]; + + protected: + template + constexpr matrix_base(std::integer_sequence): + m_data{Ss...}{} + + public: + //Default construct as identity when square, zero otherwise + constexpr matrix_base(void): + matrix_base(typename detail::default_initialization_matrix::tuple{}){} + + //Range initializing constructors + constexpr explicit matrix_base(zero_initialize_t): + m_data{}{} + constexpr explicit matrix_base(no_initialize_t){} + template + constexpr explicit matrix_base(id_initialize_t): + matrix_base() + { + static_assert(Columns == Rows, "Identity initialization only supported on square matrices"); + } + + //Value initializing constructors + constexpr explicit matrix_base(value_type v){ + for(size_type i = 0;i < Columns*Rows;++i) + m_data[i] = v; + } + template + constexpr explicit matrix_base(Args&&... args): + m_data{std::forward(args)...}{} + + //Copying constructors + constexpr matrix_base(const matrix_base&) = default; + constexpr matrix_base(matrix_base&&) = default; + template + constexpr matrix_base(const matrix_base& m){ + using mat = decltype(m); + for(typename mat::size_type i = 0;i < mat::Columns*mat::Rows;++i) + m_data[i] = m.get(i); + } + ~matrix_base(void) = default; + + //Assignement + template + constexpr matrix_base& operator=(const matrix_base& m){ + using mat = decltype(m); + for(typename mat::size_type i = 0;i < mat::Columns*mat::Rows;++i) + m_data[i] = m.get(i); + return *this; + } + constexpr matrix_base& operator=(const matrix_base&) = default; + constexpr matrix_base& operator=(matrix_base&&) = default; + + + //Getters/Setters + constexpr auto operator[](size_type x){ + return detail::mat_ref_obj{m_data, x}; + } + constexpr auto operator[](size_type x)const{ + return detail::mat_ref_obj{m_data, x}; + } + constexpr reference get(size_type x, size_type y){ + return m_data[x+(y*Rows)]; + } + constexpr const_reference get(size_type x, size_type y)const{ + return m_data[x+(y*Rows)]; + } + constexpr reference get(size_type i){ + return m_data[i]; + } + constexpr const_reference get(size_type i)const{ + return m_data[i]; + } + + constexpr size_type columns(void)const{ + return Columns; + } + constexpr size_type rows(void)const{ + return Rows; + } + constexpr size_type size(void)const{ + return Columns*Rows; + } + + constexpr pointer raw(void){ + return m_data; + } + constexpr const_pointer raw(void)const{ + return m_data; + } + constexpr operator pointer(void){ + return m_data; + } + constexpr operator const_pointer(void)const{ + return m_data; + } + + }; + +} + +#endif diff --git a/include/mat.hpp b/include/mat.hpp new file mode 100644 index 0000000..1446265 --- /dev/null +++ b/include/mat.hpp @@ -0,0 +1,227 @@ +/** + This file is a part of the rexy/r0nk/atlas project + Copyright (C) 2020 rexy712 + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef REXY_MAT_HPP +#define REXY_MAT_HPP + +#include //size_t +#include //integer_sequence +#include //decay_t +#include //sin, cos +#include "detail/math.hpp" +#include "detail/matrix.hpp" + +namespace math{ + + template + class matrix : public detail::matrix_base + { + private: + using base = detail::matrix_base; + public: + using value_type = typename base::value_type; + using size_type = typename base::size_type; + using pointer = typename base::pointer; + using const_pointer = typename base::const_pointer; + using reference = typename base::reference; + using const_reference = typename base::const_reference; + public: + using detail::matrix_base::matrix_base; + using detail::matrix_base::operator=; + }; + + template + class matrix : public detail::matrix_base + { + private: + using base = detail::matrix_base; + public: + using value_type = typename base::value_type; + using size_type = typename base::size_type; + using pointer = typename base::pointer; + using const_pointer = typename base::const_pointer; + using reference = typename base::reference; + using const_reference = typename base::const_reference; + public: + using detail::matrix_base::matrix_base; + using detail::matrix_base::operator=; + + template + static constexpr matrix rotation(value_type angle){ + value_type c = std::cos(angle); + value_type s = std::sin(angle); + return rotation(s, c); + } + template + static constexpr matrix rotation(value_type sin, value_type cos){ + return matrix(cos, -sin, 0, + sin, cos, 0, + 0, 0, 1); + } + static constexpr matrix rotation(value_type angle_x, value_type angle_y, value_type angle_z){ + //TODO + } + }; + + namespace detail{ + + template + struct is_matrix_helper{ + template + static std::true_type test(matrix*); + static std::false_type test(void*); + + static constexpr bool value = std::is_same*>(nullptr)))>::value; + }; + + } + + template + struct is_matrix{ + static constexpr bool value = (detail::is_matrix_helper::value && ...); + }; + + namespace detail{ + + template + struct are_same_size_matrix{ + using l = std::decay_t; + using r = std::decay_t; + static constexpr bool value = is_matrix::value && l::Columns == r::Columns && l::Rows == r::Rows; + }; + template + using enable_if_matrix = std::enable_if_t::value,int>; + + template + using enable_if_eq_matrix = std::enable_if_t::value,int>; + + } + + template + constexpr bool operator==(const matrix& left, const matrix right){ + for(size_t i = 0;i < left.size();++i){ + if(left.get(i) != right.get(i)) + return false; + } + return true; + } + template + constexpr bool operator!=(const matrix& left, const matrix right){ + return !(left == right); + } + + template + constexpr auto operator*(const matrix& left, const matrix& right){ + using res_t = decltype(std::declval() * std::declval()); + matrix res(no_initialize); + size_t index = 0; + for(size_t i = 0;i < right.rows();++i){ + for(size_t j = 0;j < left.rows();++j){ + for(size_t k = 0;k < left.columns();++k){ + res.get(index) += left[j][k] * right[i][k]; + } + ++index; + } + } + return res; + } + template + constexpr auto operator*(const matrix& left, U&& right){ + using res_t = decltype(std::declval() * std::declval()); + matrix res(no_initialize); + for(size_t i = 0;i < left.size();++i){ + res.get(i) = left.get(i) * std::forward(right); + } + return res; + } + template + constexpr auto operator/(const matrix& left, U&& right){ + using res_t = decltype(std::declval() / std::declval()); + matrix res(no_initialize); + for(size_t i = 0;i < left.size();++i){ + res.get(i) = left.get(i) / std::forward(right); + } + return res; + } + template + constexpr auto operator+(const matrix& left, const matrix& right){ + using res_t = decltype(std::declval() + std::declval()); + matrix res(no_initialize); + for(size_t i = 0;i < left.size();++i){ + res.get(i) = left.get(i) + right.get(i); + } + return res; + } + template + constexpr auto operator-(const matrix& left, const matrix& right){ + using res_t = decltype(std::declval() - std::declval()); + matrix res(no_initialize); + for(size_t i = 0;i < left.size();++i){ + res.get(i) = left.get(i) - right.get(i); + } + return res; + } + template + constexpr auto operator-(const matrix& left){ + using res_t = decltype(std::declval() - std::declval()); + matrix res(no_initialize); + for(size_t i = 0;i < left.size();++i){ + res.get(i) = -left.get(i); + } + return res; + } + + + template + constexpr decltype(auto) operator*=(matrix& left, const matrix& right){ + //have to evaluate entire expression first since matrix multiplication depends on reusing many elements + //cannot be expression templatized, TODO + return (left = (left * right)); + } + template + constexpr decltype(auto) operator*=(matrix& left, U&& right){ + for(size_t i = 0;i < left.size();++i){ + left.get(i) = left.get(i) * std::forward(right); + } + return left; + } + template + constexpr decltype(auto) operator/=(matrix& left, U&& right){ + for(size_t i = 0;i < left.size();++i){ + left.get(i) = left.get(i) / std::forward(right); + } + return left; + } + template + constexpr decltype(auto) operator+=(matrix& left, const matrix& right){ + for(size_t i = 0;i < left.size();++i){ + left.get(i) = left.get(i) + right.get(i); + } + return left; + } + template + constexpr decltype(auto) operator-=(matrix& left, const matrix& right){ + for(size_t i = 0;i < left.size();++i){ + left.get(i) = left.get(i) - right.get(i); + } + return left; + } + +} + +#endif