#pragma once #include #include #include #include #include #include namespace amt { namespace detail { [[nodiscard]] constexpr auto cal_index( std::size_t r, std::size_t c, [[maybe_unused]] std::size_t rs, [[maybe_unused]] std::size_t cs ) -> std::size_t { return r * cs + c; } } template struct Matrix { using value_type = T; using pointer = value_type*; using const_pointer = value_type const*; using reference = value_type&; using const_reference = value_type const&; using iterator = pointer; using const_iterator = const_pointer; using reverse_iterator = std::reverse_iterator; using const_reverse_iterator = std::reverse_iterator; using difference_type = std::ptrdiff_t; using size_type = std::size_t; template struct View { using base_type = std::conditional_t; base_type data; size_type r; size_type rows; size_type cols; constexpr reference operator[](size_type c) noexcept requires (!IsConst) { assert(c < cols && "Out of bound access"); auto const index = detail::cal_index(r, c, rows, cols); return data[index]; } constexpr const_reference operator[](size_type c) const noexcept { assert(c < cols && "Out of bound access"); auto const index = detail::cal_index(r, c, rows, cols); return data[index]; } }; constexpr Matrix() noexcept = default; Matrix(Matrix const& other) : Matrix(other.rows(), other.cols()) { std::copy(other.begin(), other.end(), begin()); } Matrix& operator=(Matrix const& other) { if (this == &other) return *this; auto temp = Matrix(other); swap(temp, *this); return *this; } constexpr Matrix(Matrix && other) noexcept : m_data(other.m_data) , m_row(other.m_row) , m_col(other.m_col) { other.m_data = nullptr; } constexpr Matrix& operator=(Matrix && other) noexcept { if (this == &other) return *this; swap(*this, other); return *this; } ~Matrix() { if (m_data) delete[] m_data; } Matrix(size_type row, size_type col) : m_data(new value_type[row * col]) , m_row(row) , m_col(col) {} Matrix(size_type row, size_type col, value_type def) : Matrix(row, col) { std::fill(begin(), end(), def); } Matrix(std::initializer_list> li) : m_row(li.size()) { for (auto const& row: li) { m_col = std::max(m_col, row.size()); } auto const size = m_row * m_col; if (size == 0) return; m_data = new value_type[size]; std::fill_n(m_data, size, 0); for (auto r = 0ul; auto const& row: li) { for (auto c = 0ul; auto const& col: row) { this->operator()(r, c++) = col; } ++r; } } constexpr bool empty() const noexcept { return size() == 0; } constexpr size_type size() const noexcept { return rows() * cols(); } constexpr size_type rows() const noexcept { return m_row; } constexpr size_type cols() const noexcept { return m_col; } constexpr auto data() noexcept -> pointer { return m_data; } constexpr auto data() const noexcept -> const_pointer { return m_data; } constexpr iterator begin() noexcept { return m_data; } constexpr iterator end() noexcept { return m_data + size(); } constexpr const_iterator begin() const noexcept { return m_data; } constexpr const_iterator end() const noexcept { return m_data + size(); } constexpr reverse_iterator rbegin() noexcept { return std::reverse_iterator(end()); } constexpr reverse_iterator rend() noexcept { return std::reverse_iterator(begin()); } constexpr const_reverse_iterator rbegin() const noexcept { return std::reverse_iterator(end()); } constexpr const_reverse_iterator rend() const noexcept { return std::reverse_iterator(begin()); } constexpr auto operator()(size_type r, size_type c) noexcept -> reference { auto const index = detail::cal_index(r, c, rows(), cols()); 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 = detail::cal_index(r, c, rows(), cols()); assert(index < size() && "Out of bound access"); return m_data[index]; } constexpr auto operator[](size_type r) noexcept -> View { assert(r < rows() && "Out of bound access"); return { .data = m_data, .r = r, .rows = m_row, .cols = m_col }; } constexpr auto operator[](size_type r) const noexcept -> View { assert(r < rows() && "Out of bound access"); return { .data = m_data, .r = r, .rows = m_row, .cols = m_col }; } friend void swap(Matrix& lhs, Matrix& rhs) noexcept { using std::swap; swap(lhs.m_data, rhs.m_data); swap(lhs.m_row, rhs.m_row); swap(lhs.m_col, rhs.m_col); } private: pointer m_data; size_type m_row{}; size_type m_col{}; }; } // namespace amt #if 0 #include namespace std { template struct formatter> { constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } auto format(amt::Matrix const& m, auto& ctx) const { std::string s = "[\n"; for (auto r = std::size_t{}; r < m.rows(); ++r) { for (auto c = std::size_t{}; c < m.cols(); ++c) { s += std::format("{}, ", m(r, c)); } s += '\n'; } s += "]"; return format_to(ctx.out(), "{}", s); } }; } // namespace std #endif