diff --git a/apps/CMakeLists.txt b/apps/CMakeLists.txt index 21a8617..27a7ae7 100644 --- a/apps/CMakeLists.txt +++ b/apps/CMakeLists.txt @@ -1 +1 @@ -add_subdirectory(Struct) \ No newline at end of file +add_subdirectory(Matrix) \ No newline at end of file diff --git a/apps/Struct/CMakeLists.txt b/apps/Matrix/CMakeLists.txt similarity index 71% rename from apps/Struct/CMakeLists.txt rename to apps/Matrix/CMakeLists.txt index 0e04147..7ca47f6 100644 --- a/apps/Struct/CMakeLists.txt +++ b/apps/Matrix/CMakeLists.txt @@ -1,4 +1,4 @@ add_and_install_project_app(matrix DEPEND - lib_Struct + lib_Matrix ) \ No newline at end of file diff --git a/apps/Matrix/src/main_Matrix.cpp b/apps/Matrix/src/main_Matrix.cpp new file mode 100644 index 0000000..6d3ba59 --- /dev/null +++ b/apps/Matrix/src/main_Matrix.cpp @@ -0,0 +1,35 @@ +/** + * \brief Main application + */ +#include +#include + + + +int main() { + constexpr int def_value = 0; + Matrix::Matrix matrix; + const int N = 10; + + auto a = matrix[0][0]; + + for (int i = 0; i < N; ++i) + matrix[i][i] = matrix[N-1-i][i] = i; + + for (int row = 1; row <= 8; ++row) { + for (int col = 1; col <= 8; ++col){ + std::cout << matrix[row][col]; + col == 8 ? std::cout << std::endl : std::cout << " "; + } + } + std::cout << matrix.size() << std::endl; + + for (const auto& [key, value]: matrix){ + std::string t; + for (const auto& c: key) { + t += std::to_string(c) + " "; + } + t = t.substr(0, t.size()-1); + std::cout << "[" << t << "] : " << value << std::endl; + } +} diff --git a/apps/Struct/src/main_Struct.cpp b/apps/Struct/src/main_Struct.cpp deleted file mode 100644 index 7b393bc..0000000 --- a/apps/Struct/src/main_Struct.cpp +++ /dev/null @@ -1,8 +0,0 @@ -/** - * \brief Main application - */ -#include - -int main() { - return 0; -} diff --git a/library/CMakeLists.txt b/library/CMakeLists.txt index 21a8617..27a7ae7 100644 --- a/library/CMakeLists.txt +++ b/library/CMakeLists.txt @@ -1 +1 @@ -add_subdirectory(Struct) \ No newline at end of file +add_subdirectory(Matrix) \ No newline at end of file diff --git a/library/Struct/CMakeLists.txt b/library/Matrix/CMakeLists.txt similarity index 100% rename from library/Struct/CMakeLists.txt rename to library/Matrix/CMakeLists.txt diff --git a/library/Struct/README.MD b/library/Matrix/README.MD similarity index 100% rename from library/Struct/README.MD rename to library/Matrix/README.MD diff --git a/library/Matrix/include/Matrix/Matrix.h b/library/Matrix/include/Matrix/Matrix.h new file mode 100644 index 0000000..60a5779 --- /dev/null +++ b/library/Matrix/include/Matrix/Matrix.h @@ -0,0 +1,158 @@ +/** + * \brief main library header for Matrix + * \code + * Matrix m; // create 5D matrix of int with default value -2; + * \endcode + * Idea: + * 1. Use to represent cell with value. It takes + * 2. Overload operator[] by using matrixes with lower dimention so that it can be used in this manner + * \code + * Matrix m; + * m [1][2][3][4] = 5; + * std::cout << m[1][2][3][4] << std::endl; // print "5"; + * std::cout << m[1][2][3][3] << std::endl; // print "-1"; + * \endcode + */ +#pragma once + +#include +#include + +namespace Matrix { + +//---------------------------------- +#pragma mark Matrix Implementation +//---------------------------------- +template +class Matrix +{ + using KeyType = std::vector; + using DataType = std::map; + using MatrixType = Matrix; + + public: + + /** + * \brief Use pattern `Proxy` to get access to element + * + * \tparam ProxyDimention + */ + template + class Proxy { + public: + Proxy(MatrixType* matrix, KeyType key) + : matrix_(matrix), + const_matrix_(nullptr), + key_(key) {} + + Proxy(const MatrixType* matrix, KeyType key) + : matrix_(nullptr), + const_matrix_(matrix), + key_(key) {} + + auto operator[](const size_t idx) { + key_[MainDimension - ProxyDimention] = idx; + if (matrix_) + return Proxy{matrix_, key_}; + else + return Proxy{const_matrix_, key_}; + } + + private: + MatrixType* matrix_; + const MatrixType* const_matrix_; + KeyType key_; + }; + + /// \brief Zero-dimention proxy to contain actual value of the element + template<> + class Proxy<0> { + public: + Proxy(MatrixType* matrix, KeyType key) + : matrix_(matrix), + const_matrix_(nullptr), + key_(key) {} + + Proxy(const MatrixType* matrix, KeyType key) + : matrix_(nullptr), + const_matrix_(matrix), + key_(key) {} + + + operator ValueType() const { + if (matrix_) + return matrix_->get_value(key_); + else + return const_matrix_->get_value(key_); + } + + auto operator=(const ValueType& value) { + return matrix_->set_value(key_, value); + } + + private: + MatrixType* matrix_; + const MatrixType* const_matrix_; + KeyType key_; + }; + + Matrix() = default; + virtual ~Matrix() = default; + + // copy + Matrix(const Matrix&) = default; + Matrix& operator=(const Matrix&) = default; + + //move + Matrix(Matrix&&) = default; + Matrix& operator=(Matrix&&) = default; + + auto operator[](const size_t idx) { + KeyType key(MainDimension, 0); + key[0] = idx; + return Proxy{this, key}; + }; + + auto operator[](const size_t idx) const { + KeyType key(MainDimension, 0); + key[0] = idx; + return Proxy{this, key}; + }; + + + size_t size() const { + return data_.size(); + } + + auto begin() const { + return data_.begin(); + } + + auto end() const { + return data_.end(); + } + + private: + DataType data_; + + auto get_value(const KeyType& key) const -> const ValueType{ + auto it = data_.find(key); + if (it == data_.end()) { + return DefaultValue; + } + else { + return it->second; + } + } + auto set_value(const KeyType& key, const ValueType& value) -> ValueType { + if (value == DefaultValue){ + data_.erase(key); + } + else + data_[key] = value; + return value; + } + +}; + +} // namespace Matrix \ No newline at end of file diff --git a/library/Matrix/src/Matrix.cpp b/library/Matrix/src/Matrix.cpp new file mode 100644 index 0000000..076a0aa --- /dev/null +++ b/library/Matrix/src/Matrix.cpp @@ -0,0 +1 @@ +#include \ No newline at end of file diff --git a/library/Struct/test/CMakeLists.txt b/library/Matrix/test/CMakeLists.txt similarity index 100% rename from library/Struct/test/CMakeLists.txt rename to library/Matrix/test/CMakeLists.txt diff --git a/library/Matrix/test/src/test_Matrix.cpp b/library/Matrix/test/src/test_Matrix.cpp new file mode 100644 index 0000000..58c0ba7 --- /dev/null +++ b/library/Matrix/test/src/test_Matrix.cpp @@ -0,0 +1,107 @@ +#include + +#include +#include +#include + +TEST(Matrix, OneDimentionalMatrix) +{ + constexpr int DefaultValue = -1; + + // non-const matrix + Matrix::Matrix m; + + EXPECT_EQ(m.size(), 0); + auto a = m[0]; + EXPECT_EQ(m.size(), 0); + EXPECT_EQ(a, DefaultValue); + m[0] = 0; + EXPECT_EQ(m.size(), 1); + EXPECT_EQ(m[0], 0); + EXPECT_EQ(m[1], DefaultValue); + + m[9] = 9; + EXPECT_EQ(m[0], 0); + EXPECT_EQ(m[1], DefaultValue); + EXPECT_EQ(m[9], 9); + EXPECT_EQ(m.size(), 2); + + std::string expected = "[ 0 ] : 0\n[ 9 ] : 9\n"; + std::stringstream str; + for (const auto& item: m) { + str << "["; + for (const auto coord : item.first) + str << " " << coord; + str <<" ] : " << item.second << '\n'; + } + EXPECT_EQ(expected, str.str()); + + + // const matrix -- no change available; + const Matrix::Matrix m_const; + EXPECT_EQ(m_const.size(), 0); + EXPECT_EQ(m_const[0], DefaultValue); + EXPECT_EQ(m_const[1], DefaultValue); + + // Const matrix: construct from existing one (to pass to functions, for instance) + const Matrix::Matrix m_const2(m); + EXPECT_EQ(m_const2.size(), 2); + EXPECT_EQ(m_const2[0], 0); + EXPECT_EQ(m_const2[1], DefaultValue); + EXPECT_EQ(m_const2[9], 9); + + // const ref + m[2] = 42; + const auto& m_ref = m; + EXPECT_EQ(m_ref.size(), 3); + EXPECT_EQ(m_ref[0], 0); + EXPECT_EQ(m_ref[1], DefaultValue); + EXPECT_EQ(m_ref[9], 9); + EXPECT_EQ(m_ref[2], 42); +} + +TEST(Matix, TwoDimentionalMatrix) { + constexpr int DefaultValue = -10; + Matrix::Matrix m; + + EXPECT_EQ(m.size(), 0); + + auto a = m[0][0]; + EXPECT_EQ(a, DefaultValue); + EXPECT_EQ(m.size(), 0); // expect still empty matrix + + m[100][100] = 314; + EXPECT_EQ(m[100][100], 314); + EXPECT_EQ(m.size(), 1); + + std::string expected = "[ 100 100 ] : 314\n"; + std::stringstream str; + for (const auto& item: m) { + str << "["; + for (const auto coord : item.first) + str << " " << coord; + str <<" ] : " << item.second << '\n'; + } + EXPECT_EQ(expected, str.str()); + + + // const matrix + const Matrix::Matrix m_const; + EXPECT_EQ(m_const.size(), 0); + EXPECT_EQ(m_const[0][0], DefaultValue); + EXPECT_EQ(m_const[0][1], DefaultValue); + + // Const matrix: construct from existing one (to pass to functions, for instance) + const Matrix::Matrix m_const2(m); + EXPECT_EQ(m_const2.size(), 1); + EXPECT_EQ(m_const2[0][0], DefaultValue); + EXPECT_EQ(m_const2[100][100], 314); +} + + +int main(int argc, char** argv) { + + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); + +} \ No newline at end of file diff --git a/library/Struct/include/Struct/Struct.h b/library/Struct/include/Struct/Struct.h deleted file mode 100644 index a87ed57..0000000 --- a/library/Struct/include/Struct/Struct.h +++ /dev/null @@ -1,2 +0,0 @@ -// empty struct for future projects -#pragma once \ No newline at end of file diff --git a/library/Struct/src/Struct.cpp b/library/Struct/src/Struct.cpp deleted file mode 100644 index eabc7f4..0000000 --- a/library/Struct/src/Struct.cpp +++ /dev/null @@ -1 +0,0 @@ -#include \ No newline at end of file diff --git a/library/Struct/test/src/test_Struct.cpp b/library/Struct/test/src/test_Struct.cpp deleted file mode 100644 index e8e8c20..0000000 --- a/library/Struct/test/src/test_Struct.cpp +++ /dev/null @@ -1,13 +0,0 @@ -#include - -#include - -TEST(Struct, DummyTest) -{ - ASSERT_TRUE(true); -} - -int main(int argc, char** argv) { - testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); -} \ No newline at end of file