Implement util::ecs packed/sparse policy

This commit is contained in:
Nikita Lisitsa 2022-06-19 22:26:22 +03:00
parent 0cb197a6c4
commit 70f3b68077

View file

@ -63,8 +63,6 @@ namespace psemek::util
virtual ~species_base() {}
static constexpr handle null = static_cast<handle>(-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 <typename ... Components>
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<sizeof...(Components)>{});
}
protected:
std::tuple<Components...> species_components_;
std::tuple<std::vector<typename Components::data>...> entity_components_;
template <std::size_t ... I>
void * get_species_component_impl(std::type_index component_type, std::index_sequence<I...>)
{
void * result = nullptr;
((result = (component_type == typeid(std::tuple_element_t<I, std::tuple<Components...>>)) ? &std::get<I>(species_components_) : result), ...);
return result;
}
template <std::size_t ... I>
void * get_entity_component_impl(std::type_index component_type, std::index_sequence<I...>)
{
void * result = nullptr;
((result = (component_type == typeid(std::tuple_element_t<I, std::tuple<Components...>>)) ? std::get<I>(entity_components_).data() : result), ...);
return result;
}
};
template <typename ... Components>
struct sparse_species_impl final
: species_impl_base<Components...>
{
using species_impl_base<Components...>::species_impl_base;
static constexpr handle null = static_cast<handle>(-1);
handle entity_count() const override
{
return entity_count_;
@ -177,30 +220,10 @@ namespace psemek::util
}
private:
std::tuple<Components...> species_components_;
std::tuple<std::vector<typename Components::data>...> entity_components_;
std::vector<handle> list_;
handle list_head_ = null;
std::size_t entity_count_ = 0;
template <std::size_t ... I>
void * get_species_component_impl(std::type_index component_type, std::index_sequence<I...>)
{
void * result = nullptr;
((result = (component_type == typeid(std::tuple_element_t<I, std::tuple<Components...>>)) ? &std::get<I>(species_components_) : result), ...);
return result;
}
template <std::size_t ... I>
void * get_entity_component_impl(std::type_index component_type, std::index_sequence<I...>)
{
void * result = nullptr;
((result = (component_type == typeid(std::tuple_element_t<I, std::tuple<Components...>>)) ? std::get<I>(entity_components_).data() : result), ...);
return result;
}
template <std::size_t ... I>
handle add_entity_impl(std::index_sequence<I...>)
{
@ -215,12 +238,12 @@ namespace psemek::util
list_[new_size - 1] = null;
list_head_ = old_size;
((std::get<I>(entity_components_).resize(new_size)), ...);
((std::get<I>(this->entity_components_).resize(new_size)), ...);
}
auto result = list_head_;
((std::get<I>(entity_components_)[result] = {}), ...);
((std::get<I>(this->entity_components_)[result] = {}), ...);
list_head_ = list_[list_head_];
list_[result] = result;
@ -229,6 +252,59 @@ namespace psemek::util
}
};
template <typename ... Components>
struct packed_species_impl final
: species_impl_base<Components...>
{
using species_impl_base<Components...>::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<sizeof...(Components)>{});
}
void remove_entity(handle h) override
{
remove_entity_impl(h, std::make_index_sequence<sizeof...(Components)>{});
}
handle const * get_free_list() override
{
return nullptr;
}
std::size_t list_size() const override
{
return 0;
}
private:
template <std::size_t ... I>
handle add_entity_impl(std::index_sequence<I...>)
{
handle result = entity_count();
((std::get<I>(this->entity_components_).emplace_back()), ...);
return result;
}
template <std::size_t ... I>
void remove_entity_impl(handle h, std::index_sequence<I...>)
{
if (h + 1 != entity_count())
{
(std::swap(std::get<I>(this->entity_components_)[h], std::get<I>(this->entity_components_).back()), ...);
}
((std::get<I>(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 <typename ... Components>
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 <typename Behavior>
void apply(Behavior && behavior) const;
void apply(Behavior && behavior);
template <typename Behavior>
void apply(Behavior && behavior, handle species) const;
void apply(Behavior && behavior, handle species);
private:
std::vector<std::unique_ptr<ecs_detail::species_base>> species_;
};
template <typename ... Components>
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<ecs_detail::species_impl<Components...>>(std::move(name), result, std::move(components)...));
if (p == policy::sparse)
species_.push_back(std::make_unique<ecs_detail::sparse_species_impl<Components...>>(std::move(name), result, std::move(components)...));
else
species_.push_back(std::make_unique<ecs_detail::packed_species_impl<Components...>>(std::move(name), result, std::move(components)...));
return result;
}
@ -391,14 +476,14 @@ namespace psemek::util
}
template <typename Behavior>
void ecs::apply(Behavior && behavior) const
void ecs::apply(Behavior && behavior)
{
for (auto & s : species_)
s->apply(behavior);
}
template <typename Behavior>
void ecs::apply(Behavior && behavior, handle species) const
void ecs::apply(Behavior && behavior, handle species)
{
species_[species]->apply(behavior);
}