Implement util::ecs packed/sparse policy
This commit is contained in:
parent
0cb197a6c4
commit
70f3b68077
1 changed files with 124 additions and 39 deletions
|
|
@ -63,8 +63,6 @@ namespace psemek::util
|
||||||
|
|
||||||
virtual ~species_base() {}
|
virtual ~species_base() {}
|
||||||
|
|
||||||
static constexpr handle null = static_cast<handle>(-1);
|
|
||||||
|
|
||||||
virtual handle const * get_free_list() = 0;
|
virtual handle const * get_free_list() = 0;
|
||||||
virtual std::size_t list_size() const = 0;
|
virtual std::size_t list_size() const = 0;
|
||||||
|
|
||||||
|
|
@ -112,26 +110,40 @@ namespace psemek::util
|
||||||
|
|
||||||
auto list = get_free_list();
|
auto list = get_free_list();
|
||||||
|
|
||||||
std::size_t const count = list_size();
|
if (list)
|
||||||
|
|
||||||
for (std::size_t i = 0; i < count; ++i)
|
|
||||||
{
|
{
|
||||||
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;
|
ctx.entity = i;
|
||||||
std::apply(visit, cptrs);
|
std::apply(visit, cptrs);
|
||||||
|
std::apply(increment, cptrs);
|
||||||
}
|
}
|
||||||
std::apply(increment, cptrs);
|
|
||||||
++list;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename ... Components>
|
template <typename ... Components>
|
||||||
struct species_impl
|
struct species_impl_base
|
||||||
: species_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_base(std::move(name), id)
|
||||||
, species_components_{std::move(components)...}
|
, 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)>{});
|
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
|
handle entity_count() const override
|
||||||
{
|
{
|
||||||
return entity_count_;
|
return entity_count_;
|
||||||
|
|
@ -177,30 +220,10 @@ namespace psemek::util
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::tuple<Components...> species_components_;
|
|
||||||
std::tuple<std::vector<typename Components::data>...> entity_components_;
|
|
||||||
std::vector<handle> list_;
|
std::vector<handle> list_;
|
||||||
handle list_head_ = null;
|
handle list_head_ = null;
|
||||||
std::size_t entity_count_ = 0;
|
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>
|
template <std::size_t ... I>
|
||||||
handle add_entity_impl(std::index_sequence<I...>)
|
handle add_entity_impl(std::index_sequence<I...>)
|
||||||
{
|
{
|
||||||
|
|
@ -215,12 +238,12 @@ namespace psemek::util
|
||||||
list_[new_size - 1] = null;
|
list_[new_size - 1] = null;
|
||||||
list_head_ = old_size;
|
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_;
|
auto result = list_head_;
|
||||||
|
|
||||||
((std::get<I>(entity_components_)[result] = {}), ...);
|
((std::get<I>(this->entity_components_)[result] = {}), ...);
|
||||||
|
|
||||||
list_head_ = list_[list_head_];
|
list_head_ = list_[list_head_];
|
||||||
list_[result] = result;
|
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
|
struct ecs
|
||||||
|
|
@ -257,8 +333,14 @@ namespace psemek::util
|
||||||
|
|
||||||
using handle = ecs_detail::handle;
|
using handle = ecs_detail::handle;
|
||||||
|
|
||||||
|
enum class policy
|
||||||
|
{
|
||||||
|
sparse,
|
||||||
|
packed,
|
||||||
|
};
|
||||||
|
|
||||||
template <typename ... Components>
|
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(); }
|
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;
|
typename Component::data const * get_if(handle species, handle entity) const;
|
||||||
|
|
||||||
template <typename Behavior>
|
template <typename Behavior>
|
||||||
void apply(Behavior && behavior) const;
|
void apply(Behavior && behavior);
|
||||||
|
|
||||||
template <typename Behavior>
|
template <typename Behavior>
|
||||||
void apply(Behavior && behavior, handle species) const;
|
void apply(Behavior && behavior, handle species);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<std::unique_ptr<ecs_detail::species_base>> species_;
|
std::vector<std::unique_ptr<ecs_detail::species_base>> species_;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename ... Components>
|
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();
|
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;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -391,14 +476,14 @@ namespace psemek::util
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Behavior>
|
template <typename Behavior>
|
||||||
void ecs::apply(Behavior && behavior) const
|
void ecs::apply(Behavior && behavior)
|
||||||
{
|
{
|
||||||
for (auto & s : species_)
|
for (auto & s : species_)
|
||||||
s->apply(behavior);
|
s->apply(behavior);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Behavior>
|
template <typename Behavior>
|
||||||
void ecs::apply(Behavior && behavior, handle species) const
|
void ecs::apply(Behavior && behavior, handle species)
|
||||||
{
|
{
|
||||||
species_[species]->apply(behavior);
|
species_[species]->apply(behavior);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue