Fix constructors & destructors order

Order of callbacks was affected by the order of caches, which are pretty
much arbitrary. For a fix, explicitly order the callbacks globally
per-world.
This commit is contained in:
Nikita Lisitsa 2024-11-28 18:55:17 +03:00
parent fad1580379
commit 80b4cc938d
5 changed files with 44 additions and 19 deletions

View file

@ -403,6 +403,9 @@ namespace psemek::ecs
detail::component_registry component_registry_;
detail::index_container index_container_;
int next_constructor_id_ = 0;
int next_destructor_id_ = 0;
util::object_pool<std::vector<util::uuid>> uuid_list_pool_;
util::object_pool<util::hash_set<util::uuid>> uuid_set_pool_;
@ -655,6 +658,8 @@ namespace psemek::ecs
static_assert(invocable_type::value, "function is not invocable with these components");
auto id = next_constructor_id_++;
auto constructor_factory = [function = std::move(function)](std::vector<std::uint32_t> const & column_indices) -> detail::table_callback {
return [function, column_indices](container & container, detail::table & table, std::uint32_t row, util::hash_set<util::uuid> const & attached_components, bool force){
@ -674,9 +679,9 @@ namespace psemek::ecs
query_cache cache = this->cache<Components...>();
cache->constructor_factories.push_back(constructor_factory);
cache->constructor_factories.push_back([id, constructor_factory](auto const & ... args){ return detail::ordered_table_callback{id, constructor_factory(args...)}; });
for (auto const & entry : cache->entries)
entry.table->add_constructor(constructor_factory(entry.columns_indices));
entry.table->add_constructor({id, constructor_factory(entry.columns_indices)});
}
template <typename ... Components, typename Function>
@ -688,6 +693,8 @@ namespace psemek::ecs
static_assert(invocable_type::value, "function is not invocable with these components");
auto id = next_destructor_id_++;
auto destructor_factory = [function = std::move(function)](std::vector<std::uint32_t> const & column_indices) -> detail::table_callback {
return [function, column_indices](container & container, detail::table & table, std::uint32_t row, util::hash_set<util::uuid> const & detached_components, bool force){
@ -707,9 +714,9 @@ namespace psemek::ecs
query_cache cache = this->cache<Components...>();
cache->destructor_factories.push_back(destructor_factory);
cache->destructor_factories.push_back([id, destructor_factory](auto const & ... args){ return detail::ordered_table_callback{id, destructor_factory(args...)}; });
for (auto const & entry : cache->entries)
entry.table->add_destructor(destructor_factory(entry.columns_indices));
entry.table->add_destructor({id, destructor_factory(entry.columns_indices)});
}
template <typename Index, typename ... Args>

View file

@ -18,6 +18,22 @@ namespace psemek::ecs
using table_callback = util::function<void(container &, table &, std::uint32_t, util::hash_set<util::uuid> const &, bool)>;
struct ordered_table_callback
{
int id;
table_callback callback;
friend auto operator <=> (ordered_table_callback const & c1, ordered_table_callback const & c2)
{
return c1.id <=> c2.id;
}
friend bool operator == (ordered_table_callback const & c1, ordered_table_callback const & c2)
{
return c1.id == c2.id;
}
};
}
}

View file

@ -27,7 +27,7 @@ namespace psemek::ecs::detail
std::list<query_cache_entry> entries;
using callback_factory = util::function<table_callback(std::vector<std::uint32_t> const &)>;
using callback_factory = util::function<ordered_table_callback(std::vector<std::uint32_t> const &)>;
std::vector<callback_factory> constructor_factories;
std::vector<callback_factory> destructor_factories;

View file

@ -70,8 +70,8 @@ namespace psemek::ecs::detail
std::vector<std::type_index> const & non_copyable_components() const;
void add_constructor(table_callback callback);
void add_destructor(table_callback callback);
void add_constructor(ordered_table_callback callback);
void add_destructor(ordered_table_callback callback);
void trigger_constructors(container & container, std::uint32_t row);
void trigger_constructors(container & container, std::uint32_t row, util::hash_set<util::uuid> const & attached_components);
@ -97,8 +97,8 @@ namespace psemek::ecs::detail
std::vector<std::type_index> non_copyable_components_;
std::shared_ptr<std::vector<table_callback>> constructors_;
std::shared_ptr<std::vector<table_callback>> destructors_;
std::shared_ptr<std::vector<ordered_table_callback>> constructors_;
std::shared_ptr<std::vector<ordered_table_callback>> destructors_;
};
}

View file

@ -21,8 +21,8 @@ namespace psemek::ecs::detail
columns_ = std::move(columns);
constructors_ = std::make_shared<std::vector<table_callback>>();
destructors_ = std::make_shared<std::vector<table_callback>>();
constructors_ = std::make_shared<std::vector<ordered_table_callback>>();
destructors_ = std::make_shared<std::vector<ordered_table_callback>>();
}
std::optional<std::size_t> table::column_index(util::uuid const & uuid) const
@ -144,38 +144,40 @@ namespace psemek::ecs::detail
return non_copyable_components_;
}
void table::add_constructor(table_callback callback)
void table::add_constructor(ordered_table_callback callback)
{
constructors_->push_back(std::move(callback));
auto it = std::upper_bound(constructors_->begin(), constructors_->end(), callback);
constructors_->insert(it, std::move(callback));
}
void table::add_destructor(table_callback callback)
void table::add_destructor(ordered_table_callback callback)
{
destructors_->push_back(std::move(callback));
auto it = std::upper_bound(destructors_->begin(), destructors_->end(), callback);
destructors_->insert(it, std::move(callback));
}
void table::trigger_constructors(container & container, std::uint32_t row)
{
for (auto const & callback : *constructors_)
callback(container, *this, row, column_uuid_set_, true);
callback.callback(container, *this, row, column_uuid_set_, true);
}
void table::trigger_constructors(container & container, std::uint32_t row, util::hash_set<util::uuid> const & attached_components)
{
for (auto const & callback : *constructors_)
callback(container, *this, row, attached_components, false);
callback.callback(container, *this, row, attached_components, false);
}
void table::trigger_destructors(container & container, std::uint32_t row)
{
for (auto const & callback : *destructors_)
callback(container, *this, row, column_uuid_set_, true);
callback.callback(container, *this, row, column_uuid_set_, true);
}
void table::trigger_destructors(container & container, std::uint32_t row, util::hash_set<util::uuid> const & detached_components)
{
for (auto const & callback : *destructors_)
callback(container, *this, row, detached_components, false);
callback.callback(container, *this, row, detached_components, false);
}
std::size_t table::memory_usage() const