added structured binding support for matrix

This commit is contained in:
Hartmut Seichter 2024-07-14 23:16:14 +02:00
parent 98685e49ed
commit f3365d0669
4 changed files with 44 additions and 11 deletions

View file

@ -23,28 +23,32 @@
#ifndef PW_CORE_MATRIX_HPP #ifndef PW_CORE_MATRIX_HPP
#define PW_CORE_MATRIX_HPP #define PW_CORE_MATRIX_HPP
#include <cstddef>
#include <pw/core/globals.hpp> #include <pw/core/globals.hpp>
#include <pw/core/math.hpp> #include <pw/core/math.hpp>
#include <pw/core/vector.hpp> #include <pw/core/vector.hpp>
#include <type_traits>
#include <utility> #include <utility>
namespace pw { 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 { 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 diag_size{std::min(Rows, Cols)};
static constexpr unsigned int rows{Rows}; static constexpr unsigned int rows{Rows};
static constexpr unsigned int cols{Cols}; static constexpr unsigned int cols{Cols};
static constexpr bool is_square{Rows == 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 diag_type = vector<Scalar, diag_size>;
using transpose_type = matrix<Scalar, Cols, Rows>; using transpose_type = matrix<Scalar, Cols, Rows>;
using minor_type = matrix<Scalar, Cols - 1, Rows - 1>; using minor_type = matrix<Scalar, Cols - 1, Rows - 1>;
using column_type = vector<Scalar, Rows>;
vector<vector<Scalar, Cols>, Rows> m_{}; vector<vector<Scalar, Cols>, Rows> m_{};
@ -56,6 +60,14 @@ struct matrix final {
return std::forward<decltype(self)>(self).m_[r]; 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 { constexpr auto diagonal() const noexcept -> diag_type {
return [this]<std::size_t... Is>(std::index_sequence<Is...>) { return [this]<std::size_t... Is>(std::index_sequence<Is...>) {
return diag_type{(*this)[Is][Is]...}; return diag_type{(*this)[Is][Is]...};
@ -226,4 +238,16 @@ constexpr auto operator*(const matrix<ScalarA, Ra, Ca>& A,
} // namespace pw } // 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 #endif

View file

@ -40,7 +40,9 @@ concept Vector3 = (N == 3);
template <typename T, auto N> template <typename T, auto N>
concept Vector4 = (N == 4); 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 value_type = Scalar;
using size_type = decltype(N); using size_type = decltype(N);
@ -71,7 +73,7 @@ template <typename Scalar, std::size_t N> struct vector {
template <typename... Args> template <typename... Args>
static constexpr auto static constexpr auto
make(Args&&... values) noexcept -> vector<Scalar, sizeof...(Args)> { 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)...}}; return {{Scalar(values)...}};
} }
@ -84,7 +86,7 @@ template <typename Scalar, std::size_t N> struct vector {
template <typename... Args> template <typename... Args>
constexpr auto swizzle(Args&&... indices) const noexcept constexpr auto swizzle(Args&&... indices) const noexcept
-> vector<Scalar, sizeof...(Args)> { -> vector<Scalar, sizeof...(Args)> {
return {{Scalar(v_[indices])...}}; return {{Scalar{v_[indices]}...}};
} }
constexpr auto minor(std::unsigned_integral auto d0) const noexcept { 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, 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 [&]<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>{}); }(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) { 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]); return std::forward_like<decltype(self)>(self.v_[idx]);
} }

View file

@ -3,6 +3,8 @@
#include <pw/core/serialize.hpp> #include <pw/core/serialize.hpp>
#include <pw/core/vector.hpp> #include <pw/core/vector.hpp>
#include <print>
auto main() -> int { auto main() -> int {
pw::debug::d() << "pixwerx.matrix.test\n"; pw::debug::d() << "pixwerx.matrix.test\n";
@ -38,4 +40,10 @@ auto main() -> int {
auto m22_tp_col1 = m22_tp.column(1); auto m22_tp_col1 = m22_tp.column(1);
pw::debug::d() << "matrix<2,2>{1,2,3,4}.transposed().column(1) -> \n" pw::debug::d() << "matrix<2,2>{1,2,3,4}.transposed().column(1) -> \n"
<< pw::serialize::to_string(m22_tp_col1); << 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);
} }

View file

@ -6,7 +6,6 @@
#include <tuple> #include <tuple>
#include <vector> #include <vector>
auto main() -> int { auto main() -> int {
auto v2_A = pw::vector{3.2, 1.2}; auto v2_A = pw::vector{3.2, 1.2};