aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHampusM <hampus@hampusmat.com>2022-03-19 13:21:54 +0100
committerHampusM <hampus@hampusmat.com>2022-06-13 17:56:56 +0200
commit55c93fe609888be73677317978959040cf35b2ff (patch)
tree41ee53961eb5667136432b69773ef7acf3ad8259
parent020303df1410d10546f53d0bfee4f48797d4f067 (diff)
refactor: implement matrix iterator
-rw-r--r--CMakeLists.txt4
-rw-r--r--src/engine/graphics/string_matrix.cpp117
-rw-r--r--src/engine/graphics/string_matrix.hpp61
-rw-r--r--src/engine/matrix_iterator.hpp65
-rw-r--r--src/engine/matrix_iterator.tpp112
-rw-r--r--src/interfaces/matrix.hpp42
-rw-r--r--test/CMakeLists.txt45
-rw-r--r--test/main.cpp2
-rw-r--r--test/string_matrix.test.cpp53
9 files changed, 430 insertions, 71 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 66bad3a..1dfce91 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -9,3 +9,7 @@ project(game-of-life CXX)
add_subdirectory(lib)
add_subdirectory(src)
+
+if("${TESTING}")
+ add_subdirectory(test)
+endif()
diff --git a/src/engine/graphics/string_matrix.cpp b/src/engine/graphics/string_matrix.cpp
index ae06755..3920b8e 100644
--- a/src/engine/graphics/string_matrix.cpp
+++ b/src/engine/graphics/string_matrix.cpp
@@ -1,30 +1,59 @@
#include "string_matrix.hpp"
+#include <iostream>
+#include <ranges>
+
StringMatrix::StringMatrix(const Bounds &bounds) noexcept
- : _rows(bounds.get_height()), _columns(bounds.get_width())
+ : _matrix(new std::string_view *[bounds.get_height()]),
+ _row_cnt(bounds.get_height()),
+ _column_cnt(bounds.get_width())
{
- _matrix.reserve(bounds.get_height());
- _matrix.assign(_matrix.capacity(), std::vector<std::string_view>(bounds.get_width()));
+ for (gsl::owner<std::string_view **> row = _matrix; row != _matrix + _row_cnt; row++)
+ {
+ *row = static_cast<gsl::owner<std::string_view *>>(
+ new std::string_view[bounds.get_width()]);
+ }
};
+StringMatrix::StringMatrix(const StringMatrix &string_matrix) noexcept
+ : _matrix(new std::string_view *[string_matrix._row_cnt]),
+ _row_cnt(string_matrix._row_cnt),
+ _column_cnt(string_matrix._column_cnt)
+{
+ _copy_matrix_from(string_matrix);
+}
+
+StringMatrix::StringMatrix(StringMatrix &&string_matrix) noexcept
+ : _matrix(string_matrix._matrix),
+ _row_cnt(string_matrix._row_cnt),
+ _column_cnt(string_matrix._column_cnt)
+{
+ string_matrix._matrix = nullptr;
+}
+
+StringMatrix::~StringMatrix() noexcept
+{
+ _delete_matrix();
+}
+
void StringMatrix::fill(std::string_view element) noexcept
{
- for (uint32_t row = 0U; row < _matrix.capacity(); row++)
+ for (auto row : *this)
{
- std::vector<std::string_view> row_vector = _matrix[row];
-
- for (uint32_t column = 0U; column < row_vector.capacity(); column++)
+ for (auto &col : row)
{
- _matrix[row][column] = element;
+ col = element;
}
}
}
std::string_view StringMatrix::get(const Vector2 &pos) const noexcept
{
+
auto x = static_cast<std::size_t>(pos.get_x());
auto y = static_cast<std::size_t>(pos.get_y());
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
return _matrix[y][x];
}
@@ -33,15 +62,79 @@ void StringMatrix::set(const Vector2 &pos, std::string_view element) noexcept
auto x = static_cast<std::size_t>(pos.get_x());
auto y = static_cast<std::size_t>(pos.get_y());
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
_matrix[y][x] = element;
}
-uint32_t StringMatrix::rows() const noexcept
+uint32_t StringMatrix::get_row_cnt() const noexcept
+{
+ return _row_cnt;
+}
+
+uint32_t StringMatrix::get_column_cnt() const noexcept
+{
+ return _column_cnt;
+}
+
+MatrixIterator<std::string_view> StringMatrix::begin() const noexcept
+{
+ return MatrixIterator(_matrix, _column_cnt);
+}
+
+MatrixIterator<std::string_view> StringMatrix::end() const noexcept
{
- return _rows;
+ return MatrixIterator(_matrix + _row_cnt, _column_cnt);
}
-uint32_t StringMatrix::columns() const noexcept
+StringMatrix &StringMatrix::operator=(const StringMatrix &rhs) noexcept
{
- return _columns;
+ if (&rhs != this)
+ {
+ _delete_matrix();
+ _matrix = nullptr;
+
+ _matrix = new std::string_view *[rhs._row_cnt];
+ _copy_matrix_from(rhs);
+ }
+
+ return *this;
+}
+
+StringMatrix &StringMatrix::operator=(StringMatrix &&rhs) noexcept
+{
+ if (&rhs != this)
+ {
+ _delete_matrix();
+ _matrix = rhs._matrix;
+ rhs._matrix = nullptr;
+ }
+
+ return *this;
+}
+
+void StringMatrix::_delete_matrix() noexcept
+{
+ for (gsl::owner<std::string_view **> row = _matrix; row != _matrix + _row_cnt; row++)
+ {
+ delete[](*row);
+ }
+
+ delete[] _matrix;
+}
+
+void StringMatrix::_copy_matrix_from(const StringMatrix &source) noexcept
+{
+ gsl::owner<std::string_view **> source_row = source._matrix;
+
+ for (gsl::owner<std::string_view **> row = _matrix; row != _matrix + _row_cnt;
+ row++, source_row++)
+ {
+ *row = static_cast<gsl::owner<std::string_view *>>(
+ new std::string_view[_column_cnt]);
+
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
+ auto *end = *source_row + _column_cnt;
+
+ std::copy(*source_row, end, *row);
+ }
}
diff --git a/src/engine/graphics/string_matrix.hpp b/src/engine/graphics/string_matrix.hpp
index 40fbb11..ff0939c 100644
--- a/src/engine/graphics/string_matrix.hpp
+++ b/src/engine/graphics/string_matrix.hpp
@@ -4,58 +4,49 @@
#include "engine/data/bounds.hpp"
#include "engine/data/vector2.hpp"
+#include "engine/matrix_iterator.hpp"
+#include <gsl/pointers>
+#include <memory>
#include <string_view>
#include <vector>
-/**
- * A Matrix.
- */
class StringMatrix : public IMatrix<std::string_view>
{
public:
- /**
- * Creates a matrix.
- *
- * @param bounds The bounds of the matrix
- */
explicit StringMatrix(const Bounds &bounds) noexcept;
- /**
- * Fills the matrix with a element.
- *
- * @param element A element
- */
+ StringMatrix(const StringMatrix &string_matrix) noexcept;
+
+ StringMatrix(StringMatrix &&string_matrix) noexcept;
+
+ ~StringMatrix() noexcept override;
+
void fill(std::string_view element) noexcept override;
- /**
- * Returns a element of the matrix.
- *
- * @param pos The position of a element
- */
[[nodiscard]] std::string_view get(const Vector2 &pos) const noexcept override;
- /**
- * Sets a element of the matrix.
- *
- * @param pos The position of a element
- * @param element A new element
- */
void set(const Vector2 &pos, std::string_view element) noexcept override;
- /**
- * Returns the number of rows the matrix has.
- */
- [[nodiscard]] uint32_t rows() const noexcept override;
+ [[nodiscard]] uint32_t get_row_cnt() const noexcept override;
+
+ [[nodiscard]] uint32_t get_column_cnt() const noexcept override;
+
+ [[nodiscard]] MatrixIterator<std::string_view> begin() const noexcept override;
- /**
- * Returns the number of columns the matrix has.
- */
- [[nodiscard]] uint32_t columns() const noexcept override;
+ [[nodiscard]] MatrixIterator<std::string_view> end() const noexcept override;
+
+ StringMatrix &operator=(const StringMatrix &rhs) noexcept;
+
+ StringMatrix &operator=(StringMatrix &&rhs) noexcept;
private:
- std::vector<std::vector<std::string_view>> _matrix;
+ gsl::owner<std::string_view **> _matrix;
+
+ uint32_t _row_cnt;
+ uint32_t _column_cnt;
+
+ void _delete_matrix() noexcept;
- uint32_t _rows;
- uint32_t _columns;
+ void _copy_matrix_from(const StringMatrix &source) noexcept;
};
diff --git a/src/engine/matrix_iterator.hpp b/src/engine/matrix_iterator.hpp
new file mode 100644
index 0000000..5d35052
--- /dev/null
+++ b/src/engine/matrix_iterator.hpp
@@ -0,0 +1,65 @@
+#pragma once
+
+#include <gsl/pointers>
+
+template <typename Element>
+class MatrixRowIterator
+{
+public:
+ using ColumnPtr = gsl::owner<Element *>;
+
+ explicit MatrixRowIterator(ColumnPtr column_ptr) noexcept;
+
+ MatrixRowIterator &operator++() noexcept;
+ MatrixRowIterator operator++(int) noexcept;
+
+ Element &operator*() const noexcept;
+
+ bool operator==(const MatrixRowIterator &rhs) const noexcept;
+ bool operator!=(const MatrixRowIterator &rhs) const noexcept;
+
+private:
+ ColumnPtr _column_ptr;
+};
+
+template <typename Element>
+class MatrixRow
+{
+public:
+ using RowPtr = gsl::owner<Element *>;
+
+ explicit MatrixRow(RowPtr row_ptr, const uint32_t &column_cnt) noexcept;
+
+ [[nodiscard]] MatrixRowIterator<Element> begin() const noexcept;
+
+ [[nodiscard]] MatrixRowIterator<Element> end() const noexcept;
+
+private:
+ RowPtr _row_ptr;
+
+ const uint32_t &_column_cnt;
+};
+
+template <typename Element>
+class MatrixIterator
+{
+public:
+ using RowPtr = gsl::owner<Element **>;
+
+ explicit MatrixIterator(RowPtr row_ptr, const uint32_t &column_cnt) noexcept;
+
+ MatrixIterator &operator++() noexcept;
+ MatrixIterator operator++(int) noexcept;
+
+ MatrixRow<Element> operator*() const noexcept;
+
+ bool operator==(const MatrixIterator &rhs) const noexcept;
+ bool operator!=(const MatrixIterator &rhs) const noexcept;
+
+private:
+ RowPtr _row_ptr;
+
+ const uint32_t &_column_cnt;
+};
+
+#include "matrix_iterator.tpp"
diff --git a/src/engine/matrix_iterator.tpp b/src/engine/matrix_iterator.tpp
new file mode 100644
index 0000000..52952c9
--- /dev/null
+++ b/src/engine/matrix_iterator.tpp
@@ -0,0 +1,112 @@
+#pragma once
+
+#include "matrix_iterator.hpp"
+
+// Matrix row iterator
+
+template <typename Element>
+MatrixRowIterator<Element>::MatrixRowIterator(ColumnPtr column_ptr) noexcept
+ : _column_ptr(column_ptr)
+{
+}
+
+template <typename Element>
+MatrixRowIterator<Element> &MatrixRowIterator<Element>::operator++() noexcept
+{
+ ++_column_ptr;
+
+ return *this;
+}
+
+template <typename Element>
+MatrixRowIterator<Element> MatrixRowIterator<Element>::operator++(int) noexcept
+{
+ auto copy = *this;
+
+ ++(*this);
+
+ return copy;
+}
+
+template <typename Element>
+Element &MatrixRowIterator<Element>::operator*() const noexcept
+{
+ return *_column_ptr;
+}
+
+template <typename Element>
+bool MatrixRowIterator<Element>::operator==(const MatrixRowIterator &rhs) const noexcept
+{
+ return _column_ptr == rhs._column_ptr;
+}
+
+template <typename Element>
+bool MatrixRowIterator<Element>::operator!=(const MatrixRowIterator &rhs) const noexcept
+{
+ return _column_ptr != rhs._column_ptr;
+}
+
+// Matrix row
+
+template <typename Element>
+MatrixRow<Element>::MatrixRow(RowPtr row_ptr, const uint32_t &column_cnt) noexcept
+ : _row_ptr(row_ptr), _column_cnt(column_cnt)
+{
+}
+
+template <typename Element>
+MatrixRowIterator<Element> MatrixRow<Element>::begin() const noexcept
+{
+ return MatrixRowIterator<Element>(_row_ptr);
+}
+
+template <typename Element>
+MatrixRowIterator<Element> MatrixRow<Element>::end() const noexcept
+{
+ return MatrixRowIterator<Element>(_row_ptr + _column_cnt);
+}
+
+// Matrix iterator
+
+template <typename Element>
+MatrixIterator<Element>::MatrixIterator(RowPtr row_ptr,
+ const uint32_t &column_cnt) noexcept
+ : _row_ptr(row_ptr), _column_cnt(column_cnt)
+{
+}
+
+template <typename Element>
+MatrixIterator<Element> &MatrixIterator<Element>::operator++() noexcept
+{
+ ++_row_ptr;
+
+ return *this;
+}
+
+template <typename Element>
+MatrixIterator<Element> MatrixIterator<Element>::operator++(int) noexcept
+{
+ auto copy = *this;
+
+ ++(*this);
+
+ return copy;
+}
+
+template <typename Element>
+MatrixRow<Element> MatrixIterator<Element>::operator*() const noexcept
+{
+ return MatrixRow(*_row_ptr, _column_cnt);
+}
+
+template <typename Element>
+bool MatrixIterator<Element>::operator==(const MatrixIterator &rhs) const noexcept
+{
+ return _row_ptr == rhs._row_ptr;
+}
+
+template <typename Element>
+bool MatrixIterator<Element>::operator!=(const MatrixIterator &rhs) const noexcept
+{
+ return _row_ptr != rhs._row_ptr;
+}
diff --git a/src/interfaces/matrix.hpp b/src/interfaces/matrix.hpp
index 44a26ed..c22c0a7 100644
--- a/src/interfaces/matrix.hpp
+++ b/src/interfaces/matrix.hpp
@@ -3,45 +3,39 @@
#include "engine/data/bounds.hpp"
#include "engine/data/vector2.hpp"
+#include "engine/matrix_iterator.hpp"
+
#include <memory>
template <typename Element>
class IMatrix
{
public:
+ IMatrix() noexcept = default;
+
+ IMatrix(const IMatrix &matrix) noexcept = default;
+
+ IMatrix(IMatrix &&matrix) noexcept = default;
+
virtual ~IMatrix() noexcept = default;
- /**
- * Fills the matrix with a element.
- *
- * @param element A element
- */
virtual void fill(Element element) noexcept = 0;
- /**
- * Returns a element of the matrix.
- *
- * @param pos The position of a element
- */
[[nodiscard]] virtual Element get(const Vector2 &pos) const noexcept = 0;
- /**
- * Sets a element of the matrix.
- *
- * @param pos The position of a element
- * @param element A new element
- */
virtual void set(const Vector2 &pos, Element element) noexcept = 0;
- /**
- * Returns the number of rows the matrix has.
- */
- [[nodiscard]] virtual uint32_t rows() const noexcept = 0;
+ [[nodiscard]] virtual uint32_t get_row_cnt() const noexcept = 0;
+
+ [[nodiscard]] virtual uint32_t get_column_cnt() const noexcept = 0;
+
+ [[nodiscard]] virtual MatrixIterator<std::string_view> begin() const noexcept = 0;
+
+ [[nodiscard]] virtual MatrixIterator<std::string_view> end() const noexcept = 0;
+
+ IMatrix &operator=(const IMatrix &matrix) noexcept = default;
- /**
- * Returns the number of columns the matrix has.
- */
- [[nodiscard]] virtual uint32_t columns() const noexcept = 0;
+ IMatrix &operator=(IMatrix &&matrix) noexcept = default;
};
template <typename Element>
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
new file mode 100644
index 0000000..ac84f42
--- /dev/null
+++ b/test/CMakeLists.txt
@@ -0,0 +1,45 @@
+file(GLOB SOURCES
+ main.cpp
+ string_matrix.test.cpp
+ ${CMAKE_SOURCE_DIR}/src/engine/data/vector2.cpp
+ ${CMAKE_SOURCE_DIR}/src/engine/data/bounds.cpp
+ ${CMAKE_SOURCE_DIR}/src/engine/graphics/string_matrix.cpp
+)
+
+add_executable(tests ${SOURCES})
+
+target_compile_features(tests PUBLIC cxx_std_20)
+
+target_compile_options(
+ tests
+ PRIVATE
+ -Wall -Wextra -Wpedantic -Wshadow
+ -Wold-style-cast -Wcast-align -Wno-unused
+ -Wconversion -Wcast-qual -Wctor-dtor-privacy
+ -Wdisabled-optimization -Wformat=2 -Winit-self
+ -Wmissing-declarations -Wmissing-include-dirs
+ -Woverloaded-virtual -Wredundant-decls
+ -Wsign-conversion -Wsign-promo
+ -Wstrict-overflow=5 -Wswitch-default
+ -Wundef -Werror
+ -pedantic -fsanitize=address -fno-exceptions
+)
+
+if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
+ target_compile_options(
+ tests
+ PRIVATE
+ -Wlogical-op -Wnoexcept -Wstrict-null-sentinel
+ )
+endif()
+
+target_include_directories(
+ tests
+ PRIVATE
+ "${CMAKE_SOURCE_DIR}/src"
+ "${CMAKE_SOURCE_DIR}/test"
+)
+
+target_link_libraries(tests GSL doctest)
+
+target_link_options(tests PRIVATE -fsanitize=address)
diff --git a/test/main.cpp b/test/main.cpp
new file mode 100644
index 0000000..0a3f254
--- /dev/null
+++ b/test/main.cpp
@@ -0,0 +1,2 @@
+#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN
+#include <doctest/doctest.h>
diff --git a/test/string_matrix.test.cpp b/test/string_matrix.test.cpp
new file mode 100644
index 0000000..522a274
--- /dev/null
+++ b/test/string_matrix.test.cpp
@@ -0,0 +1,53 @@
+#include "engine/graphics/string_matrix.hpp"
+#include "engine/data/bounds.hpp"
+
+#include <doctest/doctest.h>
+#include <type_traits>
+
+constexpr uint32_t MATRIX_WIDTH = 76;
+constexpr uint32_t MATRIX_HEIGHT = 31;
+
+TEST_CASE("String matrix")
+{
+ auto string_matrix =
+ StringMatrix(Bounds({.width = MATRIX_WIDTH, .height = MATRIX_HEIGHT}));
+
+ SUBCASE("Can set & get elements")
+ {
+ // NOLINTNEXTLINE(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers)
+ const auto position = Vector2({.x = 56, .y = 20});
+
+ string_matrix.set(position, "#");
+
+ CHECK(string_matrix.get(position) == "#");
+ }
+
+ SUBCASE("Can iterate")
+ {
+ CHECK(std::is_same_v<decltype(string_matrix.begin()),
+ MatrixIterator<std::string_view>>);
+
+ CHECK(std::is_same_v<decltype(string_matrix.end()),
+ MatrixIterator<std::string_view>>);
+
+ uint32_t row_iter_cnt = 0;
+
+ for (auto row : string_matrix)
+ {
+ row_iter_cnt++;
+
+ CHECK(std::is_same_v<decltype(row), MatrixRow<std::string_view>>);
+
+ uint32_t col_iter_cnt = 0;
+
+ for (auto &col : row)
+ {
+ col_iter_cnt++;
+ }
+
+ CHECK(col_iter_cnt == MATRIX_WIDTH);
+ }
+
+ CHECK(row_iter_cnt == MATRIX_HEIGHT);
+ }
+}