#pragma once #include #include #include #include namespace amt { template requires std::is_integral_v struct Matrix { using base_type = std::vector; using value_type = typename base_type::value_type; using pointer = typename base_type::pointer; using const_pointer = typename base_type::const_pointer; using reference = typename base_type::reference; using const_reference = typename base_type::const_reference; using iterator = typename base_type::iterator; using const_iterator = typename base_type::const_iterator; using size_type = std::size_t; template struct View { using base_type = std::conditional_t; base_type data; size_type size; constexpr reference operator[](size_type k) noexcept requires (!IsConst) { assert(k < size && "Out of bound access"); return data[k]; } constexpr const_reference operator[](size_type k) const noexcept { assert(k < size && "Out of bound access"); return data[k]; } }; constexpr Matrix() noexcept = default; constexpr Matrix(Matrix const&) = default; constexpr Matrix& operator=(Matrix const&) = default; constexpr Matrix(Matrix &&) noexcept = default; constexpr Matrix& operator=(Matrix &&) noexcept = default; constexpr ~Matrix() = default; Matrix(size_type row, size_type col, value_type def = {}) : m_data(row * col, def) , m_row(row) , m_col(col) {} constexpr bool empty() const noexcept { return m_data.empty(); }; constexpr size_type size() const noexcept { return m_data.size(); }; constexpr size_type rows() const noexcept { return m_row; }; constexpr size_type cols() const noexcept { return m_col; }; constexpr iterator begin() noexcept { return m_data.begin(); } constexpr iterator end() noexcept { return m_data.end(); } constexpr const_iterator begin() const noexcept { return m_data.begin(); } constexpr const_iterator end() const noexcept { return m_data.end(); } constexpr auto operator()(size_type r, size_type c) noexcept -> reference { auto const index = r * m_col + c; // column-major; assert(index < size() && "Out of bound access"); return m_data[index]; } constexpr auto operator()(size_type r, size_type c) const noexcept -> const_reference { auto const index = r * m_col + c; // column-major; assert(index < size() && "Out of bound access"); return m_data[index]; } constexpr auto operator[](size_type r) noexcept -> View { auto const base = r * m_col; assert(r < rows() && "Out of bound access"); return { .data = m_data.data() + base, .size = m_col }; } constexpr auto operator[](size_type r) const noexcept -> View { auto const base = r * m_col; assert(r < rows() && "Out of bound access"); return { .data = m_data.data() + base, .size = m_col }; } friend std::ostream& operator<<(std::ostream& os, Matrix const& m) { os << "[\n"; for (auto i = size_type{}; i < m.rows(); ++i) { for (auto j = size_type{}; j < m.cols(); ++j) { os << m[i][j] << ", "; } os << '\n'; } return os << "]"; } private: base_type m_data; size_type m_row{}; size_type m_col{}; }; } // namespace amt