From 89611dbf027653419296591056fcaced257fdf8f Mon Sep 17 00:00:00 2001 From: BlackMATov Date: Tue, 15 Oct 2019 09:39:21 +0700 Subject: [PATCH] add filter and require options to for_each --- headers/ecs.hpp/ecs.hpp | 171 ++++++++++++++++++++++++++++---------- untests/ecs_tests.cpp | 179 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 304 insertions(+), 46 deletions(-) diff --git a/headers/ecs.hpp/ecs.hpp b/headers/ecs.hpp/ecs.hpp index 735ea10..1f0b32f 100644 --- a/headers/ecs.hpp/ecs.hpp +++ b/headers/ecs.hpp/ecs.hpp @@ -42,6 +42,21 @@ namespace ecs_hpp class system; class registry; + template < typename... Ts > + class filter_any; + template < typename... Ts > + class filter_all; + + template < typename... Ts > + class require_any; + template < typename... Ts > + class require_all; + + template < typename... Ts > + using filter = filter_any; + template < typename... Ts > + using require = require_all; + class entity_filler; class registry_filler; @@ -656,11 +671,11 @@ namespace ecs_hpp template < typename... Args > T& assign(entity_id id, Args&&... args) { if ( T* value = components_.find(id) ) { - *value = T(std::forward(args)...); + *value = T{std::forward(args)...}; return *value; } assert(!components_locker_.is_locked()); - return *components_.insert(id, T(std::forward(args)...)).first; + return *components_.insert(id, T{std::forward(args)...}).first; } template < typename... Args > @@ -669,7 +684,7 @@ namespace ecs_hpp return *value; } assert(!components_locker_.is_locked()); - return *components_.insert(id, T(std::forward(args)...)).first; + return *components_.insert(id, T{std::forward(args)...}).first; } bool exists(entity_id id) const noexcept { @@ -1330,20 +1345,20 @@ namespace ecs_hpp std::size_t entity_count() const noexcept; std::size_t entity_component_count(const const_uentity& ent) const noexcept; - template < typename F > - void for_each_entity(F&& f); - template < typename F > - void for_each_entity(F&& f) const; + template < typename F, typename... Opts > + void for_each_entity(F&& f, Opts&&... opts); + template < typename F, typename... Opts > + void for_each_entity(F&& f, Opts&&... opts) const; - template < typename T, typename F > - void for_each_component(F&& f); - template < typename T, typename F > - void for_each_component(F&& f) const; + template < typename T, typename F, typename... Opts > + void for_each_component(F&& f, Opts&&... opts); + template < typename T, typename F, typename... Opts > + void for_each_component(F&& f, Opts&&... opts) const; - template < typename... Ts, typename F > - void for_joined_components(F&& f); - template < typename... Ts, typename F > - void for_joined_components(F&& f) const; + template < typename... Ts, typename F, typename... Opts > + void for_joined_components(F&& f, Opts&&... opts); + template < typename... Ts, typename F, typename... Opts > + void for_joined_components(F&& f, Opts&&... opts) const; template < typename T, typename... Args > void add_system(priority_t priority, Args&&... args); @@ -1374,20 +1389,24 @@ namespace ecs_hpp template < typename T , typename... Ts , typename F + , typename... Opts , std::size_t I , std::size_t... Is > void for_joined_components_impl_( std::index_sequence, - F&& f); + F&& f, + Opts&&... opts); template < typename T , typename... Ts , typename F + , typename... Opts , std::size_t I , std::size_t... Is > void for_joined_components_impl_( std::index_sequence, - F&& f) const; + F&& f, + Opts&&... opts) const; template < typename T , typename... Ts @@ -1438,6 +1457,56 @@ namespace ecs_hpp }; } +// ----------------------------------------------------------------------------- +// +// filter +// +// ----------------------------------------------------------------------------- + +namespace ecs_hpp +{ + template < typename... Ts > + class filter_any final { + public: + bool operator()(const const_entity& e) const noexcept { + return !(... || e.exists_component()); + } + }; + + template < typename... Ts > + class filter_all 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 { + return (... || e.exists_component()); + } + }; + + template < typename... Ts > + class require_all final { + public: + bool operator()(const const_entity& e) const noexcept { + return (... && e.exists_component()); + } + }; +} + // ----------------------------------------------------------------------------- // // fillers @@ -1925,7 +1994,7 @@ namespace ecs_hpp template < typename T, typename... Args > void typed_applier_with_args::apply_to_component(T& component) const { std::apply([&component](const Args&... args){ - component = T(args...); + component = T{args...}; }, args_); } } @@ -2355,52 +2424,62 @@ namespace ecs_hpp return component_count; } - template < typename F > - void registry::for_each_entity(F&& f) { + template < typename F, typename... Opts > + void registry::for_each_entity(F&& f, Opts&&... opts) { detail::incremental_lock_guard lock(entity_ids_locker_); - for ( const auto id : entity_ids_ ) { - f({*this, id}); + for ( const auto e : entity_ids_ ) { + if ( uentity ent{*this, e}; (... && opts(ent)) ) { + f(ent); + } } } - template < typename F > - void registry::for_each_entity(F&& f) const { + template < typename F, typename... Opts > + void registry::for_each_entity(F&& f, Opts&&... opts) const { detail::incremental_lock_guard lock(entity_ids_locker_); - for ( const auto id : entity_ids_ ) { - f({*this, id}); + for ( const auto e : entity_ids_ ) { + if ( const_uentity ent{*this, e}; (... && opts(ent)) ) { + f(ent); + } } } - template < typename T, typename F > - void registry::for_each_component(F&& f) { + template < typename T, typename F, typename... Opts > + void registry::for_each_component(F&& f, Opts&&... opts) { if ( detail::component_storage* storage = find_storage_() ) { - storage->for_each_component([this, &f](const entity_id e, T& t){ - f(uentity{*this, e}, t); + storage->for_each_component([this, &f, &opts...](const entity_id e, T& t){ + if ( uentity ent{*this, e}; (... && opts(ent)) ) { + f(ent, t); + } }); } } - template < typename T, typename F > - void registry::for_each_component(F&& f) const { + template < typename T, typename F, typename... Opts > + void registry::for_each_component(F&& f, Opts&&... opts) const { if ( const detail::component_storage* storage = find_storage_() ) { - storage->for_each_component([this, &f](const entity_id e, const T& t){ - f(const_uentity{*this, e}, t); + storage->for_each_component([this, &f, &opts...](const entity_id e, const T& t){ + if ( const_uentity ent{*this, e}; (... && opts(ent)) ) { + f(ent, t); + } }); } } - template < typename... Ts, typename F > - void registry::for_joined_components(F&& f) { + template < typename... Ts, typename F, typename... Opts > + void registry::for_joined_components(F&& f, Opts&&... opts) { for_joined_components_impl_( std::make_index_sequence(), - std::forward(f)); + std::forward(f), + std::forward(opts)...); } - template < typename... Ts, typename F > - void registry::for_joined_components(F&& f) const { + template < typename... Ts, typename F, typename... Opts > + void registry::for_joined_components(F&& f, Opts&&... opts) const { for_joined_components_impl_( std::make_index_sequence(), - std::forward(f)); + std::forward(f), + std::forward(opts)...); } template < typename T, typename... Args > @@ -2498,11 +2577,13 @@ namespace ecs_hpp template < typename T , typename... Ts , typename F + , typename... Opts , std::size_t I , std::size_t... Is > void registry::for_joined_components_impl_( std::index_sequence, - F&& f) + F&& f, + Opts&&... opts) { const auto ss = std::make_tuple(find_storage_()...); if ( detail::tuple_contains(ss, nullptr) ) { @@ -2510,17 +2591,19 @@ namespace ecs_hpp } for_each_component([this, &f, &ss](const uentity& e, T& t) { for_joined_components_impl_(e, f, ss, t); - }); + }, std::forward(opts)...); } template < typename T , typename... Ts , typename F + , typename... Opts , std::size_t I , std::size_t... Is > void registry::for_joined_components_impl_( std::index_sequence, - F&& f) const + F&& f, + Opts&&... opts) const { const auto ss = std::make_tuple(find_storage_()...); if ( detail::tuple_contains(ss, nullptr) ) { @@ -2528,7 +2611,7 @@ namespace ecs_hpp } for_each_component([this, &f, &ss](const const_uentity& e, const T& t) { std::as_const(*this).for_joined_components_impl_(e, f, ss, t); - }); + }, std::forward(opts)...); } template < typename T diff --git a/untests/ecs_tests.cpp b/untests/ecs_tests.cpp index bc49648..7c757fd 100644 --- a/untests/ecs_tests.cpp +++ b/untests/ecs_tests.cpp @@ -27,9 +27,11 @@ namespace velocity_c(int nx, int ny) : x(nx), y(ny) {} }; - struct movable_c { - }; + struct movable_c{}; + struct disabled_c{}; + static_assert(std::is_empty_v, "!!!"); + static_assert(std::is_empty_v, "!!!"); bool operator==(const position_c& l, const position_c& r) noexcept { return l.x == r.x @@ -1174,6 +1176,179 @@ TEST_CASE("registry") { }); } } + SECTION("options") { + { + ecs::registry w; + + auto e = w.create_entity(); + + REQUIRE(ecs::filter<>{}(e)); + REQUIRE(ecs::filter{}(e)); + REQUIRE(ecs::filter{}(e)); + REQUIRE(ecs::filter{}(e)); + + REQUIRE(ecs::filter_any<>{}(e)); + REQUIRE(ecs::filter_any{}(e)); + REQUIRE(ecs::filter_any{}(e)); + REQUIRE(ecs::filter_any{}(e)); + + REQUIRE_FALSE(ecs::filter_all<>{}(e)); + REQUIRE(ecs::filter_all{}(e)); + REQUIRE(ecs::filter_all{}(e)); + REQUIRE(ecs::filter_all{}(e)); + + e.assign_component(); + + REQUIRE(ecs::filter<>{}(e)); + REQUIRE_FALSE(ecs::filter{}(e)); + REQUIRE(ecs::filter{}(e)); + REQUIRE_FALSE(ecs::filter{}(e)); + + REQUIRE(ecs::filter_any<>{}(e)); + REQUIRE_FALSE(ecs::filter_any{}(e)); + REQUIRE(ecs::filter_any{}(e)); + REQUIRE_FALSE(ecs::filter_any{}(e)); + + REQUIRE_FALSE(ecs::filter_all<>{}(e)); + REQUIRE_FALSE(ecs::filter_all{}(e)); + REQUIRE(ecs::filter_all{}(e)); + REQUIRE(ecs::filter_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(ecs::filter_any<>{}(e)); + REQUIRE_FALSE(ecs::filter_any{}(e)); + REQUIRE_FALSE(ecs::filter_any{}(e)); + REQUIRE_FALSE(ecs::filter_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)); + } + { + 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::require_any<>{}(e)); + REQUIRE_FALSE(ecs::require_any{}(e)); + REQUIRE_FALSE(ecs::require_any{}(e)); + REQUIRE_FALSE(ecs::require_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)); + + e.assign_component(); + + REQUIRE(ecs::require<>{}(e)); + REQUIRE(ecs::require{}(e)); + REQUIRE_FALSE(ecs::require{}(e)); + REQUIRE_FALSE(ecs::require{}(e)); + + REQUIRE_FALSE(ecs::require_any<>{}(e)); + REQUIRE(ecs::require_any{}(e)); + REQUIRE_FALSE(ecs::require_any{}(e)); + REQUIRE(ecs::require_any{}(e)); + + REQUIRE(ecs::require_all<>{}(e)); + REQUIRE(ecs::require_all{}(e)); + REQUIRE_FALSE(ecs::require_all{}(e)); + REQUIRE_FALSE(ecs::require_all{}(e)); + + e.assign_component(); + + REQUIRE(ecs::require<>{}(e)); + REQUIRE(ecs::require{}(e)); + REQUIRE(ecs::require{}(e)); + REQUIRE(ecs::require{}(e)); + + REQUIRE_FALSE(ecs::require_any<>{}(e)); + REQUIRE(ecs::require_any{}(e)); + REQUIRE(ecs::require_any{}(e)); + REQUIRE(ecs::require_any{}(e)); + + REQUIRE(ecs::require_all<>{}(e)); + REQUIRE(ecs::require_all{}(e)); + REQUIRE(ecs::require_all{}(e)); + REQUIRE(ecs::require_all{}(e)); + } + { + ecs::registry w; + + auto e1 = w.create_entity(); + e1.assign_component(); + e1.assign_component(0,0); + e1.assign_component(1,2); + + auto e2 = w.create_entity(); + e2.assign_component(0,0); + e2.assign_component(1,2); + + w.for_each_component([ + ](ecs::entity, position_c& p){ + p = position_c{5,5}; + }, ecs::require{}); + + REQUIRE(e1.get_component() == position_c(5,5)); + REQUIRE(e2.get_component() == position_c(0,0)); + + w.for_joined_components([ + ](ecs::entity, position_c& p, const velocity_c& v){ + p.x += v.x; + p.y += v.y; + }, ecs::filter{}); + + REQUIRE(e1.get_component() == position_c(5,5)); + REQUIRE(e2.get_component() == position_c(1,2)); + + e1.assign_component(); + e2.assign_component(); + + w.for_joined_components([ + ](ecs::entity, position_c& p, const velocity_c& v){ + p.x += v.x; + p.y += v.y; + }, ecs::require{}, ecs::filter{}); + + REQUIRE(e1.get_component() == position_c(5,5)); + REQUIRE(e2.get_component() == position_c(2,4)); + } + { + ecs::registry w; + + auto e1 = w.create_entity(); + e1.assign_component(0,0); + e1.assign_component(1,2); + + auto e2 = w.create_entity(); + e2.assign_component(); + e2.assign_component(0,0); + e2.assign_component(1,2); + + w.for_each_entity([](ecs::entity e){ + position_c& p = e.get_component(); + const velocity_c& v = e.get_component(); + p.x += v.x; + p.y += v.y; + }, ecs::filter{}, ecs::require{}); + + REQUIRE(e1.get_component() == position_c(1,2)); + REQUIRE(e2.get_component() == position_c(0,0)); + } + } SECTION("systems") { { class movement_system : public ecs::system {