From 6b34c00b34bd60161577f8f9b6862d97bb21d27c Mon Sep 17 00:00:00 2001 From: BlackMATov Date: Tue, 15 Oct 2019 15:24:13 +0700 Subject: [PATCH] option combinator improvements --- README.md | 4 +- headers/ecs.hpp/ecs.hpp | 167 ++++++++++++++++++++++++++++++++-------- untests/ecs_tests.cpp | 164 ++++++++++++++++++++------------------- 3 files changed, 221 insertions(+), 114 deletions(-) diff --git a/README.md b/README.md index b198ae1..4af9d6a 100644 --- a/README.md +++ b/README.md @@ -67,7 +67,7 @@ public: >([](ecs::entity, position& p, const velocity& v) { p.x += v.dx; p.y += v.dy; - }, ecs::require{}, ecs::filter{}); + }, ecs::exists{} && !ecs::exists{}); } }; @@ -82,7 +82,7 @@ public: >([this](ecs::entity e, velocity& v) { v.dx += gravity_; v.dy += gravity_; - }, ecs::filter{}); + }, !ecs::exists{}); } private: float gravity_{}; diff --git a/headers/ecs.hpp/ecs.hpp b/headers/ecs.hpp/ecs.hpp index 2830c30..f00160c 100644 --- a/headers/ecs.hpp/ecs.hpp +++ b/headers/ecs.hpp/ecs.hpp @@ -42,24 +42,26 @@ namespace ecs_hpp class system; class registry; + template < typename T > + class exists; template < typename... Ts > - class filter_any; + class exists_any; template < typename... Ts > - class filter_all; + class exists_all; + template < typename T > + class option_neg; template < typename... Ts > - class require_any; + class option_conj; template < typename... Ts > - class require_all; - - template < typename... Ts > - using filter = filter_any; - template < typename... Ts > - using require = require_all; + class option_disj; class entity_filler; class registry_filler; +} +namespace ecs_hpp +{ using family_id = std::uint16_t; using entity_id = std::uint32_t; using priority_t = std::int32_t; @@ -1461,52 +1463,149 @@ namespace ecs_hpp // ----------------------------------------------------------------------------- // -// filter +// options // // ----------------------------------------------------------------------------- namespace ecs_hpp { + // + // traits + // + + template < typename T > + struct option { + static constexpr bool instance = false; + }; + + template < typename T > + struct option> { + static constexpr bool instance = true; + }; + template < typename... Ts > - class filter_any final { + struct option> { + static constexpr bool instance = true; + }; + + template < typename... Ts > + struct option> { + static constexpr bool instance = true; + }; + + template < typename T > + struct option> { + static constexpr bool instance = true; + }; + + template < typename... Ts > + struct option> { + static constexpr bool instance = true; + }; + + template < typename... Ts > + struct option> { + static constexpr bool instance = true; + }; + + // + // options + // + + template < typename T > + class exists final { public: - bool operator()(const const_entity& e) const noexcept { - return !(... || e.exists_component()); + bool operator()(const const_entity& e) const { + return e.exists_component(); } }; template < typename... Ts > - class filter_all final { + class exists_any final { public: - bool operator()(const const_entity& e) const noexcept { - return !(... && e.exists_component()); - } - }; -} - -// ----------------------------------------------------------------------------- -// -// require -// -// ----------------------------------------------------------------------------- - -namespace ecs_hpp -{ - template < typename... Ts > - class require_any final { - public: - bool operator()(const const_entity& e) const noexcept { + bool operator()(const const_entity& e) const { return (... || e.exists_component()); } }; template < typename... Ts > - class require_all final { + class exists_all final { public: - bool operator()(const const_entity& e) const noexcept { + bool operator()(const const_entity& e) const { return (... && e.exists_component()); } }; + + // + // combinators + // + + template < typename T > + class option_neg final { + public: + option_neg(T opt) + : opt_(std::move(opt)) {} + + bool operator()(const const_entity& e) const { + return !opt_(e); + } + private: + T opt_; + }; + + template < typename... Ts > + class option_conj final { + public: + option_conj(Ts... opts) + : opts_(std::make_tuple(std::move(opts)...)) {} + + bool operator()(const const_entity& e) const { + return std::apply([&e](auto&&... opts){ + return (... && opts(e)); + }, opts_); + } + private: + std::tuple opts_; + }; + + template < typename... Ts > + class option_disj final { + public: + option_disj(Ts... opts) + : opts_(std::make_tuple(std::move(opts)...)) {} + + bool operator()(const const_entity& e) const { + return std::apply([&e](auto&&... opts){ + return (... || opts(e)); + }, opts_); + } + private: + std::tuple opts_; + }; + + // + // operators + // + + template < typename A + , typename = std::enable_if_t::instance>> + option_neg> operator!(A&& a) { + return {std::forward(a)}; + } + + template < typename A, typename B + , typename = std::enable_if_t::instance> + , typename = std::enable_if_t::instance> > + option_conj, std::decay_t> operator&&(A&& a, B&& b) { + return {std::forward(a), std::forward(b)}; + } + + template < typename A, typename B + , typename = std::enable_if_t::instance> + , typename = std::enable_if_t::instance> > + option_disj, std::decay_t> operator||(A&& a, B&& b) { + return {std::forward(a), std::forward(b)}; + } } // ----------------------------------------------------------------------------- diff --git a/untests/ecs_tests.cpp b/untests/ecs_tests.cpp index caf5b19..aaa943c 100644 --- a/untests/ecs_tests.cpp +++ b/untests/ecs_tests.cpp @@ -1191,108 +1191,96 @@ TEST_CASE("registry") { auto e = w.create_entity(); - REQUIRE(ecs::filter<>{}(e)); - REQUIRE(ecs::filter{}(e)); - REQUIRE(ecs::filter{}(e)); - REQUIRE(ecs::filter{}(e)); + REQUIRE((!ecs::exists{})(e)); + REQUIRE((!ecs::exists{})(e)); - REQUIRE(ecs::filter_any<>{}(e)); - REQUIRE(ecs::filter_any{}(e)); - REQUIRE(ecs::filter_any{}(e)); - REQUIRE(ecs::filter_any{}(e)); + REQUIRE((!ecs::exists_any<>{})(e)); + REQUIRE((!ecs::exists_any{})(e)); + REQUIRE((!ecs::exists_any{})(e)); + REQUIRE((!ecs::exists_any{})(e)); - REQUIRE_FALSE(ecs::filter_all<>{}(e)); - REQUIRE(ecs::filter_all{}(e)); - REQUIRE(ecs::filter_all{}(e)); - REQUIRE(ecs::filter_all{}(e)); + REQUIRE_FALSE((!ecs::exists_all<>{})(e)); + REQUIRE((!ecs::exists_all{})(e)); + REQUIRE((!ecs::exists_all{})(e)); + REQUIRE((!ecs::exists_all{})(e)); e.assign_component(); - REQUIRE(ecs::filter<>{}(e)); - REQUIRE_FALSE(ecs::filter{}(e)); - REQUIRE(ecs::filter{}(e)); - REQUIRE_FALSE(ecs::filter{}(e)); + REQUIRE_FALSE((!ecs::exists{})(e)); + REQUIRE((!ecs::exists{})(e)); - REQUIRE(ecs::filter_any<>{}(e)); - REQUIRE_FALSE(ecs::filter_any{}(e)); - REQUIRE(ecs::filter_any{}(e)); - REQUIRE_FALSE(ecs::filter_any{}(e)); + REQUIRE((!ecs::exists_any<>{})(e)); + REQUIRE_FALSE((!ecs::exists_any{})(e)); + REQUIRE((!ecs::exists_any{})(e)); + REQUIRE_FALSE((!ecs::exists_any{})(e)); - REQUIRE_FALSE(ecs::filter_all<>{}(e)); - REQUIRE_FALSE(ecs::filter_all{}(e)); - REQUIRE(ecs::filter_all{}(e)); - REQUIRE(ecs::filter_all{}(e)); + REQUIRE_FALSE((!ecs::exists_all<>{})(e)); + REQUIRE_FALSE((!ecs::exists_all{})(e)); + REQUIRE((!ecs::exists_all{})(e)); + REQUIRE((!ecs::exists_all{})(e)); e.assign_component(); - REQUIRE(ecs::filter<>{}(e)); - REQUIRE_FALSE(ecs::filter{}(e)); - REQUIRE_FALSE(ecs::filter{}(e)); - REQUIRE_FALSE(ecs::filter{}(e)); + REQUIRE_FALSE((!ecs::exists{})(e)); + REQUIRE_FALSE((!ecs::exists{})(e)); - REQUIRE(ecs::filter_any<>{}(e)); - REQUIRE_FALSE(ecs::filter_any{}(e)); - REQUIRE_FALSE(ecs::filter_any{}(e)); - REQUIRE_FALSE(ecs::filter_any{}(e)); + REQUIRE((!ecs::exists_any<>{})(e)); + REQUIRE_FALSE((!ecs::exists_any{})(e)); + REQUIRE_FALSE((!ecs::exists_any{})(e)); + REQUIRE_FALSE((!ecs::exists_any{})(e)); - REQUIRE_FALSE(ecs::filter_all<>{}(e)); - REQUIRE_FALSE(ecs::filter_all{}(e)); - REQUIRE_FALSE(ecs::filter_all{}(e)); - REQUIRE_FALSE(ecs::filter_all{}(e)); + REQUIRE_FALSE((!ecs::exists_all<>{})(e)); + REQUIRE_FALSE((!ecs::exists_all{})(e)); + REQUIRE_FALSE((!ecs::exists_all{})(e)); + REQUIRE_FALSE((!ecs::exists_all{})(e)); } { ecs::registry w; auto e = w.create_entity(); - REQUIRE(ecs::require<>{}(e)); - REQUIRE_FALSE(ecs::require{}(e)); - REQUIRE_FALSE(ecs::require{}(e)); - REQUIRE_FALSE(ecs::require{}(e)); + REQUIRE_FALSE(ecs::exists{}(e)); + REQUIRE_FALSE(ecs::exists{}(e)); - REQUIRE_FALSE(ecs::require_any<>{}(e)); - REQUIRE_FALSE(ecs::require_any{}(e)); - REQUIRE_FALSE(ecs::require_any{}(e)); - REQUIRE_FALSE(ecs::require_any{}(e)); + REQUIRE_FALSE(ecs::exists_any<>{}(e)); + REQUIRE_FALSE(ecs::exists_any{}(e)); + REQUIRE_FALSE(ecs::exists_any{}(e)); + REQUIRE_FALSE(ecs::exists_any{}(e)); - REQUIRE(ecs::require_all<>{}(e)); - REQUIRE_FALSE(ecs::require_all{}(e)); - REQUIRE_FALSE(ecs::require_all{}(e)); - REQUIRE_FALSE(ecs::require_all{}(e)); + REQUIRE(ecs::exists_all<>{}(e)); + REQUIRE_FALSE(ecs::exists_all{}(e)); + REQUIRE_FALSE(ecs::exists_all{}(e)); + REQUIRE_FALSE(ecs::exists_all{}(e)); e.assign_component(); - REQUIRE(ecs::require<>{}(e)); - REQUIRE(ecs::require{}(e)); - REQUIRE_FALSE(ecs::require{}(e)); - REQUIRE_FALSE(ecs::require{}(e)); + REQUIRE(ecs::exists{}(e)); + REQUIRE_FALSE(ecs::exists{}(e)); - REQUIRE_FALSE(ecs::require_any<>{}(e)); - REQUIRE(ecs::require_any{}(e)); - REQUIRE_FALSE(ecs::require_any{}(e)); - REQUIRE(ecs::require_any{}(e)); + REQUIRE_FALSE(ecs::exists_any<>{}(e)); + REQUIRE(ecs::exists_any{}(e)); + REQUIRE_FALSE(ecs::exists_any{}(e)); + REQUIRE(ecs::exists_any{}(e)); - REQUIRE(ecs::require_all<>{}(e)); - REQUIRE(ecs::require_all{}(e)); - REQUIRE_FALSE(ecs::require_all{}(e)); - REQUIRE_FALSE(ecs::require_all{}(e)); + REQUIRE(ecs::exists_all<>{}(e)); + REQUIRE(ecs::exists_all{}(e)); + REQUIRE_FALSE(ecs::exists_all{}(e)); + REQUIRE_FALSE(ecs::exists_all{}(e)); e.assign_component(); - REQUIRE(ecs::require<>{}(e)); - REQUIRE(ecs::require{}(e)); - REQUIRE(ecs::require{}(e)); - REQUIRE(ecs::require{}(e)); + REQUIRE(ecs::exists{}(e)); + REQUIRE(ecs::exists{}(e)); - REQUIRE_FALSE(ecs::require_any<>{}(e)); - REQUIRE(ecs::require_any{}(e)); - REQUIRE(ecs::require_any{}(e)); - REQUIRE(ecs::require_any{}(e)); + REQUIRE_FALSE(ecs::exists_any<>{}(e)); + REQUIRE(ecs::exists_any{}(e)); + REQUIRE(ecs::exists_any{}(e)); + REQUIRE(ecs::exists_any{}(e)); - REQUIRE(ecs::require_all<>{}(e)); - REQUIRE(ecs::require_all{}(e)); - REQUIRE(ecs::require_all{}(e)); - REQUIRE(ecs::require_all{}(e)); + REQUIRE(ecs::exists_all<>{}(e)); + REQUIRE(ecs::exists_all{}(e)); + REQUIRE(ecs::exists_all{}(e)); + REQUIRE(ecs::exists_all{}(e)); } { ecs::registry w; @@ -1309,7 +1297,7 @@ TEST_CASE("registry") { w.for_each_component([ ](ecs::entity, position_c& p){ p = position_c{5,5}; - }, ecs::require{}); + }, ecs::exists{}); REQUIRE(e1.get_component() == position_c(5,5)); REQUIRE(e2.get_component() == position_c(0,0)); @@ -1318,7 +1306,7 @@ TEST_CASE("registry") { ](ecs::entity, position_c& p, const velocity_c& v){ p.x += v.x; p.y += v.y; - }, ecs::filter{}); + }, !ecs::exists{}); REQUIRE(e1.get_component() == position_c(5,5)); REQUIRE(e2.get_component() == position_c(1,2)); @@ -1330,7 +1318,7 @@ TEST_CASE("registry") { ](ecs::entity, position_c& p, const velocity_c& v){ p.x += v.x; p.y += v.y; - }, ecs::require{}, ecs::filter{}); + }, ecs::exists{} && !ecs::exists{}); REQUIRE(e1.get_component() == position_c(5,5)); REQUIRE(e2.get_component() == position_c(2,4)); @@ -1352,11 +1340,31 @@ TEST_CASE("registry") { const velocity_c& v = e.get_component(); p.x += v.x; p.y += v.y; - }, ecs::filter{}, ecs::require{}); + }, !ecs::exists{} && ecs::exists_all{}); REQUIRE(e1.get_component() == position_c(1,2)); REQUIRE(e2.get_component() == position_c(0,0)); } + { + ecs::registry w; + + struct ignore_disabled {}; + + auto e1 = w.create_entity(); + ecs::entity_filler(e1) + .component() + .component() + .component(0,0) + .component(1,2); + + w.for_joined_components([ + ](ecs::entity, position_c& p, const velocity_c& v){ + p.x += v.x; + p.y += v.y; + }, !ecs::exists{} || ecs::exists{}); + + REQUIRE(e1.get_component() == position_c(1,2)); + } } SECTION("systems") { { @@ -1602,7 +1610,7 @@ TEST_CASE("example") { >([](ecs::entity, position& p, const velocity& v) { p.x += v.dx; p.y += v.dy; - }, ecs::require{}, ecs::filter{}); + }, ecs::exists{} && !ecs::exists{}); } }; @@ -1617,7 +1625,7 @@ TEST_CASE("example") { >([this](ecs::entity, velocity& v) { v.dx += gravity_; v.dy += gravity_; - }, ecs::filter{}); + }, !ecs::exists{}); } private: float gravity_{};