diff options
| author | HampusM <hampus@hampusmat.com> | 2022-03-19 13:21:54 +0100 | 
|---|---|---|
| committer | HampusM <hampus@hampusmat.com> | 2022-06-13 17:56:56 +0200 | 
| commit | 55c93fe609888be73677317978959040cf35b2ff (patch) | |
| tree | 41ee53961eb5667136432b69773ef7acf3ad8259 | |
| parent | 020303df1410d10546f53d0bfee4f48797d4f067 (diff) | |
refactor: implement matrix iterator
| -rw-r--r-- | CMakeLists.txt | 4 | ||||
| -rw-r--r-- | src/engine/graphics/string_matrix.cpp | 117 | ||||
| -rw-r--r-- | src/engine/graphics/string_matrix.hpp | 61 | ||||
| -rw-r--r-- | src/engine/matrix_iterator.hpp | 65 | ||||
| -rw-r--r-- | src/engine/matrix_iterator.tpp | 112 | ||||
| -rw-r--r-- | src/interfaces/matrix.hpp | 42 | ||||
| -rw-r--r-- | test/CMakeLists.txt | 45 | ||||
| -rw-r--r-- | test/main.cpp | 2 | ||||
| -rw-r--r-- | test/string_matrix.test.cpp | 53 | 
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); +	} +}  | 
