Move ecs::entity_accessor to a separate header

This commit is contained in:
Nikita Lisitsa 2023-08-26 21:53:02 +03:00
parent 8b1157c641
commit bc63d98d51
2 changed files with 113 additions and 96 deletions

View file

@ -0,0 +1,112 @@
#pragma once
#include <psemek/ecs/detail/table.hpp>
#include <psemek/ecs/entity_accessor.hpp>
#include <psemek/util/span.hpp>
#include <psemek/util/range.hpp>
#include <psemek/util/exception.hpp>
#include <psemek/util/type_name.hpp>
#include <psemek/util/to_string.hpp>
#include <typeindex>
namespace psemek::ecs
{
struct component_not_found_exception
: util::exception
{
component_not_found_exception(std::type_info const & type, entity_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))
, type_(type)
, handle_(handle)
{}
std::type_info const & type() const
{
return type_;
}
entity_handle const & handle() const
{
return handle_;
}
private:
std::type_info const & type_;
entity_handle handle_;
};
struct entity_accessor
{
entity_accessor() = default;
entity_accessor(entity_accessor const &) = default;
explicit operator bool() const;
/** Obtain a pointer to the specified component type
* of the accessed entity, or a null pointer if
* the entity doesn't contain this component type.
*/
template <typename Component>
Component * get_if();
/** Obtain a reference to the specified component type
* of the accessed entity.
* If the entity doesn't contain this component type,
* an exception of type `component_not_found_exception` is thrown.
*/
template <typename Component>
Component & get();
/** Check if the entity contains this component type.
*/
template <typename Component>
bool contains() const;
private:
detail::table * table_ = nullptr;
std::uint32_t row_ = 0;
friend struct entity_container;
entity_accessor(detail::table * table, std::uint32_t row);
};
inline entity_accessor::operator bool() const
{
return table_ != nullptr;
}
template <typename Component>
Component * entity_accessor::get_if()
{
util::uuid const uuid = Component::uuid();
auto column = table_->column(uuid);
if (!column)
return nullptr;
return reinterpret_cast<Component *>(column->data() + detail::stride<Component>() * row_);
}
template <typename Component>
Component & entity_accessor::get()
{
if (auto ptr = get_if<Component>())
return *ptr;
throw component_not_found_exception(typeid(Component), table_->entity_handles()[row_]);
}
template <typename Component>
bool entity_accessor::contains() const
{
return get_if<Component>() != nullptr;
}
inline entity_accessor::entity_accessor(detail::table * table, std::uint32_t row)
: table_(table)
, row_(row)
{}
}

View file

@ -6,6 +6,7 @@
#include <psemek/ecs/detail/apply_helper.hpp>
#include <psemek/ecs/detail/all_different_types.hpp>
#include <psemek/ecs/detail/component_uuid_helper.hpp>
#include <psemek/ecs/entity_accessor.hpp>
#include <psemek/util/span.hpp>
#include <psemek/util/range.hpp>
#include <psemek/util/exception.hpp>
@ -19,66 +20,6 @@ namespace psemek::ecs
using query_cache = std::shared_ptr<detail::query_cache>;
struct component_not_found_exception
: util::exception
{
component_not_found_exception(std::type_info const & type, entity_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))
, type_(type)
, handle_(handle)
{}
std::type_info const & type() const
{
return type_;
}
entity_handle const & handle() const
{
return handle_;
}
private:
std::type_info const & type_;
entity_handle handle_;
};
struct entity_accessor
{
entity_accessor() = default;
entity_accessor(entity_accessor const &) = default;
explicit operator bool() const;
/** Obtain a pointer to the specified component type
* of the accessed entity, or a null pointer if
* the entity doesn't contain this component type.
*/
template <typename Component>
Component * get_if();
/** Obtain a reference to the specified component type
* of the accessed entity.
* If the entity doesn't contain this component type,
* an exception of type `component_not_found_exception` is thrown.
*/
template <typename Component>
Component & get();
/** Check if the entity contains this component type.
*/
template <typename Component>
bool contains() const;
private:
detail::table * table_ = nullptr;
std::uint32_t row_ = 0;
friend struct entity_container;
entity_accessor(detail::table * table, std::uint32_t row);
};
struct entity_container
{
/** Create an entity with the specified components.
@ -390,40 +331,4 @@ namespace psemek::ecs
}
}
inline entity_accessor::operator bool() const
{
return table_ != nullptr;
}
template <typename Component>
Component * entity_accessor::get_if()
{
util::uuid const uuid = Component::uuid();
auto column = table_->column(uuid);
if (!column)
return nullptr;
return reinterpret_cast<Component *>(column->data() + detail::stride<Component>() * row_);
}
template <typename Component>
Component & entity_accessor::get()
{
if (auto ptr = get_if<Component>())
return *ptr;
throw component_not_found_exception(typeid(Component), table_->entity_handles()[row_]);
}
template <typename Component>
bool entity_accessor::contains() const
{
return get_if<Component>() != nullptr;
}
inline entity_accessor::entity_accessor(detail::table * table, std::uint32_t row)
: table_(table)
, row_(row)
{}
}