diff --git a/ecs.hpp b/ecs.hpp index 9d10a25..b721715 100644 --- a/ecs.hpp +++ b/ecs.hpp @@ -659,103 +659,142 @@ namespace ecs_hpp virtual std::size_t memory_usage() const noexcept = 0; }; - template < typename T > + template < typename T, bool E = std::is_empty::value > class component_storage final : public component_storage_base { public: - component_storage(registry& owner); + component_storage(registry& owner) + : owner_(owner) {} template < typename... Args > - T& assign(entity_id id, Args&&... args); - bool exists(entity_id id) const noexcept; - bool remove(entity_id id) noexcept override; + T& assign(entity_id id, Args&&... args) { + components_.insert_or_assign(id, T(std::forward(args)...)); + return components_.get(id); + } - T* find(entity_id id) noexcept; - const T* find(entity_id id) const noexcept; + bool exists(entity_id id) const noexcept { + return components_.has(id); + } - std::size_t count() const noexcept; - bool has(entity_id id) const noexcept override; - void clone(entity_id from, entity_id to) override; + bool remove(entity_id id) noexcept override { + return components_.unordered_erase(id); + } + + T* find(entity_id id) noexcept { + return components_.find(id); + } + + const T* find(entity_id id) const noexcept { + return components_.find(id); + } + + std::size_t count() const noexcept { + return components_.size(); + } + + bool has(entity_id id) const noexcept override { + return components_.has(id); + } + + void clone(entity_id from, entity_id to) override { + const T* c = components_.find(from); + if ( c ) { + components_.insert_or_assign(to, *c); + } + } template < typename F > - void for_each_component(F&& f); - template < typename F > - void for_each_component(F&& f) const; + void for_each_component(F&& f) { + for ( const entity_id id : components_ ) { + f(id, components_.get(id)); + } + } - std::size_t memory_usage() const noexcept override; + template < typename F > + void for_each_component(F&& f) const { + for ( const entity_id id : components_ ) { + f(id, components_.get(id)); + } + } + + std::size_t memory_usage() const noexcept override { + return components_.memory_usage(); + } private: registry& owner_; detail::sparse_map components_; }; template < typename T > - component_storage::component_storage(registry& owner) - : owner_(owner) {} + class component_storage final : public component_storage_base { + public: + component_storage(registry& owner) + : owner_(owner) {} - template < typename T > - template < typename... Args > - T& component_storage::assign(entity_id id, Args&&... args) { - components_.insert_or_assign(id, T(std::forward(args)...)); - return components_.get(id); - } - - template < typename T > - bool component_storage::exists(entity_id id) const noexcept { - return components_.has(id); - } - - template < typename T > - bool component_storage::remove(entity_id id) noexcept { - return components_.unordered_erase(id); - } - - template < typename T > - T* component_storage::find(entity_id id) noexcept { - return components_.find(id); - } - - template < typename T > - const T* component_storage::find(entity_id id) const noexcept { - return components_.find(id); - } - - template < typename T > - std::size_t component_storage::count() const noexcept { - return components_.size(); - } - - template < typename T > - bool component_storage::has(entity_id id) const noexcept { - return components_.has(id); - } - - template < typename T > - void component_storage::clone(entity_id from, entity_id to) { - const T* c = components_.find(from); - if ( c ) { - components_.insert_or_assign(to, *c); + template < typename... Args > + T& assign(entity_id id, Args&&... args) { + components_.insert(id); + return empty_value_; } - } - template < typename T > - template < typename F > - void component_storage::for_each_component(F&& f) { - for ( const entity_id id : components_ ) { - f(id, components_.get(id)); + bool exists(entity_id id) const noexcept { + return components_.has(id); } - } - template < typename T > - template < typename F > - void component_storage::for_each_component(F&& f) const { - for ( const entity_id id : components_ ) { - f(id, components_.get(id)); + bool remove(entity_id id) noexcept override { + return components_.unordered_erase(id); } - } + + T* find(entity_id id) noexcept { + return components_.has(id) + ? &empty_value_ + : nullptr; + } + + const T* find(entity_id id) const noexcept { + return components_.has(id) + ? &empty_value_ + : nullptr; + } + + std::size_t count() const noexcept { + return components_.size(); + } + + bool has(entity_id id) const noexcept override { + return components_.has(id); + } + + void clone(entity_id from, entity_id to) override { + if ( components_.has(from) ) { + components_.insert(to); + } + } + + template < typename F > + void for_each_component(F&& f) { + for ( const entity_id id : components_ ) { + f(id, empty_value_); + } + } + + template < typename F > + void for_each_component(F&& f) const { + for ( const entity_id id : components_ ) { + f(id, empty_value_); + } + } + + std::size_t memory_usage() const noexcept override { + return components_.memory_usage(); + } + private: + registry& owner_; + static T empty_value_; + detail::sparse_set components_; + }; template < typename T > - std::size_t component_storage::memory_usage() const noexcept { - return components_.memory_usage(); - } + T component_storage::empty_value_; } } diff --git a/ecs_tests.cpp b/ecs_tests.cpp index 0f6c56b..0220f3f 100644 --- a/ecs_tests.cpp +++ b/ecs_tests.cpp @@ -28,6 +28,10 @@ namespace velocity_c(int nx, int ny) : x(nx), y(ny) {} }; + struct movable_c { + }; + static_assert(std::is_empty::value, "!!!"); + bool operator==(const position_c& l, const position_c& r) noexcept { return l.x == r.x && l.y == r.y; @@ -1226,6 +1230,29 @@ TEST_CASE("registry") { 3 * sizeof(std::size_t) + 1 * sizeof(ecs::entity_id)); } + { + ecs::registry w; + auto e1 = w.create_entity(); + auto e2 = w.create_entity(); + e1.assign_component(); + e2.assign_component(); + REQUIRE(w.component_memory_usage() == + 4 * sizeof(std::size_t) + + 2 * sizeof(ecs::entity_id)); + } + } + SECTION("empty_component") { + ecs::registry w; + auto e1 = w.create_entity(); + ecs::entity_filler(e1) + .component() + .component(1, 2) + .component(3, 4); + REQUIRE(w.exists_component(e1)); + REQUIRE(w.find_component(e1)); + w.for_joined_components([ + ](const ecs::const_entity&, movable_c&, position_c&){ + }); } }