From 4b97a0eb6c9ef2a0e8f53dd7d6f89129d8467fac Mon Sep 17 00:00:00 2001 From: Nao Pross Date: Sat, 23 Feb 2019 14:56:30 +0100 Subject: Add initializer_list constructor to basic_matrix and matrix test --- include/mmmatrix.hpp | 148 ++++++++++++++++++++++++++++++++---------------- test/CMakeLists.txt | 32 +++++++++++ test/matrix_example.cpp | 13 +++++ 3 files changed, 143 insertions(+), 50 deletions(-) create mode 100644 test/matrix_example.cpp diff --git a/include/mmmatrix.hpp b/include/mmmatrix.hpp index d18f3f1..b973aba 100644 --- a/include/mmmatrix.hpp +++ b/include/mmmatrix.hpp @@ -13,12 +13,13 @@ #include #include +#include +#include namespace mm { template class basic_matrix; - template class matrix; @@ -43,73 +44,102 @@ public: static constexpr std::size_t rows = Rows; static constexpr std::size_t cols = Cols; + // from initializer_list + basic_matrix(std::initializer_list> l); + + // copyable and movable basic_matrix(const basic_matrix& other); basic_matrix(basic_matrix&& other); + // copy from another matrix template basic_matrix(const basic_matrix& other); + // copy or move from 2D array basic_matrix(const T (& values)[Rows][Cols]); basic_matrix(T (&& values)[Rows][Cols]); // access data T& at(std::size_t row, std::size_t col); + const T& at(std::size_t row, std::size_t col) const; auto&& operator[](std::size_t index); void swap_rows(std::size_t x, std::size_t y); void swap_cols(std::size_t x, std::size_t y); // mathematical operations - basic_matrix transposed(); - inline basic_matrix trd() { return transposed(); } + basic_matrix transposed() const; + inline basic_matrix trd() const { return transposed(); } - // bool is_invertible(); - // bool invert(); - // basic_matrix inverse(); + // bool is_invertible() const; + // basic_matrix inverse() const; /// downcast to square matrix - inline constexpr bool is_square() { return (Rows == Cols); } - inline constexpr square_matrix to_square() { + inline constexpr bool is_square() const { return (Rows == Cols); } + inline constexpr square_matrix to_square() const { static_assert(is_square()); return static_cast>(*this); } /// downcast to row_vector - inline constexpr bool is_row_vec() { return (Cols == 1); } - inline constexpr row_vec to_row_vec() { + inline constexpr bool is_row_vec() const { return (Cols == 1); } + inline constexpr row_vec to_row_vec() const { static_assert(is_row_vec()); return static_cast>(*this); } /// downcast to col_vector - inline constexpr bool is_col_vec() { return (Rows == 1); } - inline constexpr col_vec to_col_vec() { + inline constexpr bool is_col_vec() const { return (Rows == 1); } + inline constexpr col_vec to_col_vec() const { static_assert(is_col_vec()); return static_cast>(*this); } private: - T data[Rows][Cols] = {}; + T data[Rows * Cols] = {}; }; template -mm::basic_matrix::basic_matrix(const mm::basic_matrix& other) { - for (int row = 0; row < Rows; row++) - for (int col = 0; col < Cols; col++) - data[row][col] = other.data[row][col]; +mm::basic_matrix::basic_matrix( + std::initializer_list> l +) { + assert(l.size() == Rows); + + auto row_it = l.begin(); + for (unsigned row = 0; (row < Rows) && (row_it != l.end()); row++) { + assert((*row_it).size() == Cols); + + auto col_it = (*row_it).begin(); + for (unsigned col = 0; (col < Cols) && (col_it != (*row_it).end()); col++) { + this->at(row, col) = *col_it; + ++col_it; + } + ++row_it; + } +} + +template +mm::basic_matrix::basic_matrix( + const mm::basic_matrix& other +) { + std::memcpy(&data, &other.data, sizeof(data)); } template -mm::basic_matrix::basic_matrix(mm::basic_matrix&& other) { +mm::basic_matrix::basic_matrix( + mm::basic_matrix&& other +) { data = other.data; } template template -mm::basic_matrix::basic_matrix(const mm::basic_matrix& other) { +mm::basic_matrix::basic_matrix( + const mm::basic_matrix& other +) { static_assert((ORows <= Rows), "cannot copy a taller matrix into a smaller one" ); @@ -118,9 +148,7 @@ mm::basic_matrix::basic_matrix(const mm::basic_matrix @@ -138,20 +166,32 @@ mm::basic_matrix::basic_matrix(T (&& values)[Rows][Cols]) { template T& mm::basic_matrix::at(std::size_t row, std::size_t col) { - static_assert(row < Rows, "out of row bound"); - static_assert(col < Cols, "out of column bound"); + assert(row < Rows); // "out of row bound" + assert(col < Cols); // "out of column bound" + + return data[row * Cols + col]; +} + +template +const T& mm::basic_matrix::at(std::size_t row, std::size_t col) const { + assert(row < Rows); // "out of row bound" + assert(col < Cols); // "out of column bound" - return data[row][col]; + return data[row * Cols + col]; } template auto&& mm::basic_matrix::operator[](std::size_t index) { - if constexpr (is_row_vec()) - return data[0][index]; - else if constexpr (is_col_vec()) - return data[index][0]; + if constexpr (is_row_vec()) { + static_assert(index < Rows); + return data[index]; + } else if constexpr (is_col_vec()) { + static_assert(index < Cols); + return data[index]; + } - return row_vec(std::move(data[index])); + // TODO: fix + // return row_vec(std::move(data[index])); } template @@ -159,8 +199,8 @@ void mm::basic_matrix::swap_rows(std::size_t x, std::size_t y) { if (x == y) return; - for (int col = 0; col < Cols; col++) - std::swap(data[x][col], data[y][col]); + for (unsigned col = 0; col < Cols; col++) + std::swap(this->at(x, col), this->at(y, col)); } template @@ -168,17 +208,17 @@ void mm::basic_matrix::swap_cols(std::size_t x, std::size_t y) { if (x == y) return; - for (int row = 0; row < rows; row++) - std::swap(data[row][x], data[row][y]); + for (unsigned row = 0; row < rows; row++) + std::swap(this->at(row, x), this->at(row, y)); } template -mm::basic_matrix mm::basic_matrix::transposed() { +mm::basic_matrix mm::basic_matrix::transposed() const { mm::basic_matrix result; - for (int row = 0; row < M; row++) - for (int col = 0; col < N; col++) - result[row][col] = this[col][row]; + for (unsigned row = 0; row < M; row++) + for (unsigned col = 0; col < N; col++) + result.at(row, col) = this->at(row, col); return result; } @@ -192,8 +232,8 @@ mm::basic_matrix operator+( ) { mm::basic_matrix result; - for (int row = 0; row < Rows; row++) - for (int col = 0; col < Cols; col++) + for (unsigned row = 0; row < Rows; row++) + for (unsigned col = 0; col < Cols; col++) result.at(row, col) = a.at(row, col) + a.at(row, col); return result; @@ -205,8 +245,8 @@ mm::basic_matrix operator*( const T& scalar ) { mm::basic_matrix result; - for (int row = 0; row < Rows; row++) - for (int col = 0; col < Cols; col++) + for (unsigned row = 0; row < Rows; row++) + for (unsigned col = 0; col < Cols; col++) result.at(row, col) = m.at(row, col) * scalar; return result; @@ -228,8 +268,8 @@ mm::basic_matrix operator*( mm::basic_matrix result; // TODO: use a more efficient algorithm - for (int row = 0; row < M; row++) - for (int col = 0; col < N; col++) + for (unsigned row = 0; row < M; row++) + for (unsigned col = 0; col < N; col++) for (int k = 0; k < P; k++) result.at(row, col) = a.at(row, k) * b.at(k, col); @@ -247,12 +287,12 @@ mm::basic_matrix operator-( template std::ostream& operator<<(std::ostream& os, const mm::basic_matrix& m) { - for (int row = 0; row < Rows; row++) { + for (unsigned row = 0; row < Rows; row++) { os << "[ "; - for (int col = 0; col < (Cols -1); col++) { - os << m.at(row, col); + for (unsigned col = 0; col < (Cols -1); col++) { + os << m.at(row, col) << ", "; } - os << m.at(Rows -1, Cols -1) << " ]\n"; + os << m.at(row, (Cols -1)) << " ]\n"; } return os; @@ -275,8 +315,8 @@ public: template void mm::square_matrix::transpose() { - for (int row = 0; row < N; row++) - for (int col = 0; col < row; col++) + for (unsigned row = 0; row < N; row++) + for (unsigned col = 0; col < row; col++) std::swap(this->at(row, col), this->at(col, row)); } @@ -285,10 +325,18 @@ void mm::square_matrix::transpose() { template class mm::row_vec : public mm::basic_matrix { public: + using mm::basic_matrix::basic_matrix; }; /* column vector specialization */ template class mm::col_vec : public mm::basic_matrix { public: + using mm::basic_matrix::basic_matrix; +}; + +template +class mm::matrix : public mm::basic_matrix { +public: + using mm::basic_matrix::basic_matrix; }; diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index e80e737..89e7c47 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -1,3 +1,4 @@ +# vectors example add_executable(vec_example vec_example.cpp ) @@ -26,3 +27,34 @@ target_link_libraries(vec_example PRIVATE MM::mm ) + + +# matrix example +add_executable(matrix_example + matrix_example.cpp +) + +target_compile_options(matrix_example + PRIVATE + $<$: + -pedantic -Wall -Wextra -Wcast-qual -Wcast-align -Wpointer-arith + -Winit-self -Wshadow -Wswitch-enum -Wredundant-decls -Wfloat-equal + -Wundef -Wvla -Wconversion -Wstrict-aliasing + > + $<$:/W4> +) + +target_compile_features(matrix_example + PRIVATE + cxx_std_17 +) + +target_include_directories(matrix_example + PRIVATE + ${MM_INCLUDE_DIRS} +) + +target_link_libraries(matrix_example + PRIVATE + MM::mm +) diff --git a/test/matrix_example.cpp b/test/matrix_example.cpp new file mode 100644 index 0000000..3fb7c78 --- /dev/null +++ b/test/matrix_example.cpp @@ -0,0 +1,13 @@ +#include "mmmatrix.hpp" + +#include +#include + +int main(int argc, char *argv[]) { + std::cout << "MxN dimensional (int) matrices" << std::endl; + mm::matrix m {{1, 2}, {3, 4}, {5, 6}}; + + std::cout << m; + + return 0; +} -- cgit v1.2.1