// -*- c++ -*- #pragma once #include #include #include #include template concept supports_modulo = requires(T1 t1, T2 t2) { t1 % t2; }; template concept supports_matrix = requires(T a, T b, int i) { a * b; a / b; a + b; a - b; a * i; a / i; a + i; a - i; a *= b; a /= b; a += b; a -= b; a *= i; a /= i; a += i; a -= i; a = b; a = {}; }; template requires supports_matrix class Matrix { public: Matrix() : data(T{}, N * M) { } Matrix(Matrix&& other) { *this = std::move(other); } Matrix(const Matrix& other) { *this = other; } Matrix& operator=(Matrix&& other) { data = std::move(other.data); return *this; } Matrix& operator=(const Matrix& other) { data = other.data; return *this; } T& m(std::size_t x, std::size_t y) { if(x >= N) throw std::out_of_range("Subscript x out of range."); if(y >= M) throw std::out_of_range("Subscript y out of range."); return data[x + y * N]; } const T& m(std::size_t x, std::size_t y) const { if(x >= N) throw std::out_of_range("Subscript x out of range."); if(y >= M) throw std::out_of_range("Subscript y out of range."); return data[x + y * N]; } Matrix operator+(const Matrix& other) const { Matrix m(*this); m.data += other.data; return m; } Matrix operator+(int val) { Matrix m(*this); for(auto& d : m.data) d += val; return m; } Matrix operator-(const Matrix& other) const { Matrix m(*this); m.data -= other.data; return m; } Matrix operator-(int val) { Matrix m(*this); for(auto& d : m.data) d -= val; return m; } Matrix operator%(const Matrix& other) const requires(supports_modulo) { Matrix m(*this); m.data %= other.data; return m; } Matrix operator%(int val) requires(supports_modulo) { Matrix m(*this); for(auto& d : m.data) d %= val; return m; } template Matrix operator*(const Matrix& other) const { Matrix out; for(std::size_t i = 0; i < N; ++i) { for(std::size_t j = 0; j < R; ++j) { out.m(i,j) = {}; for(std::size_t k = 0; k < M; ++k) { out.m(i,j) += m(i,k) * other.m(k,j); } } } return out; } Matrix operator*(int val) { Matrix m(*this); for(auto& d : m.data) d *= val; return m; } template Matrix operator/(const Matrix& other) const { Matrix out; for(std::size_t i = 0; i < N; ++i) { for(std::size_t j = 0; j < R; ++j) { out.m(i,j) = {}; for(std::size_t k = 0; k < M; ++k) { out.m(i,j) += m(i,k) / other.m(k,j); } } } return out; } Matrix operator/(int val) const { Matrix m(*this); for(auto& d : m.data) d /= val; return m; } struct pos_t { std::size_t x; std::size_t y; }; void Move(pos_t from, pos_t to) { m(to.x, to.x) = m(from.x, from.x); m(from.x, from.y) = {}; } std::vector Row(std::size_t n) const { if(n >= M) throw std::out_of_range("Subscript out of range."); std::vector out; for(std::size_t x = 0; x < N; ++x) { out.push_back(m(x, n)); } return out; } std::vector Column(std::size_t n) const { if(n >= N) throw std::out_of_range("Subscript out of range."); std::vector out; for(std::size_t y = 0; y < M; ++y) { out.push_back(m(n, y)); } return out; } private: // Invariant; at all times data contains w * h initialized data members std::valarray data; // default initialized to empty };