Class meta_factory< Type >
Synopsis
#include <src/entt/meta/factory.hpp>
template<typename Type>
class meta_factory<Type>
Description
Basic meta factory to be used for reflection purposes.
- Template Parameters
Type
- Reflected type for which the factory was created.
Inheritance
Decsendents: meta_factory< Type, Spec... >
Methods
base | Assigns a meta base to a meta type. | |
conv overload | Assigns a meta conversion function to a meta type. | |
ctor overload | Assigns a meta constructor to a meta type. | |
data overload | Assigns a meta data to a meta type. | |
data overload | Assigns a meta data to a meta type by means of its setter and getter. | |
dtor | Assigns a meta destructor to a meta type. | |
func | Assigns a meta funcion to a meta type. | |
type | Makes a meta type searchable. |
Source
Lines 336-704 in src/entt/meta/factory.hpp.
template<typename Type>
class meta_factory<Type> {
template<typename Node>
bool exists(const Node *candidate, const Node *node) ENTT_NOEXCEPT {
return node && (node == candidate || exists(candidate, node->next));
}
template<typename Node>
bool exists(const id_type id, const Node *node) ENTT_NOEXCEPT {
return node && (node->id == id || exists(id, node->next));
}
public:
/**
* @brief Makes a meta type _searchable_.
* @param id Optional unique identifier.
* @return An extended meta factory for the given type.
*/
auto type(const id_type id = type_hash<Type>::value()) {
auto * const node = internal::meta_info<Type>::resolve();
ENTT_ASSERT(!exists(id, *internal::meta_context::global()));
ENTT_ASSERT(!exists(node, *internal::meta_context::global()));
node->id = id;
node->next = *internal::meta_context::global();
*internal::meta_context::global() = node;
return meta_factory<Type, Type>{&node->prop};
}
/**
* @brief Assigns a meta base to a meta type.
*
* A reflected base class must be a real base class of the reflected type.
*
* @tparam Base Type of the base class to assign to the meta type.
* @return A meta factory for the parent type.
*/
template<typename Base>
auto base() ENTT_NOEXCEPT {
static_assert(std::is_base_of_v<Base, Type>, "Invalid base type");
auto * const type = internal::meta_info<Type>::resolve();
static internal::meta_base_node node{
type,
nullptr,
&internal::meta_info<Base>::resolve,
[](const void *instance) ENTT_NOEXCEPT -> const void * {
return static_cast<const Base *>(static_cast<const Type *>(instance));
}
};
ENTT_ASSERT(!exists(&node, type->base));
node.next = type->base;
type->base = &node;
return meta_factory<Type>{};
}
/**
* @brief Assigns a meta conversion function to a meta type.
*
* The given type must be such that an instance of the reflected type can be
* converted to it.
*
* @tparam To Type of the conversion function to assign to the meta type.
* @return A meta factory for the parent type.
*/
template<typename To>
auto conv() ENTT_NOEXCEPT {
static_assert(std::is_convertible_v<Type, To>, "Could not convert to the required type");
auto * const type = internal::meta_info<Type>::resolve();
static internal::meta_conv_node node{
type,
nullptr,
&internal::meta_info<To>::resolve,
[](const void *instance) -> meta_any {
return static_cast<To>(*static_cast<const Type *>(instance));
}
};
ENTT_ASSERT(!exists(&node, type->conv));
node.next = type->conv;
type->conv = &node;
return meta_factory<Type>{};
}
/**
* @brief Assigns a meta conversion function to a meta type.
*
* Conversion functions can be either free functions or member
* functions.<br/>
* In case of free functions, they must accept a const reference to an
* instance of the parent type as an argument. In case of member functions,
* they should have no arguments at all.
*
* @tparam Candidate The actual function to use for the conversion.
* @return A meta factory for the parent type.
*/
template<auto Candidate>
auto conv() ENTT_NOEXCEPT {
using conv_type = std::invoke_result_t<decltype(Candidate), Type &>;
auto * const type = internal::meta_info<Type>::resolve();
static internal::meta_conv_node node{
type,
nullptr,
&internal::meta_info<conv_type>::resolve,
[](const void *instance) -> meta_any {
return std::invoke(Candidate, *static_cast<const Type *>(instance));
}
};
ENTT_ASSERT(!exists(&node, type->conv));
node.next = type->conv;
type->conv = &node;
return meta_factory<Type>{};
}
/**
* @brief Assigns a meta constructor to a meta type.
*
* Both member functions and free function can be assigned to meta types in
* the role of constructors. All that is required is that they return an
* instance of the underlying type.<br/>
* From a client's point of view, nothing changes if a constructor of a meta
* type is a built-in one or not.
*
* @tparam Candidate The actual function to use as a constructor.
* @tparam Policy Optional policy (no policy set by default).
* @return An extended meta factory for the parent type.
*/
template<auto Candidate, typename Policy = as_is_t>
auto ctor() ENTT_NOEXCEPT {
using helper_type = internal::meta_function_helper_t<Type, decltype(Candidate)>;
static_assert(std::is_same_v<std::remove_cv_t<std::remove_reference_t<typename helper_type::return_type>>, Type>, "The function doesn't return an object of the required type");
auto * const type = internal::meta_info<Type>::resolve();
static internal::meta_ctor_node node{
type,
nullptr,
nullptr,
helper_type::args_type::size,
&helper_type::arg,
[](meta_any * const any) {
return internal::invoke<Type, Candidate, Policy>({}, any, std::make_index_sequence<helper_type::args_type::size>{});
}
};
ENTT_ASSERT(!exists(&node, type->ctor));
node.next = type->ctor;
type->ctor = &node;
return meta_factory<Type, std::integral_constant<decltype(Candidate), Candidate>>{&node.prop};
}
/**
* @brief Assigns a meta constructor to a meta type.
*
* A meta constructor is uniquely identified by the types of its arguments
* and is such that there exists an actual constructor of the underlying
* type that can be invoked with parameters whose types are those given.
*
* @tparam Args Types of arguments to use to construct an instance.
* @return An extended meta factory for the parent type.
*/
template<typename... Args>
auto ctor() ENTT_NOEXCEPT {
using helper_type = internal::meta_function_helper_t<Type, Type(*)(Args...)>;
auto * const type = internal::meta_info<Type>::resolve();
static internal::meta_ctor_node node{
type,
nullptr,
nullptr,
helper_type::args_type::size,
&helper_type::arg,
[](meta_any * const any) {
return internal::construct<Type, Args...>(any, std::make_index_sequence<helper_type::args_type::size>{});
}
};
ENTT_ASSERT(!exists(&node, type->ctor));
node.next = type->ctor;
type->ctor = &node;
return meta_factory<Type, Type(Args...)>{&node.prop};
}
/**
* @brief Assigns a meta destructor to a meta type.
*
* Free functions can be assigned to meta types in the role of destructors.
* The signature of the function should identical to the following:
*
* @code{.cpp}
* void(Type &);
* @endcode
*
* The purpose is to give users the ability to free up resources that
* require special treatment before an object is actually destroyed.
*
* @tparam Func The actual function to use as a destructor.
* @return A meta factory for the parent type.
*/
template<auto Func>
auto dtor() ENTT_NOEXCEPT {
static_assert(std::is_invocable_v<decltype(Func), Type &>, "The function doesn't accept an object of the type provided");
auto * const type = internal::meta_info<Type>::resolve();
ENTT_ASSERT(!type->dtor);
type->dtor = [](void *instance) {
if(instance) {
std::invoke(Func, *static_cast<Type *>(instance));
}
};
return meta_factory<Type>{};
}
/**
* @brief Assigns a meta data to a meta type.
*
* Both data members and static and global variables, as well as constants
* of any kind, can be assigned to a meta type.<br/>
* From a client's point of view, all the variables associated with the
* reflected object will appear as if they were part of the type itself.
*
* @tparam Data The actual variable to attach to the meta type.
* @tparam Policy Optional policy (no policy set by default).
* @param id Unique identifier.
* @return An extended meta factory for the parent type.
*/
template<auto Data, typename Policy = as_is_t>
auto data(const id_type id) ENTT_NOEXCEPT {
if constexpr(std::is_member_object_pointer_v<decltype(Data)>) {
return data<Data, Data, Policy>(id);
} else {
using data_type = std::remove_pointer_t<std::decay_t<decltype(Data)>>;
auto * const type = internal::meta_info<Type>::resolve();
static internal::meta_data_node node{
{},
type,
nullptr,
nullptr,
true,
&internal::meta_info<data_type>::resolve,
[]() -> std::remove_cv_t<decltype(internal::meta_data_node::set)> {
if constexpr(std::is_same_v<Type, data_type> || std::is_const_v<data_type>) {
return nullptr;
} else {
return &internal::setter<Type, Data>;
}
}(),
&internal::getter<Type, Data, Policy>
};
ENTT_ASSERT(!exists(id, type->data));
ENTT_ASSERT(!exists(&node, type->data));
node.id = id;
node.next = type->data;
type->data = &node;
return meta_factory<Type, std::integral_constant<decltype(Data), Data>>{&node.prop};
}
}
/**
* @brief Assigns a meta data to a meta type by means of its setter and
* getter.
*
* Setters and getters can be either free functions, member functions or a
* mix of them.<br/>
* In case of free functions, setters and getters must accept a reference to
* an instance of the parent type as their first argument. A setter has then
* an extra argument of a type convertible to that of the parameter to
* set.<br/>
* In case of member functions, getters have no arguments at all, while
* setters has an argument of a type convertible to that of the parameter to
* set.
*
* @tparam Setter The actual function to use as a setter.
* @tparam Getter The actual function to use as a getter.
* @tparam Policy Optional policy (no policy set by default).
* @param id Unique identifier.
* @return An extended meta factory for the parent type.
*/
template<auto Setter, auto Getter, typename Policy = as_is_t>
auto data(const id_type id) ENTT_NOEXCEPT {
using underlying_type = std::remove_reference_t<std::invoke_result_t<decltype(Getter), Type &>>;
auto * const type = internal::meta_info<Type>::resolve();
static internal::meta_data_node node{
{},
type,
nullptr,
nullptr,
false,
&internal::meta_info<underlying_type>::resolve,
[]() -> std::remove_cv_t<decltype(internal::meta_data_node::set)> {
if constexpr(std::is_same_v<decltype(Setter), std::nullptr_t> || (std::is_member_object_pointer_v<decltype(Setter)> && std::is_const_v<underlying_type>)) {
return nullptr;
} else {
return &internal::setter<Type, Setter>;
}
}(),
&internal::getter<Type, Getter, Policy>
};
ENTT_ASSERT(!exists(id, type->data));
ENTT_ASSERT(!exists(&node, type->data));
node.id = id;
node.next = type->data;
type->data = &node;
return meta_factory<Type, std::integral_constant<decltype(Setter), Setter>, std::integral_constant<decltype(Getter), Getter>>{&node.prop};
}
/**
* @brief Assigns a meta funcion to a meta type.
*
* Both member functions and free functions can be assigned to a meta
* type.<br/>
* From a client's point of view, all the functions associated with the
* reflected object will appear as if they were part of the type itself.
*
* @tparam Candidate The actual function to attach to the meta type.
* @tparam Policy Optional policy (no policy set by default).
* @param id Unique identifier.
* @return An extended meta factory for the parent type.
*/
template<auto Candidate, typename Policy = as_is_t>
auto func(const id_type id) ENTT_NOEXCEPT {
using helper_type = internal::meta_function_helper_t<Type, decltype(Candidate)>;
auto * const type = internal::meta_info<Type>::resolve();
static internal::meta_func_node node{
{},
type,
nullptr,
nullptr,
helper_type::args_type::size,
helper_type::is_const,
helper_type::is_static,
&internal::meta_info<std::conditional_t<std::is_same_v<Policy, as_void_t>, void, typename helper_type::return_type>>::resolve,
&helper_type::arg,
[](meta_handle instance, meta_any *args) {
return internal::invoke<Type, Candidate, Policy>(std::move(instance), args, std::make_index_sequence<helper_type::args_type::size>{});
}
};
ENTT_ASSERT(!exists(&node, type->func));
internal::meta_func_node **it = &type->func;
for(; *it && (*it)->id != id; it = &(*it)->next);
for(; *it && (*it)->id == id && (*it)->size < node.size; it = &(*it)->next);
node.id = id;
node.next = *it;
*it = &node;
return meta_factory<Type, std::integral_constant<decltype(Candidate), Candidate>>{&node.prop};
}
};