diff --git a/ecs.hpp b/ecs.hpp index 0b10a62..04bafb2 100644 --- a/ecs.hpp +++ b/ecs.hpp @@ -56,10 +56,62 @@ namespace ecs_hpp { namespace detail { + // + // as_const + // + template < typename T > constexpr std::add_const_t& as_const(T& t) noexcept { return t; } + + // + // tuple_tail + // + + namespace impl + { + template < typename T, typename... Ts, std::size_t... Is > + std::tuple tuple_tail_impl(std::tuple&& t, std::index_sequence iseq) { + (void)iseq; + return std::make_tuple(std::move(std::get(t))...); + } + + template < typename T, typename... Ts, std::size_t... Is > + std::tuple tuple_tail_impl(const std::tuple& t, std::index_sequence iseq) { + (void)iseq; + return std::make_tuple(std::get(t)...); + } + } + + template < typename T, typename... Ts > + std::tuple tuple_tail(std::tuple&& t) { + return impl::tuple_tail_impl(std::move(t), std::make_index_sequence()); + } + + template < typename T, typename... Ts > + std::tuple tuple_tail(const std::tuple& t) { + return impl::tuple_tail_impl(t, std::make_index_sequence()); + } + + // + // tuple_contains + // + + template < typename V > + bool tuple_contains(const std::tuple<>& t, const V& v) { + (void)t; + (void)v; + return false; + } + + template < typename V, typename T, typename... Ts > + bool tuple_contains(const std::tuple& t, const V& v) { + if ( std::get<0>(t) == v ) { + return true; + } + return tuple_contains(tuple_tail(t), v); + } } } @@ -674,34 +726,38 @@ namespace ecs_hpp template < typename T , typename... Ts , typename F - , typename S - , typename... Ss + , typename Ss , typename... Cs > void for_joined_components_impl_( const entity& e, const F& f, - detail::component_storage* s, - detail::component_storage*... ss, + const Ss& ss, Cs&... cs); template < typename T , typename... Ts , typename F - , typename S - , typename... Ss + , typename Ss , typename... Cs > void for_joined_components_impl_( const entity& e, const F& f, - const detail::component_storage* s, - const detail::component_storage*... ss, + const Ss& ss, const Cs&... cs) const; template < typename F, typename... Cs > - void for_joined_components_impl_(const entity& e, const F& f, Cs&... cs); + void for_joined_components_impl_( + const entity& e, + const F& f, + const std::tuple<>& ss, + Cs&... cs); template < typename F, typename... Cs > - void for_joined_components_impl_(const entity& e, const F& f, const Cs&... cs) const; + void for_joined_components_impl_( + const entity& e, + const F& f, + const std::tuple<>& ss, + const Cs&... cs) const; private: entity_id last_entity_id_{0u}; std::vector free_entity_ids_; @@ -1044,57 +1100,59 @@ namespace ecs_hpp : nullptr; } - template < typename T, typename... Ts, typename F, std::size_t I, std::size_t... Is > - void registry::for_joined_components_impl_(F&& f, std::index_sequence iseq) { + template < typename T + , typename... Ts + , typename F + , std::size_t I + , std::size_t... Is > + void registry::for_joined_components_impl_( + F&& f, + std::index_sequence iseq) + { (void)iseq; - for_each_component([ - this, - f = std::forward(f), - storages = std::make_tuple(find_storage_()...) - ](const entity& e, T& t) mutable { - for_joined_components_impl_( - e, - f, - std::get(storages)..., - t); - }); - } - - template < typename T, typename... Ts, typename F, std::size_t I, std::size_t... Is > - void registry::for_joined_components_impl_(F&& f, std::index_sequence iseq) const { - (void)iseq; - for_each_component([ - this, - f = std::forward(f), - storages = std::make_tuple(find_storage_()...) - ](const entity& e, const T& t) mutable { - for_joined_components_impl_( - e, - f, - std::get(storages)..., - t); - }); + const auto ss = std::make_tuple(find_storage_()...); + if ( !detail::tuple_contains(ss, nullptr) ) { + for_each_component([this, &f, &ss](const entity& e, T& t) { + for_joined_components_impl_(e, f, ss, t); + }); + } } template < typename T , typename... Ts , typename F - , typename S - , typename... Ss + , std::size_t I + , std::size_t... Is > + void registry::for_joined_components_impl_( + F&& f, + std::index_sequence iseq) const + { + (void)iseq; + const auto ss = std::make_tuple(find_storage_()...); + if ( !detail::tuple_contains(ss, nullptr) ) { + for_each_component([this, &f, &ss](const entity& e, const T& t) { + detail::as_const(*this).for_joined_components_impl_(e, f, ss, t); + }); + } + } + + template < typename T + , typename... Ts + , typename F + , typename Ss , typename... Cs > void registry::for_joined_components_impl_( const entity& e, const F& f, - detail::component_storage* s, - detail::component_storage*... ss, + const Ss& ss, Cs&... cs) { - T* c = s->find(e.id()); + T* c = std::get<0>(ss)->find(e.id()); if ( c ) { for_joined_components_impl_( e, f, - std::forward(ss)..., + detail::tuple_tail(ss), cs..., *c); } @@ -1103,34 +1161,44 @@ namespace ecs_hpp template < typename T , typename... Ts , typename F - , typename S - , typename... Ss + , typename Ss , typename... Cs > void registry::for_joined_components_impl_( const entity& e, const F& f, - const detail::component_storage* s, - const detail::component_storage*... ss, + const Ss& ss, const Cs&... cs) const { - const T* c = s->find(e.id()); + const T* c = std::get<0>(ss)->find(e.id()); if ( c ) { for_joined_components_impl_( e, f, - std::forward(ss)..., + detail::tuple_tail(ss), cs..., *c); } } template < typename F, typename... Cs > - void registry::for_joined_components_impl_(const entity& e, const F& f, Cs&... cs) { + void registry::for_joined_components_impl_( + const entity& e, + const F& f, + const std::tuple<>& ss, + Cs&... cs) + { + (void)ss; f(e, cs...); } template < typename F, typename... Cs > - void registry::for_joined_components_impl_(const entity& e, const F& f, const Cs&... cs) const { + void registry::for_joined_components_impl_( + const entity& e, + const F& f, + const std::tuple<>& ss, + const Cs&... cs) const + { + (void)ss; f(e, cs...); } } diff --git a/ecs_tests.cpp b/ecs_tests.cpp index d166053..48dfc79 100644 --- a/ecs_tests.cpp +++ b/ecs_tests.cpp @@ -41,14 +41,31 @@ namespace TEST_CASE("detail") { SECTION("get_type_id") { - REQUIRE(ecs::detail::type_family::id() == 1u); - REQUIRE(ecs::detail::type_family::id() == 1u); + using namespace ecs::detail; + REQUIRE(type_family::id() == 1u); + REQUIRE(type_family::id() == 1u); - REQUIRE(ecs::detail::type_family::id() == 2u); - REQUIRE(ecs::detail::type_family::id() == 2u); + REQUIRE(type_family::id() == 2u); + REQUIRE(type_family::id() == 2u); - REQUIRE(ecs::detail::type_family::id() == 1u); - REQUIRE(ecs::detail::type_family::id() == 2u); + REQUIRE(type_family::id() == 1u); + REQUIRE(type_family::id() == 2u); + } + SECTION("tuple_tail") { + using namespace ecs::detail; + { + REQUIRE(tuple_tail(std::make_tuple(1, 2, 3)) == std::make_tuple(2, 3)); + REQUIRE(tuple_tail(std::make_tuple(2, 3)) == std::make_tuple(3)); + REQUIRE(tuple_tail(std::make_tuple(3)) == std::make_tuple()); + } + { + const auto t1 = std::make_tuple(1); + const auto t2 = std::make_tuple(1, 2); + const auto t3 = std::make_tuple(1, 2, 3); + REQUIRE(tuple_tail(t1) == std::make_tuple()); + REQUIRE(tuple_tail(t2) == std::make_tuple(2)); + REQUIRE(tuple_tail(t3) == std::make_tuple(2, 3)); + } } SECTION("sparse_set") { using namespace ecs::detail; @@ -523,6 +540,15 @@ TEST_CASE("registry") { REQUIRE(acc2 == 16); } } + { + ecs::registry w; + auto e1 = w.create_entity(); + e1.assign_component(1, 2); + w.for_joined_components([]( + ecs::entity, const position_c&, const velocity_c&) + { + }); + } } SECTION("systems") { {