Rename ecs::entity_handle -> ecs::handle

This commit is contained in:
Nikita Lisitsa 2023-12-16 16:29:10 +03:00
parent d48bbc91a6
commit 95b26d890e
13 changed files with 80 additions and 71 deletions

View file

@ -16,9 +16,9 @@ namespace psemek::ecs::detail
{ {
template <typename Function, typename ... Components> template <typename Function, typename ... Components>
void invoke(Function && function, entity_container & parent, entity_handle const & handle, Components & ... components) void invoke(Function && function, entity_container & parent, handle const & handle, Components & ... components)
{ {
if constexpr (std::invocable<Function, entity_container &, entity_handle, Components & ...>) if constexpr (std::invocable<Function, entity_container &, ecs::handle, Components & ...>)
{ {
function(parent, handle, components...); function(parent, handle, components...);
} }
@ -26,7 +26,7 @@ namespace psemek::ecs::detail
{ {
function(parent, components...); function(parent, components...);
} }
else if constexpr (std::invocable<Function, entity_handle, Components & ...>) else if constexpr (std::invocable<Function, ecs::handle, Components & ...>)
{ {
function(handle, components...); function(handle, components...);
} }
@ -37,15 +37,15 @@ namespace psemek::ecs::detail
} }
template <typename Function, typename ... Components> template <typename Function, typename ... Components>
void batch_invoke(Function && function, entity_container & parent, std::size_t count, entity_handle const * handles, Components * ... components) void batch_invoke(Function && function, entity_container & parent, std::size_t count, handle const * handles, Components * ... components)
{ {
util::span<entity_handle const> handles_span{handles, count}; util::span<handle const> handles_span{handles, count};
if constexpr (std::invocable<Function, entity_container &, util::span<entity_handle const>, util::span<Components> ...>) if constexpr (std::invocable<Function, entity_container &, util::span<handle const>, util::span<Components> ...>)
{ {
function(parent, handles_span, util::span<Components>{components, is_empty_v<Components> ? 1 : count} ...); function(parent, handles_span, util::span<Components>{components, is_empty_v<Components> ? 1 : count} ...);
} }
else if constexpr (std::invocable<Function, util::span<entity_handle const>, util::span<Components> ...>) else if constexpr (std::invocable<Function, util::span<handle const>, util::span<Components> ...>)
{ {
function(handles_span, util::span<Components>{components, is_empty_v<Components> ? 1 : count} ...); function(handles_span, util::span<Components>{components, is_empty_v<Components> ? 1 : count} ...);
} }
@ -64,11 +64,11 @@ namespace psemek::ecs::detail
{ {
entity_container & parent; entity_container & parent;
std::size_t row_count; std::size_t row_count;
entity_handle const * entity_handles_pointer; handle const * entity_handles_pointer;
// (+1) to prevent zero-sized array // (+1) to prevent zero-sized array
std::uint8_t * pointers[sizeof...(Components) + 1]; std::uint8_t * pointers[sizeof...(Components) + 1];
static_apply_helper(entity_container & parent, util::span<entity_handle const> entity_handles) static_apply_helper(entity_container & parent, util::span<handle const> entity_handles)
: parent(parent) : parent(parent)
, row_count(entity_handles.size()) , row_count(entity_handles.size())
, entity_handles_pointer(entity_handles.data()) , entity_handles_pointer(entity_handles.data())

View file

@ -1,6 +1,6 @@
#pragma once #pragma once
#include <psemek/ecs/entity_handle.hpp> #include <psemek/ecs/detail/id.hpp>
#include <psemek/util/span.hpp> #include <psemek/util/span.hpp>
#include <vector> #include <vector>

View file

@ -0,0 +1,11 @@
#pragma once
#include <cstdint>
namespace psemek::ecs::detail
{
using entity_id = std::uint32_t;
using entity_epoch = std::uint32_t;
}

View file

@ -1,6 +1,6 @@
#pragma once #pragma once
#include <psemek/ecs/entity_handle.hpp> #include <psemek/ecs/handle.hpp>
#include <psemek/ecs/detail/component_hash.hpp> #include <psemek/ecs/detail/component_hash.hpp>
#include <psemek/ecs/detail/column.hpp> #include <psemek/ecs/detail/column.hpp>
#include <psemek/util/uuid.hpp> #include <psemek/util/uuid.hpp>
@ -28,7 +28,7 @@ namespace psemek::ecs::detail
detail::column * column(util::uuid const & uuid) const; detail::column * column(util::uuid const & uuid) const;
util::span<entity_handle const> entity_handles() const util::span<handle const> entity_handles() const
{ {
return entity_handles_; return entity_handles_;
} }
@ -48,8 +48,8 @@ namespace psemek::ecs::detail
return entity_handles_.size(); return entity_handles_.size();
} }
std::size_t push_row(entity_handle handle); std::size_t push_row(handle handle);
std::size_t move_row(entity_handle handle, table * from, std::size_t from_row); std::size_t move_row(handle handle, table * from, std::size_t from_row);
void swap_rows(std::size_t row1, std::size_t row2); void swap_rows(std::size_t row1, std::size_t row2);
void pop_row(); void pop_row();
void clear(); void clear();
@ -70,14 +70,14 @@ namespace psemek::ecs::detail
std::unique_ptr<table> clone() const; std::unique_ptr<table> clone() const;
table * get_delayed_table(); table * get_delayed_table();
util::span<entity_handle const> flush_delayed(); util::span<handle const> flush_delayed();
protected: protected:
std::size_t hash_; std::size_t hash_;
std::vector<std::unique_ptr<detail::column>> columns_; std::vector<std::unique_ptr<detail::column>> columns_;
util::hash_map<util::uuid, detail::column *> component_uuid_to_column_; util::hash_map<util::uuid, detail::column *> component_uuid_to_column_;
std::vector<entity_handle> entity_handles_; std::vector<handle> entity_handles_;
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_;

View file

@ -16,7 +16,7 @@ namespace psemek::ecs
struct component_not_found_exception struct component_not_found_exception
: util::exception : util::exception
{ {
component_not_found_exception(std::type_info const & type, entity_handle const & handle, boost::stacktrace::stacktrace stacktrace = {}) component_not_found_exception(std::type_info const & type, handle const & handle, boost::stacktrace::stacktrace stacktrace = {})
: util::exception(util::to_string("Component ", util::type_name(type), " not found for entity ", handle), std::move(stacktrace)) : util::exception(util::to_string("Component ", util::type_name(type), " not found for entity ", handle), std::move(stacktrace))
, type_(type) , type_(type)
, handle_(handle) , handle_(handle)
@ -27,14 +27,14 @@ namespace psemek::ecs
return type_; return type_;
} }
entity_handle const & handle() const ecs::handle const & handle() const
{ {
return handle_; return handle_;
} }
private: private:
std::type_info const & type_; std::type_info const & type_;
entity_handle handle_; ecs::handle handle_;
}; };
struct entity_accessor struct entity_accessor

View file

@ -41,14 +41,14 @@ namespace psemek::ecs
* whether the created entity will be visited by iteration or not. * whether the created entity will be visited by iteration or not.
*/ */
template <typename ... Components> template <typename ... Components>
entity_handle create(Components && ... components); handle create(Components && ... components);
/** Check if an entity handle refers to an alive entity (i.e. one that wasn't /** Check if an entity handle refers to an alive entity (i.e. one that wasn't
* destroyed yet). * destroyed yet).
* If the handle wasn't previously obtained by a `create()` call, the * If the handle wasn't previously obtained by a `create()` call, the
* behavior is undefined. * behavior is undefined.
*/ */
bool alive(entity_handle const & entity) const; bool alive(handle const & entity) const;
/** Destroy an entity specified by a handle. After the call, `alive()` /** Destroy an entity specified by a handle. After the call, `alive()`
* returns false for this handle. * returns false for this handle.
@ -58,7 +58,7 @@ namespace psemek::ecs
* If the handle wasn't previously obtained by a `create()` call, or * If the handle wasn't previously obtained by a `create()` call, or
* the refered entity was already destroyed, the behavior is undefined. * the refered entity was already destroyed, the behavior is undefined.
*/ */
void destroy(entity_handle const & entity); void destroy(handle const & entity);
/** Get an entity accessor for an entity, which provides access to the entity's components. /** Get an entity accessor for an entity, which provides access to the entity's components.
* It is designed to be a single-use object; it cannot be stored as a reference to * It is designed to be a single-use object; it cannot be stored as a reference to
@ -68,7 +68,7 @@ namespace psemek::ecs
* If the handle wasn't previously obtained by a `create()` call, or * If the handle wasn't previously obtained by a `create()` call, or
* the referred entity was already destroyed, the behavior is undefined. * the referred entity was already destroyed, the behavior is undefined.
*/ */
entity_accessor get(entity_handle const & entity); entity_accessor get(handle const & entity);
/** Attach new components to an existing entity, or update existing /** Attach new components to an existing entity, or update existing
* components with new values. Other components of this entity * components with new values. Other components of this entity
@ -82,7 +82,7 @@ namespace psemek::ecs
* the refered entity was already destroyed, the behavior is undefined. * the refered entity was already destroyed, the behavior is undefined.
*/ */
template <typename ... Components> template <typename ... Components>
void attach(entity_handle const & entity, Components && ... components); void attach(handle const & entity, Components && ... components);
/** Detach (remove) components from an existing entity. Other components of this entity /** Detach (remove) components from an existing entity. Other components of this entity
* are left untouched. Detaching a component that doesn't exist does nothing. * are left untouched. Detaching a component that doesn't exist does nothing.
@ -95,7 +95,7 @@ namespace psemek::ecs
* the refered entity was already destroyed, the behavior is undefined. * the refered entity was already destroyed, the behavior is undefined.
*/ */
template <typename ... Components> template <typename ... Components>
void detach(entity_handle const & entity); void detach(handle const & entity);
/** Create a query cache that can be used to speed up `apply()` calls. /** Create a query cache that can be used to speed up `apply()` calls.
*/ */
@ -218,12 +218,12 @@ namespace psemek::ecs
util::hash_set<util::uuid> uuid_set_helper_; util::hash_set<util::uuid> uuid_set_helper_;
detail::table * insert_table(std::vector<std::unique_ptr<detail::column>> columns); detail::table * insert_table(std::vector<std::unique_ptr<detail::column>> columns);
void do_destroy(entity_handle const & entity); void do_destroy(handle const & entity);
void remove_row(detail::table & table, std::uint32_t row, util::span<detail::entity_data> entities); void remove_row(detail::table & table, std::uint32_t row, util::span<detail::entity_data> entities);
}; };
template <typename ... Components> template <typename ... Components>
entity_handle entity_container::create(Components && ... components) handle entity_container::create(Components && ... components)
{ {
static_assert(detail::all_different_types_v<Components...>, "all component types must be different"); static_assert(detail::all_different_types_v<Components...>, "all component types must be different");
@ -243,7 +243,7 @@ namespace psemek::ecs
table = table->get_delayed_table(); 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}; handle handle{id, entity_list_.get_entities()[id].epoch};
[[maybe_unused]] entity_accessor accessor = get(handle); [[maybe_unused]] entity_accessor accessor = get(handle);
table->push_row(handle); table->push_row(handle);
@ -253,7 +253,7 @@ namespace psemek::ecs
} }
template <typename ... Components> template <typename ... Components>
void entity_container::attach(entity_handle const & entity, Components && ... components) void entity_container::attach(handle const & entity, Components && ... components)
{ {
static_assert(detail::all_different_types_v<Components...>, "all component types must be different"); static_assert(detail::all_different_types_v<Components...>, "all component types must be different");
@ -295,7 +295,7 @@ namespace psemek::ecs
} }
template <typename ... Components> template <typename ... Components>
void entity_container::detach(entity_handle const & entity) void entity_container::detach(handle const & entity)
{ {
static_assert(detail::all_different_types_v<Components...>, "all component types must be different"); static_assert(detail::all_different_types_v<Components...>, "all component types must be different");

View file

@ -1,24 +0,0 @@
#pragma once
#include <cstdint>
#include <iostream>
namespace psemek::ecs
{
using entity_id = std::uint32_t;
using entity_epoch = std::uint32_t;
struct entity_handle
{
entity_id id;
entity_epoch epoch;
};
inline std::ostream & operator << (std::ostream & out, entity_handle const & handle)
{
out << '(' << handle.id << ',' << handle.epoch << ')';
return out;
}
}

View file

@ -0,0 +1,22 @@
#pragma once
#include <psemek/ecs/detail/id.hpp>
#include <iostream>
namespace psemek::ecs
{
struct handle
{
detail::entity_id id;
detail::entity_epoch epoch;
};
inline std::ostream & operator << (std::ostream & out, handle const & handle)
{
out << '(' << handle.id << ',' << handle.epoch << ')';
return out;
}
}

View file

@ -25,7 +25,7 @@ namespace psemek::ecs::detail
return nullptr; return nullptr;
} }
std::size_t table::push_row(entity_handle handle) std::size_t table::push_row(handle handle)
{ {
for (auto & column : columns_) for (auto & column : columns_)
column->push_row(); column->push_row();
@ -33,7 +33,7 @@ namespace psemek::ecs::detail
return entity_handles_.size() - 1; return entity_handles_.size() - 1;
} }
std::size_t table::move_row(entity_handle handle, table * from, std::size_t from_row) std::size_t table::move_row(handle handle, table * from, std::size_t from_row)
{ {
for (auto & column : columns_) for (auto & column : columns_)
{ {
@ -92,7 +92,7 @@ namespace psemek::ecs::detail
return delayed_table_.get(); return delayed_table_.get();
} }
util::span<entity_handle const> table::flush_delayed() util::span<handle const> table::flush_delayed()
{ {
if (!delayed_table_) if (!delayed_table_)
return {}; return {};

View file

@ -3,18 +3,18 @@
namespace psemek::ecs namespace psemek::ecs
{ {
bool entity_container::alive(entity_handle const & entity) const bool entity_container::alive(handle const & entity) const
{ {
return entity_list_.get_entities()[entity.id].epoch == entity.epoch; return entity_list_.get_entities()[entity.id].epoch == entity.epoch;
} }
void entity_container::destroy(entity_handle const & entity) void entity_container::destroy(handle const & entity)
{ {
do_destroy(entity); do_destroy(entity);
entity_list_.destroy(entity.id); entity_list_.destroy(entity.id);
} }
entity_accessor entity_container::get(entity_handle const & entity) entity_accessor entity_container::get(handle const & entity)
{ {
auto const data = entity_list_.get_entities()[entity.id]; auto const data = entity_list_.get_entities()[entity.id];
return {data.table, data.row}; return {data.table, data.row};
@ -31,7 +31,7 @@ namespace psemek::ecs
return table; return table;
} }
void entity_container::do_destroy(entity_handle const & entity) void entity_container::do_destroy(handle const & entity)
{ {
auto entities = entity_list_.get_entities(); auto entities = entity_list_.get_entities();
auto & data = entities[entity.id]; auto & data = entities[entity.id];

View file

@ -36,9 +36,9 @@ test_case(ecs_apply_empty)
container.create(); container.create();
int call_count = 0; int call_count = 0;
container.apply<>([&](entity_container &, entity_handle const &){ ++call_count; }); container.apply<>([&](entity_container &, handle const &){ ++call_count; });
container.apply<>([&](entity_container &){ ++call_count; }); container.apply<>([&](entity_container &){ ++call_count; });
container.apply<>([&](entity_handle const &){ ++call_count; }); container.apply<>([&](handle const &){ ++call_count; });
container.apply<>([&]{ ++call_count; }); container.apply<>([&]{ ++call_count; });
expect_equal(count * 4, call_count); expect_equal(count * 4, call_count);
} }
@ -119,9 +119,9 @@ test_case(ecs_apply_batch_invoke)
container.create(component_1{i}); container.create(component_1{i});
int call_count = 0; int call_count = 0;
container.batch_apply<component_1>([&](entity_container &, util::span<entity_handle const>, util::span<component_1> components){ call_count += components.size(); }); container.batch_apply<component_1>([&](entity_container &, util::span<handle const>, util::span<component_1> components){ call_count += components.size(); });
container.batch_apply<component_1>([&](entity_container &, util::span<component_1> components){ call_count += components.size(); }); container.batch_apply<component_1>([&](entity_container &, util::span<component_1> components){ call_count += components.size(); });
container.batch_apply<component_1>([&](util::span<entity_handle const>, util::span<component_1> components){ call_count += components.size(); }); container.batch_apply<component_1>([&](util::span<handle const>, util::span<component_1> components){ call_count += components.size(); });
container.batch_apply<component_1>([&](util::span<component_1> components){ call_count += components.size(); }); container.batch_apply<component_1>([&](util::span<component_1> components){ call_count += components.size(); });
expect_equal(count * 4, call_count); expect_equal(count * 4, call_count);
} }
@ -174,7 +174,7 @@ test_case(ecs_apply_remove_forward)
{ {
entity_container container; entity_container container;
std::vector<entity_handle> handles; std::vector<handle> handles;
int const count = 1024 * 1024; int const count = 1024 * 1024;
for (int i = 0; i < count; ++i) for (int i = 0; i < count; ++i)
handles.push_back(container.create()); handles.push_back(container.create());
@ -195,7 +195,7 @@ test_case(ecs_apply_remove_reversed)
{ {
entity_container container; entity_container container;
std::vector<entity_handle> handles; std::vector<handle> handles;
int const count = 1024 * 1024; int const count = 1024 * 1024;
for (int i = 0; i < count; ++i) for (int i = 0; i < count; ++i)
handles.push_back(container.create()); handles.push_back(container.create());
@ -220,7 +220,7 @@ test_case(ecs_apply_remove_random)
entity_container container; entity_container container;
random::generator rng; random::generator rng;
std::vector<entity_handle> handles; std::vector<handle> handles;
int const count = 1024 * 1024; int const count = 1024 * 1024;
for (int i = 0; i < count; ++i) for (int i = 0; i < count; ++i)
handles.push_back(container.create()); handles.push_back(container.create());

View file

@ -89,7 +89,7 @@ test_case(ecs_component_lifetime)
random::generator rng; random::generator rng;
entity_container container; entity_container container;
std::vector<entity_handle> entities; std::vector<handle> entities;
for (int i = 0; i < 1024 * 1024; ++i) for (int i = 0; i < 1024 * 1024; ++i)
entities.push_back(container.create(component_counter{std::make_shared<int>(42)})); entities.push_back(container.create(component_counter{std::make_shared<int>(42)}));

View file

@ -114,12 +114,12 @@ test_case(ecs_entity_random)
random::generator rng; random::generator rng;
entity_container container; entity_container container;
std::vector<std::pair<entity_handle, int>> entities; std::vector<std::pair<handle, int>> entities;
for (int i = 0; i < 1024 * 1024; ++i) for (int i = 0; i < 1024 * 1024; ++i)
{ {
int value = random::uniform(rng, -1024, 1024); int value = random::uniform(rng, -1024, 1024);
entity_handle handle; handle handle;
if (random::uniform<bool>(rng)) if (random::uniform<bool>(rng))
handle = container.create(component_1{value}); handle = container.create(component_1{value});
else else