diff --git a/ecs.hpp b/ecs.hpp index 9affc02..463da10 100644 --- a/ecs.hpp +++ b/ecs.hpp @@ -98,16 +98,28 @@ namespace ecs_hpp template < typename T > class component_storage : public component_storage_base { public: + component_storage(world& owner); + template < typename... Args > void assign(entity_id id, Args&&... args); bool remove(entity_id id) noexcept override; bool exists(entity_id id) const noexcept override; T* find(entity_id id) noexcept; const T* find(entity_id id) const noexcept; + + template < typename F > + void for_each_component(F&& f) noexcept; + template < typename F > + void for_each_component(F&& f) const noexcept; private: + world& owner_; std::unordered_map components_; }; + template < typename T > + component_storage::component_storage(world& owner) + : owner_(owner) {} + template < typename T > template < typename... Args > void component_storage::assign(entity_id id, Args&&... args) { @@ -139,6 +151,22 @@ namespace ecs_hpp ? &iter->second : nullptr; } + + template < typename T > + template < typename F > + void component_storage::for_each_component(F&& f) noexcept { + for ( auto& component_pair : components_ ) { + f(entity(owner_, component_pair.first), component_pair.second); + } + } + + template < typename T > + template < typename F > + void component_storage::for_each_component(F&& f) const noexcept { + for ( auto& component_pair : components_ ) { + f(entity(owner_, component_pair.first), component_pair.second); + } + } } } @@ -258,6 +286,12 @@ namespace ecs_hpp template < typename T > const T* find_component(const entity& ent) const noexcept; + + template < typename T, typename F > + void for_each_component(F&& f) noexcept; + + template < typename T, typename F > + void for_each_component(F&& f) const noexcept; private: template < typename T > detail::component_storage* find_storage_() noexcept; @@ -436,7 +470,9 @@ namespace ecs_hpp template < typename T > T& world::get_component(const entity& ent) { - T* component = find_component(ent); + std::lock_guard guard(mutex_); + detail::component_storage* storage = find_storage_(); + T* component = storage ? storage->find(ent.id()) : nullptr; if ( component ) { return *component; } @@ -445,7 +481,9 @@ namespace ecs_hpp template < typename T > const T& world::get_component(const entity& ent) const { - const T* component = find_component(ent); + std::lock_guard guard(mutex_); + const detail::component_storage* storage = find_storage_(); + const T* component = storage ? storage->find(ent.id()) : nullptr; if ( component ) { return *component; } @@ -454,6 +492,7 @@ namespace ecs_hpp template < typename T > T* world::find_component(const entity& ent) noexcept { + std::lock_guard guard(mutex_); detail::component_storage* storage = find_storage_(); return storage ? storage->find(ent.id()) @@ -462,12 +501,31 @@ namespace ecs_hpp template < typename T > const T* world::find_component(const entity& ent) const noexcept { + std::lock_guard guard(mutex_); const detail::component_storage* storage = find_storage_(); return storage ? storage->find(ent.id()) : nullptr; } + template < typename T, typename F > + void world::for_each_component(F&& f) noexcept { + std::lock_guard guard(mutex_); + detail::component_storage* storage = find_storage_(); + if ( storage ) { + storage->for_each_component(std::forward(f)); + } + } + + template < typename T, typename F > + void world::for_each_component(F&& f) const noexcept { + std::lock_guard guard(mutex_); + const detail::component_storage* storage = find_storage_(); + if ( storage ) { + storage->for_each_component(std::forward(f)); + } + } + template < typename T > detail::component_storage* world::find_storage_() noexcept { const auto family = detail::type_family::id(); @@ -497,7 +555,7 @@ namespace ecs_hpp const auto family = detail::type_family::id(); const auto emplace_r = storages_.emplace(std::make_pair( family, - std::make_unique>())); + std::make_unique>(*this))); assert(emplace_r.second && "unexpected internal error"); return *static_cast*>( emplace_r.first->second.get()); diff --git a/ecs_tests.cpp b/ecs_tests.cpp index eeaf611..8f7d9dd 100644 --- a/ecs_tests.cpp +++ b/ecs_tests.cpp @@ -181,6 +181,9 @@ TEST_CASE("world") { w.assign_component(e1, 1, 2); w.assign_component(e2, 3, 4); + REQUIRE(e1.find_component()->y == 2); + REQUIRE(e2.find_component()->dy == 4); + { const ecs::world& ww = w; REQUIRE(ww.get_component(e1).x == 1); @@ -191,6 +194,48 @@ TEST_CASE("world") { REQUIRE_THROWS_AS(ww.get_component(e1), ecs::basic_exception); REQUIRE_THROWS_AS(ww.get_component(e2), ecs::basic_exception); + + ww.remove_all_components(e1); + ww.remove_all_components(e2); + + REQUIRE_FALSE(ww.find_component(e1)); + REQUIRE_FALSE(ww.find_component(e2)); + } + } + } + SECTION("for_each_component") { + { + ecs::world w; + + auto e1 = w.create_entity(); + auto e2 = w.create_entity(); + + e1.assign_component(1, 2); + e1.assign_component(3, 4); + e2.assign_component(5, 6); + e2.assign_component(7, 8); + + { + ecs::entity_id acc1 = 0; + int acc2 = 0; + w.for_each_component([&acc1, &acc2](ecs::entity e, position_c& p){ + acc1 += e.id(); + acc2 += p.x; + }); + REQUIRE(acc1 == e1.id() + e2.id()); + REQUIRE(acc2 == 6); + } + + { + const ecs::world& ww = w; + ecs::entity_id acc1 = 0; + int acc2 = 0; + ww.for_each_component([&acc1, &acc2](ecs::entity e, const position_c& p){ + acc1 += e.id(); + acc2 += p.x; + }); + REQUIRE(acc1 == e1.id() + e2.id()); + REQUIRE(acc2 == 6); } } }