diff --git a/src/core/include/pw/core/matrix.hpp b/src/core/include/pw/core/matrix.hpp index 5199228..0a305e2 100644 --- a/src/core/include/pw/core/matrix.hpp +++ b/src/core/include/pw/core/matrix.hpp @@ -23,28 +23,32 @@ #ifndef PW_CORE_MATRIX_HPP #define PW_CORE_MATRIX_HPP +#include <cstddef> #include <pw/core/globals.hpp> #include <pw/core/math.hpp> #include <pw/core/vector.hpp> +#include <type_traits> #include <utility> namespace pw { -template <typename Scalar, unsigned int Rows, unsigned int Cols> +template <typename Scalar, std::size_t Rows, std::size_t Cols> struct matrix final { - static_assert(Rows > 0 && Cols > 0, "undefined matrix type"); + static_assert(Rows > 0 && Cols > 0, "Undefined matrix type."); static constexpr unsigned int diag_size{std::min(Rows, Cols)}; static constexpr unsigned int rows{Rows}; static constexpr unsigned int cols{Cols}; static constexpr bool is_square{Rows == Cols}; + using size_type = std::common_type_t<decltype(Rows), decltype(Cols)>; + using row_type = vector<Scalar, Cols>; + using column_type = vector<Scalar, Rows>; using diag_type = vector<Scalar, diag_size>; using transpose_type = matrix<Scalar, Cols, Rows>; using minor_type = matrix<Scalar, Cols - 1, Rows - 1>; - using column_type = vector<Scalar, Rows>; vector<vector<Scalar, Cols>, Rows> m_{}; @@ -56,6 +60,14 @@ struct matrix final { return std::forward<decltype(self)>(self).m_[r]; } + // + // part of tuple-protocol + // + template <size_type idx> auto get(this auto&& self) -> decltype(auto) { + static_assert(idx < Rows, "Out of bounds access to a member."); + return std::forward_like<decltype(self)>(self.m_[idx]); + } + constexpr auto diagonal() const noexcept -> diag_type { return [this]<std::size_t... Is>(std::index_sequence<Is...>) { return diag_type{(*this)[Is][Is]...}; @@ -226,4 +238,16 @@ constexpr auto operator*(const matrix<ScalarA, Ra, Ca>& A, } // namespace pw +// +// tuple - protocol +// +template <class Scalar, std::size_t R, std::size_t C> +struct std::tuple_size<pw::matrix<Scalar, R, C>> + : std::integral_constant<std::size_t, R> {}; + +template <std::size_t I, class Scalar, std::size_t R, std::size_t C> +struct std::tuple_element<I, pw::matrix<Scalar, R, C>> { + using type = pw::matrix<Scalar, R, C>::row_type; +}; + #endif diff --git a/src/core/include/pw/core/vector.hpp b/src/core/include/pw/core/vector.hpp index bf589d9..0008c25 100644 --- a/src/core/include/pw/core/vector.hpp +++ b/src/core/include/pw/core/vector.hpp @@ -40,7 +40,9 @@ concept Vector3 = (N == 3); template <typename T, auto N> concept Vector4 = (N == 4); -template <typename Scalar, std::size_t N> struct vector { +template <typename Scalar, std::size_t N> struct vector final { + + static_assert(N > 0, "Undefined vector space."); using value_type = Scalar; using size_type = decltype(N); @@ -71,7 +73,7 @@ template <typename Scalar, std::size_t N> struct vector { template <typename... Args> static constexpr auto make(Args&&... values) noexcept -> vector<Scalar, sizeof...(Args)> { - static_assert(sizeof...(Args) == N, "incorrect number of arguments"); + static_assert(sizeof...(Args) == N, "Incorrect number of arguments."); return {{Scalar(values)...}}; } @@ -84,7 +86,7 @@ template <typename Scalar, std::size_t N> struct vector { template <typename... Args> constexpr auto swizzle(Args&&... indices) const noexcept -> vector<Scalar, sizeof...(Args)> { - return {{Scalar(v_[indices])...}}; + return {{Scalar{v_[indices]}...}}; } constexpr auto minor(std::unsigned_integral auto d0) const noexcept { @@ -102,9 +104,9 @@ template <typename Scalar, std::size_t N> struct vector { } static constexpr auto lerp(const vector& A, const vector& B, - const Scalar& factor) -> vector { + const Scalar& t) -> vector { return [&]<std::size_t... Ss>(std::index_sequence<Ss...>) { - return vector<Scalar, N>{{A[Ss] + factor * (B[Ss] - A[Ss])...}}; + return vector<Scalar, N>{{A[Ss] + t * (B[Ss] - A[Ss])...}}; }(std::make_index_sequence<N>{}); } @@ -254,10 +256,10 @@ template <typename Scalar, std::size_t N> struct vector { }; // - // tuple like for structured bindings + // part of tuple-protocol // template <size_type idx> auto get(this auto&& self) -> decltype(auto) { - static_assert(idx < N, "out of bounds access to a member."); + static_assert(idx < N, "Out of bounds access to a member."); return std::forward_like<decltype(self)>(self.v_[idx]); } diff --git a/src/core/tests/pwcore_test_matrix.cpp b/src/core/tests/pwcore_test_matrix.cpp index 594142d..a63e4f7 100644 --- a/src/core/tests/pwcore_test_matrix.cpp +++ b/src/core/tests/pwcore_test_matrix.cpp @@ -3,6 +3,8 @@ #include <pw/core/serialize.hpp> #include <pw/core/vector.hpp> +#include <print> + auto main() -> int { pw::debug::d() << "pixwerx.matrix.test\n"; @@ -38,4 +40,10 @@ auto main() -> int { auto m22_tp_col1 = m22_tp.column(1); pw::debug::d() << "matrix<2,2>{1,2,3,4}.transposed().column(1) -> \n" << pw::serialize::to_string(m22_tp_col1); + + auto& [r1, r2] = m22_inv; + + auto& [r1_x, r1_y] = r1; + + std::print("r1.x:{} r1.y:{}\n", r1_x, r1_y); } diff --git a/src/core/tests/pwcore_test_vector.cpp b/src/core/tests/pwcore_test_vector.cpp index 697038e..446671d 100644 --- a/src/core/tests/pwcore_test_vector.cpp +++ b/src/core/tests/pwcore_test_vector.cpp @@ -6,7 +6,6 @@ #include <tuple> #include <vector> - auto main() -> int { auto v2_A = pw::vector{3.2, 1.2};