diff options
-rw-r--r-- | .clang-format | 1 | ||||
-rw-r--r-- | lib/CMakeLists.txt | 8 | ||||
-rw-r--r-- | lib/range-v3/CMakeLists.txt | 3 | ||||
-rw-r--r-- | src/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/engine/data/vector2.cpp | 20 | ||||
-rw-r--r-- | src/engine/data/vector2.hpp | 5 | ||||
-rw-r--r-- | src/game/RLE_reader.cpp | 44 | ||||
-rw-r--r-- | src/game/cell_helper.hpp | 9 | ||||
-rw-r--r-- | src/game/cell_helper_impl.hpp | 121 | ||||
-rw-r--r-- | src/game/components/statusline.cpp | 23 | ||||
-rw-r--r-- | src/game/game.cpp | 86 | ||||
-rw-r--r-- | src/game/game.hpp | 5 | ||||
-rw-r--r-- | src/interfaces/cell_helper.hpp | 5 | ||||
-rw-r--r-- | src/util/algorithm.hpp | 38 | ||||
-rw-r--r-- | src/util/algorithm_impl.hpp | 67 | ||||
-rw-r--r-- | src/util/ranges.hpp | 47 | ||||
-rw-r--r-- | src/util/ranges_impl.hpp | 59 | ||||
-rw-r--r-- | test/CMakeLists.txt | 8 |
18 files changed, 203 insertions, 347 deletions
diff --git a/.clang-format b/.clang-format index 1c720bb..092ca5a 100644 --- a/.clang-format +++ b/.clang-format @@ -17,3 +17,4 @@ BinPackArguments: false BinPackParameters: false AlignAfterOpenBracket: AlwaysBreak BreakBeforeTernaryOperators: true +AlignOperands: AlignAfterOperator diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index eca9503..baf8680 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -40,6 +40,14 @@ FetchContent_Declare( add_subdirectory(backward) +FetchContent_Declare( + range-v3 + GIT_REPOSITORY "https://github.com/ericniebler/range-v3" + GIT_TAG 0.12.0 +) + +add_subdirectory(range-v3) + if(test) FetchContent_Declare( catch2 diff --git a/lib/range-v3/CMakeLists.txt b/lib/range-v3/CMakeLists.txt new file mode 100644 index 0000000..62596c9 --- /dev/null +++ b/lib/range-v3/CMakeLists.txt @@ -0,0 +1,3 @@ +message(STATUS "Fetching range-v3...") + +FetchContent_MakeAvailable(range-v3) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 2a98dd7..147f0e0 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -64,6 +64,7 @@ target_link_libraries_system( yacppdic ctre backward + range-v3 ) target_link_options(${PROJECT_NAME} PRIVATE -fsanitize=address) diff --git a/src/engine/data/vector2.cpp b/src/engine/data/vector2.cpp index 84986bd..80fc43c 100644 --- a/src/engine/data/vector2.cpp +++ b/src/engine/data/vector2.cpp @@ -82,11 +82,31 @@ auto Vector2::operator==(const Vector2 &rhs) const noexcept -> bool return _x == rhs._x && _y == rhs._y; } +auto Vector2::operator!=(const Vector2 &rhs) const noexcept -> bool +{ + return !(*this == rhs); +} + auto Vector2::operator<(const Vector2 &rhs) const noexcept -> bool { return std::tie(_x, _y) < std::tie(rhs._x, rhs._y); } +auto Vector2::operator>(const Vector2 &rhs) const noexcept -> bool +{ + return std::tie(_x, _y) > std::tie(rhs._x, rhs._y); +} + +auto Vector2::operator<=(const Vector2 &rhs) const noexcept -> bool +{ + return *this < rhs || *this == rhs; +} + +auto Vector2::operator>=(const Vector2 &rhs) const noexcept -> bool +{ + return *this > rhs || *this == rhs; +} + auto Vector2Hasher::operator()(const Vector2 &vector2) const noexcept -> std::size_t { std::size_t result_hash = 0; diff --git a/src/engine/data/vector2.hpp b/src/engine/data/vector2.hpp index 03c2562..da96e72 100644 --- a/src/engine/data/vector2.hpp +++ b/src/engine/data/vector2.hpp @@ -43,8 +43,13 @@ public: auto operator*(const Vector2 &rhs) const noexcept -> Vector2; auto operator==(const Vector2 &rhs) const noexcept -> bool; + auto operator!=(const Vector2 &rhs) const noexcept -> bool; auto operator<(const Vector2 &rhs) const noexcept -> bool; + auto operator>(const Vector2 &rhs) const noexcept -> bool; + + auto operator<=(const Vector2 &rhs) const noexcept -> bool; + auto operator>=(const Vector2 &rhs) const noexcept -> bool; /** * Returns Vector2({.x = 0, .y = 1}) diff --git a/src/game/RLE_reader.cpp b/src/game/RLE_reader.cpp index df2823c..79890f1 100644 --- a/src/game/RLE_reader.cpp +++ b/src/game/RLE_reader.cpp @@ -1,14 +1,19 @@ #include "RLE_reader.hpp" -#include <ctre.hpp> #include <cctype> +#include <ctre.hpp> +#include <range/v3/algorithm/find_if.hpp> +#include <range/v3/algorithm/fold_left.hpp> +#include <range/v3/range/conversion.hpp> +#include <range/v3/view/drop.hpp> +#include <range/v3/view/iota.hpp> +#include <range/v3/view/join.hpp> #include <string> #include <vector> #include "engine/data/bounds.hpp" #include "engine/data/vector2.hpp" #include "errors/RLE_reader.hpp" -#include "util/algorithm_impl.hpp" #include "util/io_impl.hpp" #include "util/string_impl.hpp" @@ -32,15 +37,14 @@ auto RLEReader::read_RLE_file(const std::filesystem::path &path) const content_lines.pop_back(); } - const auto header_line_iter = container_find( + const auto header_line_iter = ranges::find_if( content_lines, [](const std::string &line) { return ctre::starts_with<"x = \\d+, y = \\d+">(line); - // return ctre::match<"x = \\d+, y = \\d+(, rule = [a-zA-Z0-9/]+)?">(line); }); - if (header_line_iter == content_lines.end()) + if (header_line_iter == ranges::end(content_lines)) { throw InvalidRLEFileError(path, "No header line"); } @@ -64,26 +68,28 @@ auto RLEReader::read_RLE_file(const std::filesystem::path &path) const auto pattern_pos = Vector2({.x = 0, .y = 0}); - const auto first_pattern_line_iter = header_line_iter + 1; + const auto header_line_index = + static_cast<int32_t>(header_line_iter - content_lines.begin()); - for (auto pattern_line_iter = first_pattern_line_iter; - pattern_line_iter != content_lines.end(); - ++pattern_line_iter) + const auto pattern_lines = content_lines | + ranges::views::drop(header_line_index + 1) | + ranges::to<std::vector>(); + + for (const auto &pattern_line : pattern_lines) { - if (!ctre::match<"[bo$0-9!]+">(*pattern_line_iter)) + if (!ctre::match<"[bo$0-9!]+">(pattern_line)) { throw InvalidRLEFileError(path, "Invalid pattern line"); } } - auto pattern = std::string(); - - for (auto pattern_line_iter = first_pattern_line_iter; - pattern_line_iter != content_lines.end(); - ++pattern_line_iter) - { - pattern.append(*pattern_line_iter); - } + auto pattern = ranges::fold_left( + pattern_lines, + std::string(), + [](const std::string &acc, const std::string &line) + { + return acc + line; + }); auto run_count_str = std::string(); @@ -111,7 +117,7 @@ auto RLEReader::read_RLE_file(const std::filesystem::path &path) const continue; } - for (auto run_index = 0; run_index < run_count; run_index++) + for (const auto &run_index : ranges::views::iota(0, run_count)) { if (pattern_size.validate_coords(pattern_pos) != CoordsValidation::VALID) { diff --git a/src/game/cell_helper.hpp b/src/game/cell_helper.hpp index cf84a75..c54b12e 100644 --- a/src/game/cell_helper.hpp +++ b/src/game/cell_helper.hpp @@ -5,7 +5,6 @@ #include "engine/data/vector2.hpp" -#include <list> #include <memory> #include <vector> @@ -19,17 +18,17 @@ public: -> bool override; [[nodiscard]] auto - get_birth_cell_positions(const std::list<Vector2> &cell_positions) const noexcept - -> std::list<Vector2> override; + get_birth_cell_positions(const std::vector<Vector2> &cell_positions) const noexcept + -> std::vector<Vector2> override; [[nodiscard]] auto find_neighbours(const Vector2 &cell_pos) const noexcept -> std::vector<Vector2> override; private: - std::shared_ptr<IMatrix<MatrixElement>> _matrix; + const std::shared_ptr<IMatrix<MatrixElement>> _matrix; static auto _get_position_neighbours(const Vector2 &position) noexcept - -> std::list<Vector2>; + -> std::vector<Vector2>; }; #include "cell_helper_impl.hpp" diff --git a/src/game/cell_helper_impl.hpp b/src/game/cell_helper_impl.hpp index bd40794..c03b80c 100644 --- a/src/game/cell_helper_impl.hpp +++ b/src/game/cell_helper_impl.hpp @@ -2,18 +2,15 @@ #include "cell_helper.hpp" -#include "util/algorithm.hpp" - -template <typename MatrixElement> -constexpr auto has_matrix_value( - const std::shared_ptr<IMatrix<MatrixElement>> &matrix, - const MatrixElement &value) noexcept -{ - return [&matrix, &value](const Vector2 &pos) - { - return matrix->get(pos) == value; - }; -} +#include <memory> +#include <range/v3/action/insert.hpp> +#include <range/v3/action/sort.hpp> +#include <range/v3/action/unique.hpp> +#include <range/v3/algorithm/count_if.hpp> +#include <range/v3/algorithm/fold_left.hpp> +#include <range/v3/range/conversion.hpp> +#include <range/v3/view/filter.hpp> +#include <utility> template <typename MatrixElement> CellHelper<MatrixElement>::CellHelper( @@ -26,74 +23,82 @@ template <typename MatrixElement> auto CellHelper<MatrixElement>::is_cell_dying(const Vector2 &cell_pos) const noexcept -> bool { - const auto neighbour_cell_positions = - container_filter(find_neighbours(cell_pos), has_matrix_value(_matrix, 'x')); - - const auto neighbour_cell_cnt = neighbour_cell_positions.size(); + int64_t neighbour_cell_cnt = ranges::count_if( + find_neighbours(cell_pos), + [this](const Vector2 &pos) + { + return _matrix->get(pos) == 'x'; + }); return neighbour_cell_cnt < 2 || neighbour_cell_cnt >= 4; } template <typename MatrixElement> auto CellHelper<MatrixElement>::get_birth_cell_positions( - const std::list<Vector2> &cell_positions) const noexcept -> std::list<Vector2> + const std::vector<Vector2> &cell_positions) const noexcept -> std::vector<Vector2> { - auto all_empty_neighbour_positions = std::list<Vector2>(); - - for (const auto &cell_pos : cell_positions) - { - const std::vector<Vector2> empty_neighbour_positions = - container_filter(find_neighbours(cell_pos), has_matrix_value(_matrix, ' ')); - - all_empty_neighbour_positions.insert( - all_empty_neighbour_positions.end(), - empty_neighbour_positions.begin(), - empty_neighbour_positions.end()); - } - - // Remove duplicates - all_empty_neighbour_positions.sort(); - all_empty_neighbour_positions.unique(); - - auto birth_cell_positions = container_filter( - all_empty_neighbour_positions, - [this](const Vector2 &cell_pos) - { - const auto neighbour_cell_positions = container_filter( - find_neighbours(cell_pos), - has_matrix_value(_matrix, 'x')); - - return neighbour_cell_positions.size() == 3; - }); - - return birth_cell_positions; + std::vector<Vector2> empty_neighbour_positions = + ranges::fold_left( + cell_positions, + std::vector<Vector2>(), + [this](std::vector<Vector2> acc, const Vector2 &pos) + { + std::vector<Vector2> neighbours = find_neighbours(pos); + + auto empty_neighbours = + neighbours | ranges::views::filter( + [this](const Vector2 &neighbour_pos) + { + return _matrix->get(neighbour_pos) == ' '; + }); + + ranges::actions::insert(acc, acc.end(), empty_neighbours); + + return acc; + }) | + ranges::actions::sort | ranges::actions::unique; + + auto birth_cell_positions = empty_neighbour_positions | + ranges::views::filter( + [this](const Vector2 &cell_pos) + { + auto neighbours = find_neighbours(cell_pos); + + int64_t neighbour_cell_cnt = ranges::count_if( + neighbours, + [this](const Vector2 &neighbour_pos) + { + return _matrix->get(neighbour_pos) == 'x'; + }); + + return neighbour_cell_cnt == 3; + }); + + return birth_cell_positions | ranges::to<std::vector>(); } template <typename MatrixElement> auto CellHelper<MatrixElement>::find_neighbours(const Vector2 &cell_pos) const noexcept -> std::vector<Vector2> { - std::vector<Vector2> cell_positions = {}; - const auto matrix_size = Bounds({.width = _matrix->get_column_cnt(), .height = _matrix->get_row_cnt()}); const auto neighbours = _get_position_neighbours(cell_pos); - for (const auto &neighbour_pos : neighbours) - { - if (matrix_size.validate_coords(neighbour_pos) == CoordsValidation::VALID) - { - cell_positions.push_back(neighbour_pos); - } - } - - return cell_positions; + return neighbours | + ranges::views::filter( + [&matrix_size](const Vector2 &neighbour_pos) + { + return matrix_size.validate_coords(neighbour_pos) == + CoordsValidation::VALID; + }) | + ranges::to<std::vector>(); } template <typename MatrixElement> auto CellHelper<MatrixElement>::_get_position_neighbours(const Vector2 &position) noexcept - -> std::list<Vector2> + -> std::vector<Vector2> { return { position + Vector2::up(), diff --git a/src/game/components/statusline.cpp b/src/game/components/statusline.cpp index aac1c27..8344c22 100644 --- a/src/game/components/statusline.cpp +++ b/src/game/components/statusline.cpp @@ -1,12 +1,11 @@ #include "statusline.hpp" #include <fmt/color.h> +#include <range/v3/view/iota.hpp> #include <utility> #include "engine/data/vector2.hpp" #include "interfaces/matrix.hpp" -#include "util/ranges.hpp" -#include "util/ranges_impl.hpp" StatusLine::StatusLine(std::shared_ptr<ComponentMatrix> component_matrix) noexcept : _component_matrix(std::move(component_matrix)), _need_render(false) @@ -55,7 +54,8 @@ void StatusLine::set_section_status( auto pos = Vector2({.x = section_start + start, .y = 0}); - const auto column_cnt = static_cast<std::int32_t>(_component_matrix->get_column_cnt()); + const auto column_cnt = + static_cast<std::int32_t>(_component_matrix->get_column_cnt()); const auto section_length = _section_lengths[section]; @@ -73,7 +73,7 @@ void StatusLine::set_section_status( _component_matrix->set(pos, {.value = ' ', .style = section_style}); padding_remaining--; - for (auto index : IotaView(0U, padding_remaining)) + for (auto index : ranges::views::iota(0U, padding_remaining)) { pos += Vector2::right(); @@ -103,11 +103,13 @@ void StatusLine::set_section_status( _matrix_write_string( pos, - status.substr(status_offset_start, static_cast<std::uint32_t>(final_status_length))); + status.substr( + status_offset_start, + static_cast<std::uint32_t>(final_status_length))); pos = pos.to_direction(Vector2::right(), final_status_length); - for (auto index : IotaView(0U, section_style.padding_right)) + for (auto index : ranges::views::iota(0U, section_style.padding_right)) { _component_matrix->set(pos, {.value = ' '}); @@ -119,7 +121,9 @@ void StatusLine::set_section_status( set_need_render(true); } -void StatusLine::set_section_length(StatusLineSection section, std::int32_t length) noexcept +void StatusLine::set_section_length( + StatusLineSection section, + std::int32_t length) noexcept { _section_lengths[section] = length; } @@ -143,7 +147,8 @@ void StatusLine::_matrix_write_string( } } -auto StatusLine::_get_section_start_x(StatusLineSection section) const noexcept -> std::int32_t +auto StatusLine::_get_section_start_x(StatusLineSection section) const noexcept + -> std::int32_t { std::int32_t section_start = 0; @@ -169,7 +174,7 @@ void StatusLine::_clear_section(StatusLineSection section, std::int32_t start) n auto section_length = _section_lengths[section]; - for (auto index : IotaView(0, section_length - start)) + for (auto index : ranges::views::iota(0, section_length - start)) { _component_matrix->set(pos, ComponentElement({.value = ' '})); diff --git a/src/game/game.cpp b/src/game/game.cpp index a121089..86b6eac 100644 --- a/src/game/game.cpp +++ b/src/game/game.cpp @@ -1,20 +1,23 @@ #include "game.hpp" +#include <cstdlib> +#include <filesystem> #include <fmt/color.h> #include <fmt/core.h> #include <fmt/format.h> -#include <yacppdic/factory.hpp> -#include <cstdlib> -#include <filesystem> #include <iostream> #include <iterator> +#include <range/v3/action/remove.hpp> +#include <range/v3/algorithm/contains.hpp> +#include <range/v3/range/conversion.hpp> +#include <range/v3/view/filter.hpp> #include <stdexcept> #include <utility> +#include <yacppdic/factory.hpp> #include "engine/data/bounds.hpp" #include "engine/escape.hpp" #include "engine/graphics/matrix_iterator.hpp" -#include "engine/graphics/matrix_iterator_impl.hpp" #include "engine/keycodes.hpp" #include "errors/RLE_reader.hpp" #include "errors/io.hpp" @@ -24,9 +27,8 @@ #include "interfaces/input.hpp" #include "interfaces/matrix.hpp" #include "interfaces/status_manager.hpp" -#include "util/algorithm_impl.hpp" #include "util/fs.hpp" -#include "util/string_impl.hpp" +#include "util/string.hpp" Game::Game( IStatusLineFactory statusline_factory, @@ -190,7 +192,7 @@ void Game::on_start() scene_matrix->set(col_pos, col); - if (!container_has(_living_cell_positions, col_pos)) + if (!ranges::contains(_living_cell_positions, col_pos)) { _living_cell_positions.push_back(col_pos); } @@ -311,7 +313,7 @@ void Game::_on_normal_mode_update() noexcept } _set_space(matrix, position, ' '); - _living_cell_positions.remove(position); + std::erase(_living_cell_positions, position); break; } @@ -390,38 +392,7 @@ void Game::_on_normal_mode_update() noexcept _last_gen_update_time = time_now; - auto matrix = _scene->get_matrix(); - - const auto dying_cell_positions = container_filter( - _living_cell_positions, - [this](const Vector2 &cell_pos) - { - return _cell_helper->is_cell_dying(cell_pos); - }); - - auto birth_cell_positions = - _cell_helper->get_birth_cell_positions(_living_cell_positions); - - for (const auto &dying_cell_pos : dying_cell_positions) - { - _set_space(matrix, dying_cell_pos, ' '); - - const auto cell_found = container_find(_living_cell_positions, dying_cell_pos); - - if (cell_found != _living_cell_positions.end()) - { - _living_cell_positions.erase(cell_found); - } - } - - for (const auto &birth_cell_pos : birth_cell_positions) - { - if (birth_cell_pos.get_y() >= _minimum_cursor_pos_y) - { - _set_space(matrix, birth_cell_pos, 'x'); - _living_cell_positions.push_back(birth_cell_pos); - } - } + _process_next_generation(); } void Game::_on_command_mode_update() noexcept @@ -640,3 +611,38 @@ void Game::_erase_line_from_cursor() noexcept std::cout.flush(); } +void Game::_process_next_generation() noexcept +{ + const auto dying_cell_positions = + _living_cell_positions | + ranges::views::filter( + [this](const Vector2 &cell_pos) + { + return _cell_helper->is_cell_dying(cell_pos); + }) | + ranges::to<std::vector>(); + + auto birth_cell_positions = + _cell_helper->get_birth_cell_positions(_living_cell_positions); + + auto matrix = _scene->get_matrix(); + + for (const auto &dying_cell_pos : dying_cell_positions) + { + _set_space(matrix, dying_cell_pos, ' '); + + if (ranges::contains(_living_cell_positions, dying_cell_pos)) + { + ranges::actions::remove(_living_cell_positions, dying_cell_pos); + } + } + + for (const auto &birth_cell_pos : birth_cell_positions) + { + if (birth_cell_pos.get_y() >= _minimum_cursor_pos_y) + { + _set_space(matrix, birth_cell_pos, 'x'); + _living_cell_positions.push_back(birth_cell_pos); + } + } +} diff --git a/src/game/game.hpp b/src/game/game.hpp index 13e229e..9fc5237 100644 --- a/src/game/game.hpp +++ b/src/game/game.hpp @@ -29,6 +29,7 @@ class IGenerationTracker; class IRLEReader; class IStatusManager; class IUserInputObserver; + template <typename ElementType> class IMatrix; @@ -107,7 +108,7 @@ private: std::int64_t _generations_per_second = DEFAULT_GENERATIONS_PER_SECOND; - std::list<Vector2> _living_cell_positions; + std::vector<Vector2> _living_cell_positions; void _on_normal_mode_update() noexcept; @@ -129,4 +130,6 @@ private: static void _erase_entire_line() noexcept; static void _erase_line_from_cursor() noexcept; + + void _process_next_generation() noexcept; }; diff --git a/src/interfaces/cell_helper.hpp b/src/interfaces/cell_helper.hpp index 69bf8b0..38e214d 100644 --- a/src/interfaces/cell_helper.hpp +++ b/src/interfaces/cell_helper.hpp @@ -6,7 +6,6 @@ #include <yacppdic/factory.hpp> -#include <list> #include <memory> #include <vector> @@ -20,8 +19,8 @@ public: -> bool = 0; [[nodiscard]] virtual auto - get_birth_cell_positions(const std::list<Vector2> &cell_positions) const noexcept - -> std::list<Vector2> = 0; + get_birth_cell_positions(const std::vector<Vector2> &cell_positions) const noexcept + -> std::vector<Vector2> = 0; [[nodiscard]] virtual auto find_neighbours(const Vector2 &cell_pos) const noexcept -> std::vector<Vector2> = 0; diff --git a/src/util/algorithm.hpp b/src/util/algorithm.hpp deleted file mode 100644 index 60c68e2..0000000 --- a/src/util/algorithm.hpp +++ /dev/null @@ -1,38 +0,0 @@ -#pragma once - -#include "util/concepts.hpp" - -#include <concepts> - -template <typename ContainerType, typename Value> -requires Container<ContainerType> -constexpr auto container_find(const ContainerType &container, const Value &value) noexcept - -> typename ContainerType::const_iterator; - -template <typename ContainerType, typename Predicate> -requires Container<ContainerType> && - std::predicate<Predicate, typename ContainerType::value_type> -constexpr auto -container_find(const ContainerType &container, Predicate predicate) noexcept -> - typename ContainerType::const_iterator; - -template <typename ContainerType, typename Value> -requires Container<ContainerType> -constexpr auto container_has(const ContainerType &container, const Value &value) noexcept - -> bool; - -template <typename ContainerType, typename Predicate> -requires Container<ContainerType> && HasPushBack<ContainerType> && - std::predicate<Predicate, typename ContainerType::value_type> -constexpr auto -container_filter(const ContainerType &container, Predicate predicate) noexcept - -> ContainerType; - -template <typename ContainerType, typename Predicate> -requires Container<ContainerType> && - std::predicate<Predicate, typename ContainerType::value_type> -constexpr auto -container_filter(const ContainerType &container, Predicate predicate) noexcept - -> ContainerType; - -#include "algorithm_impl.hpp" diff --git a/src/util/algorithm_impl.hpp b/src/util/algorithm_impl.hpp deleted file mode 100644 index d7c5e3b..0000000 --- a/src/util/algorithm_impl.hpp +++ /dev/null @@ -1,67 +0,0 @@ -#pragma once - -#include "algorithm.hpp" - -#include <algorithm> - -template <typename ContainerType, typename Value> -requires Container<ContainerType> -constexpr auto container_find(const ContainerType &container, const Value &value) noexcept - -> typename ContainerType::const_iterator -{ - return std::find(container.begin(), container.end(), value); -} - -template <typename ContainerType, typename Predicate> -requires Container<ContainerType> && - std::predicate<Predicate, typename ContainerType::value_type> -constexpr auto -container_find(const ContainerType &container, Predicate predicate) noexcept -> - typename ContainerType::const_iterator -{ - return std::find_if(container.begin(), container.end(), predicate); -} - -template <typename ContainerType, typename Value> -requires Container<ContainerType> -constexpr auto container_has(const ContainerType &container, const Value &value) noexcept - -> bool -{ - return container_find(container, value) != container.end(); -} - -template <typename ContainerType, typename Predicate> -requires Container<ContainerType> && HasPushBack<ContainerType> && - std::predicate<Predicate, typename ContainerType::value_type> -constexpr auto -container_filter(const ContainerType &container, Predicate predicate) noexcept - -> ContainerType -{ - ContainerType filtered_container; - - std::copy_if( - std::begin(container), - std::end(container), - std::back_inserter(filtered_container), - predicate); - - return filtered_container; -} - -template <typename ContainerType, typename Predicate> -requires Container<ContainerType> && - std::predicate<Predicate, typename ContainerType::value_type> -constexpr auto -container_filter(const ContainerType &container, Predicate predicate) noexcept - -> ContainerType -{ - ContainerType filtered_container; - - std::copy_if( - std::begin(container), - std::end(container), - std::inserter(filtered_container, filtered_container.begin()), - predicate); - - return filtered_container; -} diff --git a/src/util/ranges.hpp b/src/util/ranges.hpp deleted file mode 100644 index c47c7b5..0000000 --- a/src/util/ranges.hpp +++ /dev/null @@ -1,47 +0,0 @@ -#pragma once - -#include <concepts> -#include <iterator> - -template <std::weakly_incrementable Value> -class IotaViewIterator -{ -public: - constexpr explicit IotaViewIterator(Value value) noexcept; - - constexpr auto operator++() noexcept -> const IotaViewIterator &; - constexpr auto operator++(int) noexcept -> IotaViewIterator; - - constexpr auto operator*() const noexcept -> Value; - - constexpr auto operator==(const IotaViewIterator &rhs) const noexcept -> bool; - constexpr auto operator!=(const IotaViewIterator &rhs) const noexcept -> bool; - -private: - Value _value; -}; - -/** - * A range factory that generates a sequence of elements by repeatedly incrementing an - * initial value. - * - * This class was created because C++20 ranges is a complete shitshow in Clang. - * https://github.com/llvm/llvm-project/issues/52696 - */ -template <std::weakly_incrementable Value, std::semiregular Bound> -requires std::equality_comparable_with<Value, Bound> && std::copyable<Value> -class IotaView -{ -public: - constexpr IotaView(Value value, Bound bound) noexcept; - - [[nodiscard]] constexpr auto begin() const noexcept -> IotaViewIterator<Value>; - - [[nodiscard]] constexpr auto end() const noexcept -> IotaViewIterator<Value>; - -private: - Value _value; - Bound _bound; -}; - -#include "ranges_impl.hpp" diff --git a/src/util/ranges_impl.hpp b/src/util/ranges_impl.hpp deleted file mode 100644 index 1f1a577..0000000 --- a/src/util/ranges_impl.hpp +++ /dev/null @@ -1,59 +0,0 @@ -#pragma once - -#include "ranges.hpp" - -// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) -#define IOTA_VIEW_ITERATOR(return_type) \ - template <std::weakly_incrementable Value> \ - constexpr return_type IotaViewIterator<Value> - -IOTA_VIEW_ITERATOR()::IotaViewIterator(Value value) noexcept : _value(value) {} - -IOTA_VIEW_ITERATOR(auto)::operator++() noexcept -> const IotaViewIterator & -{ - ++_value; - - return *this; -} - -IOTA_VIEW_ITERATOR(auto)::operator++(int) noexcept -> IotaViewIterator -{ - auto copy = *this; - - ++(*this); - - return copy; -} - -IOTA_VIEW_ITERATOR(auto)::operator*() const noexcept -> Value -{ - return _value; -} - -IOTA_VIEW_ITERATOR(auto)::operator==(const IotaViewIterator &rhs) const noexcept -> bool -{ - return _value == rhs._value; -} - -IOTA_VIEW_ITERATOR(auto)::operator!=(const IotaViewIterator &rhs) const noexcept -> bool -{ - return !(*this == rhs); -} - -// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) -#define IOTA_VIEW(return_type) \ - template <std::weakly_incrementable Value, std::semiregular Bound> \ - requires std::equality_comparable_with<Value, Bound> && std::copyable<Value> \ - constexpr return_type IotaView<Value, Bound> - -IOTA_VIEW()::IotaView(Value value, Bound bound) noexcept : _value(value), _bound(bound) {} - -IOTA_VIEW(auto)::begin() const noexcept -> IotaViewIterator<Value> -{ - return IotaViewIterator(_value); -} - -IOTA_VIEW(auto)::end() const noexcept -> IotaViewIterator<Value> -{ - return IotaViewIterator(_bound); -} diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 8a92723..10a5509 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -36,10 +36,16 @@ target_link_options(${PROJECT_NAME} PRIVATE -fsanitize=address) target_link_libraries( ${PROJECT_NAME} - PRIVATE GSL yacppdic Catch2::Catch2WithMain trompeloeil ) +include(${CMAKE_SOURCE_DIR}/cmake/linking.cmake) + +target_link_libraries_system( + ${PROJECT_NAME} + range-v3 +) + |