Support creating new ecs entities while iterating over them
This commit is contained in:
parent
d7babe6a0f
commit
3701df15f4
3 changed files with 93 additions and 1 deletions
|
|
@ -73,6 +73,15 @@ namespace psemek::ecs::detail
|
||||||
return std::move(remove_queue_);
|
return std::move(remove_queue_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
table * get_delayed_table()
|
||||||
|
{
|
||||||
|
if (!delayed_table_)
|
||||||
|
delayed_table_ = create_delayed_table();
|
||||||
|
return delayed_table_.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual util::span<entity_handle const> flush_delayed() = 0;
|
||||||
|
|
||||||
virtual ~table() = default;
|
virtual ~table() = default;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
@ -85,6 +94,10 @@ namespace psemek::ecs::detail
|
||||||
std::optional<iteration_data> iteration_data_;
|
std::optional<iteration_data> iteration_data_;
|
||||||
|
|
||||||
std::vector<std::uint32_t> remove_queue_;
|
std::vector<std::uint32_t> remove_queue_;
|
||||||
|
|
||||||
|
std::unique_ptr<table> delayed_table_;
|
||||||
|
|
||||||
|
virtual std::unique_ptr<table> create_delayed_table() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename ... Components>
|
template <typename ... Components>
|
||||||
|
|
@ -99,12 +112,16 @@ namespace psemek::ecs::detail
|
||||||
|
|
||||||
void clear() override;
|
void clear() override;
|
||||||
|
|
||||||
|
util::span<entity_handle const> flush_delayed() override;
|
||||||
|
|
||||||
~table_impl() override;
|
~table_impl() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::size_t capacity_ = 0;
|
std::size_t capacity_ = 0;
|
||||||
|
|
||||||
void reallocate();
|
void reallocate();
|
||||||
|
|
||||||
|
std::unique_ptr<table> create_delayed_table() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename ... Components>
|
template <typename ... Components>
|
||||||
|
|
@ -182,7 +199,7 @@ namespace psemek::ecs::detail
|
||||||
if constexpr (!detail::is_empty_v<Component>)
|
if constexpr (!detail::is_empty_v<Component>)
|
||||||
{
|
{
|
||||||
for (std::size_t i = 0; i < row_count_; ++i)
|
for (std::size_t i = 0; i < row_count_; ++i)
|
||||||
ptr[i]->~Component();
|
ptr[i].~Component();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -193,6 +210,42 @@ namespace psemek::ecs::detail
|
||||||
entity_handles_.clear();
|
entity_handles_.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename ... Components>
|
||||||
|
util::span<entity_handle const> table_impl<Components...>::flush_delayed()
|
||||||
|
{
|
||||||
|
if (!delayed_table_)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
auto delayed = static_cast<table_impl<Components...> *>(delayed_table_.get());
|
||||||
|
|
||||||
|
auto old_row_count = row_count_;
|
||||||
|
|
||||||
|
while (capacity_ < row_count_ + delayed->row_count_)
|
||||||
|
reallocate();
|
||||||
|
|
||||||
|
std::size_t delayed_row = 0;
|
||||||
|
[[maybe_unused]] auto move_row_impl = [&]<typename Component>(std::uint8_t * data_tgt, std::uint8_t * data_src)
|
||||||
|
{
|
||||||
|
if constexpr (!detail::is_empty_v<Component>)
|
||||||
|
{
|
||||||
|
new (reinterpret_cast<Component *>(data_tgt) + row_count_) Component{std::move(*(reinterpret_cast<Component *>(data_src) + delayed_row))};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
for (; delayed_row < delayed->row_count_; ++delayed_row)
|
||||||
|
{
|
||||||
|
std::size_t i1 = 0, i2 = 0;
|
||||||
|
(move_row_impl.template operator()<Components>(component_pointers_[i1++].data, delayed->component_pointers_[i2++].data), ...);
|
||||||
|
++row_count_;
|
||||||
|
}
|
||||||
|
|
||||||
|
entity_handles_.insert(entity_handles_.end(), delayed->entity_handles_.begin(), delayed->entity_handles_.end());
|
||||||
|
|
||||||
|
delayed->clear();
|
||||||
|
|
||||||
|
return {entity_handles_.data() + old_row_count, entity_handles_.data() + row_count_};
|
||||||
|
}
|
||||||
|
|
||||||
template <typename ... Components>
|
template <typename ... Components>
|
||||||
table_impl<Components...>::~table_impl()
|
table_impl<Components...>::~table_impl()
|
||||||
{
|
{
|
||||||
|
|
@ -250,4 +303,10 @@ namespace psemek::ecs::detail
|
||||||
capacity_ = new_capacity;
|
capacity_ = new_capacity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename ... Components>
|
||||||
|
std::unique_ptr<table> table_impl<Components...>::create_delayed_table()
|
||||||
|
{
|
||||||
|
return std::make_unique<table_impl<Components...>>(component_uuids_);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -110,6 +110,9 @@ namespace psemek::ecs
|
||||||
}, mask);
|
}, mask);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (table->get_iteration_data())
|
||||||
|
table = table->get_delayed_table();
|
||||||
|
|
||||||
auto id = entity_list_.create(table, table->row_count());
|
auto id = entity_list_.create(table, table->row_count());
|
||||||
entity_handle handle{id, entity_list_.get_entities()[id].epoch};
|
entity_handle handle{id, entity_list_.get_entities()[id].epoch};
|
||||||
[[maybe_unused]] entity_accessor accessor = get(handle);
|
[[maybe_unused]] entity_accessor accessor = get(handle);
|
||||||
|
|
@ -164,6 +167,14 @@ namespace psemek::ecs
|
||||||
auto entities = entity_list_.get_entities();
|
auto entities = entity_list_.get_entities();
|
||||||
for (auto row : util::reversed(remove_queue))
|
for (auto row : util::reversed(remove_queue))
|
||||||
remove_row(*entry.table, row, entities);
|
remove_row(*entry.table, row, entities);
|
||||||
|
|
||||||
|
std::uint32_t row = entry.table->row_count();
|
||||||
|
for (auto const & handle : entry.table->flush_delayed())
|
||||||
|
{
|
||||||
|
auto & data = entities[handle.id];
|
||||||
|
data.table = entry.table;
|
||||||
|
data.row = row++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -239,3 +239,25 @@ test_case(ecs_apply_remove_random)
|
||||||
for (auto h : handles)
|
for (auto h : handles)
|
||||||
expect(!container.alive(h));
|
expect(!container.alive(h));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test_case(ecs_apply_create)
|
||||||
|
{
|
||||||
|
entity_container container;
|
||||||
|
|
||||||
|
int const count = 1024 * 1024;
|
||||||
|
for (int i = 0; i < count; ++i)
|
||||||
|
container.create();
|
||||||
|
|
||||||
|
int call_count = 0;
|
||||||
|
container.apply([&]{
|
||||||
|
++call_count;
|
||||||
|
container.create();
|
||||||
|
});
|
||||||
|
expect_equal(call_count, count);
|
||||||
|
|
||||||
|
call_count = 0;
|
||||||
|
container.apply([&]{
|
||||||
|
++call_count;
|
||||||
|
});
|
||||||
|
expect_equal(call_count, 2 * count);
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue