From 70f3b6807750e662e19a78eb7a7ea151f76a7964 Mon Sep 17 00:00:00 2001 From: lisyarus Date: Sun, 19 Jun 2022 22:26:22 +0300 Subject: [PATCH] Implement util::ecs packed/sparse policy --- libs/util/include/psemek/util/ecs.hpp | 163 ++++++++++++++++++++------ 1 file changed, 124 insertions(+), 39 deletions(-) diff --git a/libs/util/include/psemek/util/ecs.hpp b/libs/util/include/psemek/util/ecs.hpp index be714d16..44a2f8e1 100644 --- a/libs/util/include/psemek/util/ecs.hpp +++ b/libs/util/include/psemek/util/ecs.hpp @@ -63,8 +63,6 @@ namespace psemek::util virtual ~species_base() {} - static constexpr handle null = static_cast(-1); - virtual handle const * get_free_list() = 0; virtual std::size_t list_size() const = 0; @@ -112,26 +110,40 @@ namespace psemek::util auto list = get_free_list(); - std::size_t const count = list_size(); - - for (std::size_t i = 0; i < count; ++i) + if (list) { - if (*list == i) + // sparse + std::size_t const size = list_size(); + for (std::size_t i = 0; i < size; ++i) + { + if (*list == i) + { + ctx.entity = i; + std::apply(visit, cptrs); + } + std::apply(increment, cptrs); + ++list; + } + } + else + { + // packed + std::size_t const size = entity_count(); + for (std::size_t i = 0; i < size; ++i) { ctx.entity = i; std::apply(visit, cptrs); + std::apply(increment, cptrs); } - std::apply(increment, cptrs); - ++list; } } }; template - struct species_impl + struct species_impl_base : species_base { - species_impl(std::string name, handle id, Components && ... components) + species_impl_base(std::string name, handle id, Components && ... components) : species_base(std::move(name), id) , species_components_{std::move(components)...} {} @@ -149,6 +161,37 @@ namespace psemek::util return get_entity_component_impl(component_type, std::make_index_sequence{}); } + protected: + std::tuple species_components_; + std::tuple...> entity_components_; + + template + void * get_species_component_impl(std::type_index component_type, std::index_sequence) + { + void * result = nullptr; + + ((result = (component_type == typeid(std::tuple_element_t>)) ? &std::get(species_components_) : result), ...); + return result; + } + + template + void * get_entity_component_impl(std::type_index component_type, std::index_sequence) + { + void * result = nullptr; + + ((result = (component_type == typeid(std::tuple_element_t>)) ? std::get(entity_components_).data() : result), ...); + return result; + } + }; + + template + struct sparse_species_impl final + : species_impl_base + { + using species_impl_base::species_impl_base; + + static constexpr handle null = static_cast(-1); + handle entity_count() const override { return entity_count_; @@ -177,30 +220,10 @@ namespace psemek::util } private: - std::tuple species_components_; - std::tuple...> entity_components_; std::vector list_; handle list_head_ = null; std::size_t entity_count_ = 0; - template - void * get_species_component_impl(std::type_index component_type, std::index_sequence) - { - void * result = nullptr; - - ((result = (component_type == typeid(std::tuple_element_t>)) ? &std::get(species_components_) : result), ...); - return result; - } - - template - void * get_entity_component_impl(std::type_index component_type, std::index_sequence) - { - void * result = nullptr; - - ((result = (component_type == typeid(std::tuple_element_t>)) ? std::get(entity_components_).data() : result), ...); - return result; - } - template handle add_entity_impl(std::index_sequence) { @@ -215,12 +238,12 @@ namespace psemek::util list_[new_size - 1] = null; list_head_ = old_size; - ((std::get(entity_components_).resize(new_size)), ...); + ((std::get(this->entity_components_).resize(new_size)), ...); } auto result = list_head_; - ((std::get(entity_components_)[result] = {}), ...); + ((std::get(this->entity_components_)[result] = {}), ...); list_head_ = list_[list_head_]; list_[result] = result; @@ -229,6 +252,59 @@ namespace psemek::util } }; + template + struct packed_species_impl final + : species_impl_base + { + using species_impl_base::species_impl_base; + + handle entity_count() const override + { + return std::get<0>(this->entity_components_).size(); + } + + handle add_entity() override + { + return add_entity_impl(std::make_index_sequence{}); + } + + void remove_entity(handle h) override + { + remove_entity_impl(h, std::make_index_sequence{}); + } + + handle const * get_free_list() override + { + return nullptr; + } + + std::size_t list_size() const override + { + return 0; + } + + private: + + template + handle add_entity_impl(std::index_sequence) + { + handle result = entity_count(); + ((std::get(this->entity_components_).emplace_back()), ...); + return result; + } + + template + void remove_entity_impl(handle h, std::index_sequence) + { + if (h + 1 != entity_count()) + { + (std::swap(std::get(this->entity_components_)[h], std::get(this->entity_components_).back()), ...); + } + + ((std::get(this->entity_components_).pop_back()), ...); + } + }; + } struct ecs @@ -257,8 +333,14 @@ namespace psemek::util using handle = ecs_detail::handle; + enum class policy + { + sparse, + packed, + }; + template - handle register_species(std::string name, Components && ... components); + handle register_species(std::string name, policy p, Components && ... components); handle species_count() const { return species_.size(); } @@ -296,20 +378,23 @@ namespace psemek::util typename Component::data const * get_if(handle species, handle entity) const; template - void apply(Behavior && behavior) const; + void apply(Behavior && behavior); template - void apply(Behavior && behavior, handle species) const; + void apply(Behavior && behavior, handle species); private: std::vector> species_; }; template - ecs::handle ecs::register_species(std::string name, Components && ... components) + ecs::handle ecs::register_species(std::string name, policy p, Components && ... components) { handle result = species_.size(); - species_.push_back(std::make_unique>(std::move(name), result, std::move(components)...)); + if (p == policy::sparse) + species_.push_back(std::make_unique>(std::move(name), result, std::move(components)...)); + else + species_.push_back(std::make_unique>(std::move(name), result, std::move(components)...)); return result; } @@ -391,14 +476,14 @@ namespace psemek::util } template - void ecs::apply(Behavior && behavior) const + void ecs::apply(Behavior && behavior) { for (auto & s : species_) s->apply(behavior); } template - void ecs::apply(Behavior && behavior, handle species) const + void ecs::apply(Behavior && behavior, handle species) { species_[species]->apply(behavior); }