1#ifndef ENTT_META_FACTORY_HPP
2#define ENTT_META_FACTORY_HPP
11#include "../config/config.h"
12#include "../core/bit.hpp"
13#include "../core/fwd.hpp"
14#include "../core/type_info.hpp"
15#include "../core/type_traits.hpp"
16#include "../locator/locator.hpp"
30class basic_meta_factory {
31 using invoke_type = std::remove_pointer_t<
decltype(meta_func_node::invoke)>;
33 auto *find_member_or_assert() {
34 auto *member = find_member<&meta_data_node::id>(details->data, bucket);
35 ENTT_ASSERT(member !=
nullptr,
"Cannot find member");
39 auto *find_overload_or_assert() {
40 auto *
overload = find_overload(find_member<&meta_func_node::id>(details->func, bucket), invoke);
41 ENTT_ASSERT(overload !=
nullptr,
"Cannot find overload");
45 void reset_bucket(
const id_type
id, invoke_type *
const ref =
nullptr) {
51 void type(
const id_type
id)
noexcept {
53 auto &&elem = meta_context::from(*ctx).value[parent];
54 ENTT_ASSERT(elem.id ==
id || !
resolve(*ctx,
id),
"Duplicate identifier");
58 template<
typename Type>
59 void insert_or_assign(Type node) {
62 if constexpr(std::is_same_v<Type, meta_base_node>) {
63 auto *member = find_member<&meta_base_node::type>(details->base, node.type);
64 member ? (*member = node) : details->base.emplace_back(node);
65 }
else if constexpr(std::is_same_v<Type, meta_conv_node>) {
66 auto *member = find_member<&meta_conv_node::type>(details->conv, node.type);
67 member ? (*member = node) : details->conv.emplace_back(node);
69 static_assert(std::is_same_v<Type, meta_ctor_node>,
"Unexpected type");
70 auto *member = find_member<&meta_ctor_node::id>(details->ctor, node.id);
71 member ? (*member = node) : details->ctor.emplace_back(node);
75 void dtor(meta_dtor_node node) {
77 meta_context::from(*ctx).value[parent].dtor = node;
80 void data(meta_data_node node) {
81 reset_bucket(node.id);
83 if(
auto *member = find_member<&meta_data_node::id>(details->data, node.id); member ==
nullptr) {
84 details->data.emplace_back(std::move(node));
85 }
else if(member->set != node.set || member->get != node.get) {
86 *member = std::move(node);
90 void func(meta_func_node node) {
91 reset_bucket(node.id, node.invoke);
93 if(
auto *member = find_member<&meta_func_node::id>(details->func, node.id); member ==
nullptr) {
94 details->func.emplace_back(std::move(node));
95 }
else if(
auto *overload = find_overload(member, node.invoke); overload ==
nullptr) {
96 while(member->next !=
nullptr) { member = member->next.get(); }
97 member->next = std::make_shared<meta_func_node>(std::move(node));
101 void prop(meta_prop_node node) {
102 std::vector<meta_prop_node> *container =
nullptr;
104 if(bucket == parent) {
105 container = &details->prop;
106 }
else if(invoke ==
nullptr) {
107 container = &find_member_or_assert()->prop;
109 container = &find_overload_or_assert()->prop;
112 auto *member = find_member<&meta_prop_node::id>(*container, node.id);
113 (member !=
nullptr) ? (*member = std::move(node)) : container->emplace_back(std::move(node));
116 void traits(
const meta_traits value) {
117 if(bucket == parent) {
118 meta_context::from(*ctx).value[bucket].traits |= value;
119 }
else if(invoke ==
nullptr) {
120 find_member_or_assert()->traits |= value;
122 find_overload_or_assert()->traits |= value;
126 void custom(meta_custom_node node) {
127 if(bucket == parent) {
128 meta_context::from(*ctx).value[bucket].custom = std::move(node);
129 }
else if(invoke ==
nullptr) {
130 find_member_or_assert()->custom = std::move(node);
132 find_overload_or_assert()->custom = std::move(node);
137 basic_meta_factory(
const id_type
id, meta_ctx &area)
141 auto &&elem = meta_context::from(*ctx).value[parent];
144 elem.details = std::make_shared<meta_type_descriptor>();
147 details = elem.details.get();
155 meta_type_descriptor *details{};
165template<
typename Type>
167 using base_type = internal::basic_meta_factory;
169 template<
typename Setter,
auto Getter,
typename Policy, std::size_t... Index>
170 void data(
const id_type id, std::index_sequence<Index...>)
noexcept {
171 using data_type = std::invoke_result_t<
decltype(Getter), Type &>;
173 static_assert(Policy::template value<data_type>,
"Invalid return type for the given policy");
176 internal::meta_data_node{
179 (std::is_member_object_pointer_v<
decltype(
value_list_element_v<Index, Setter>)> && ... && std::is_const_v<std::remove_reference_t<data_type>>) ? internal::meta_traits::is_const : internal::meta_traits::is_none,
181 &internal::resolve<std::remove_cv_t<std::remove_reference_t<data_type>>>,
217 template<
typename Base>
219 static_assert(!std::is_same_v<Type, Base> && std::is_base_of_v<Base, Type>,
"Invalid base type");
220 auto *
const op = +[](
const void *instance)
noexcept {
return static_cast<const void *
>(
static_cast<const Base *
>(
static_cast<const Type *
>(instance))); };
221 base_type::insert_or_assign(internal::meta_base_node{
type_id<Base>().
hash(), &internal::resolve<Base>, op});
237 template<auto Cand
idate>
239 using conv_type = std::remove_cv_t<std::remove_reference_t<std::invoke_result_t<
decltype(Candidate), Type &>>>;
240 auto *
const op = +[](
const meta_ctx &area,
const void *instance) {
return forward_as_meta(area, std::invoke(Candidate, *
static_cast<const Type *
>(instance))); };
254 template<
typename To>
256 using conv_type = std::remove_cv_t<std::remove_reference_t<To>>;
257 auto *
const op = +[](
const meta_ctx &area,
const void *instance) {
return forward_as_meta(area,
static_cast<To
>(*
static_cast<const Type *
>(instance))); };
275 template<auto Cand
idate,
typename Policy = as_is_t>
278 static_assert(Policy::template value<typename descriptor::return_type>,
"Invalid return type for the given policy");
279 static_assert(std::is_same_v<std::remove_cv_t<std::remove_reference_t<typename descriptor::return_type>>, Type>,
"The function doesn't return an object of the required type");
294 template<
typename... Args>
297 if constexpr(
sizeof...(Args) != 0u) {
325 static_assert(std::is_invocable_v<
decltype(Func), Type &>,
"The function doesn't accept an object of the type provided");
326 auto *
const op = +[](
void *instance) { std::invoke(Func, *
static_cast<Type *
>(instance)); };
327 base_type::dtor(internal::meta_dtor_node{op});
344 template<auto Data,
typename Policy = as_is_t>
346 if constexpr(std::is_member_object_pointer_v<
decltype(Data)>) {
347 using data_type = std::invoke_result_t<
decltype(Data), Type &>;
348 static_assert(Policy::template value<data_type>,
"Invalid return type for the given policy");
351 internal::meta_data_node{
354 std::is_const_v<std::remove_reference_t<data_type>> ? internal::meta_traits::is_const : internal::meta_traits::is_none,
356 &internal::resolve<std::remove_cv_t<std::remove_reference_t<data_type>>>,
357 &meta_arg<type_list<std::remove_cv_t<std::remove_reference_t<data_type>>>>,
361 using data_type = std::remove_pointer_t<
decltype(Data)>;
363 if constexpr(std::is_pointer_v<
decltype(Data)>) {
364 static_assert(Policy::template value<
decltype(*Data)>,
"Invalid return type for the given policy");
366 static_assert(Policy::template value<data_type>,
"Invalid return type for the given policy");
370 internal::meta_data_node{
372 ((std::is_same_v<Type, std::remove_cv_t<std::remove_reference_t<data_type>>> || std::is_const_v<std::remove_reference_t<data_type>>) ? internal::meta_traits::is_const : internal::meta_traits::is_none) | internal::meta_traits::is_static,
374 &internal::resolve<std::remove_cv_t<std::remove_reference_t<data_type>>>,
375 &meta_arg<
type_list<std::remove_cv_t<std::remove_reference_t<data_type>>>>,
403 template<auto Setter, auto Getter,
typename Policy = as_is_t>
405 using data_type = std::invoke_result_t<
decltype(Getter), Type &>;
406 static_assert(Policy::template value<data_type>,
"Invalid return type for the given policy");
408 if constexpr(std::is_same_v<
decltype(Setter), std::nullptr_t>) {
410 internal::meta_data_node{
413 internal::meta_traits::is_const,
415 &internal::resolve<std::remove_cv_t<std::remove_reference_t<data_type>>>,
416 &meta_arg<type_list<>>,
423 internal::meta_data_node{
426 internal::meta_traits::is_none,
428 &internal::resolve<std::remove_cv_t<std::remove_reference_t<data_type>>>,
429 &meta_arg<type_list<type_list_element_t<args_type::size != 1u, args_type>>>,
454 template<
typename Setter, auto Getter,
typename Policy = as_is_t>
456 data<Setter, Getter, Policy>(
id, std::make_index_sequence<Setter::size>{});
473 template<auto Cand
idate,
typename Policy = as_is_t>
476 static_assert(Policy::template value<typename descriptor::return_type>,
"Invalid return type for the given policy");
479 internal::meta_func_node{
481 (descriptor::is_const ? internal::meta_traits::is_const : internal::meta_traits::is_none) | (descriptor::is_static ? internal::meta_traits::is_static : internal::meta_traits::is_none),
482 descriptor::args_type::size,
483 &internal::resolve<std::conditional_t<std::is_same_v<Policy, as_void_t>, void, std::remove_cv_t<std::remove_reference_t<typename descriptor::return_type>>>>,
484 &meta_arg<typename descriptor::args_type>,
500 template<
typename... Value>
502 if constexpr(
sizeof...(Value) == 0u) {
503 base_type::prop(internal::meta_prop_node{id, &internal::resolve<void>});
505 base_type::prop(internal::meta_prop_node{id, &internal::resolve<std::decay_t<Value>>..., std::make_shared<std::decay_t<Value>>(std::forward<Value>(value))...});
520 template<
typename Value>
522 static_assert(std::is_enum_v<Value>,
"Invalid enum type");
523 base_type::traits(internal::user_to_meta_traits(value));
534 template<
typename Value,
typename... Args>
536 base_type::custom(internal::meta_custom_node{
type_id<Value>().
hash(), std::make_shared<Value>(std::forward<Args>(args)...)});
553template<
typename Type>
555 auto &&context = internal::meta_context::from(ctx);
557 context.value.try_emplace(
type_id<Type>().hash(), internal::resolve<Type>(context));
572template<
typename Type>
573[[nodiscard]]
auto meta() noexcept {
590 auto &&context = internal::meta_context::from(ctx);
592 for(
auto it = context.value.begin(); it != context.value.end();) {
593 if(it->second.id ==
id) {
594 it = context.value.erase(it);
624template<
typename Type>
626 internal::meta_context::from(ctx).value.erase(
type_id<Type>().hash());
636template<
typename Type>
649 internal::meta_context::from(ctx).value.clear();
Service locator, nothing more.
static Service & value_or(Args &&...args)
Returns a service if available or sets it from a fallback type.
std::enable_if_t< is_meta_policy_v< Policy >, meta_any > meta_invoke(const meta_ctx &ctx, meta_handle instance, Candidate &&candidate, meta_any *const args)
Tries to invoke an object given a list of erased parameters.
typename meta_function_helper< Type, Candidate >::type meta_function_helper_t
Helper type.
constexpr auto value_list_element_v
Helper type.
meta_any meta_construct(const meta_ctx &ctx, meta_any *const args)
Tries to construct an instance given a list of erased parameters.
std::uint32_t id_type
Alias declaration for type identifiers.
auto meta() noexcept
Utility function to use for reflection.
typename type_list_element< Index, List >::type type_list_element_t
Helper type.
std::enable_if_t< is_meta_policy_v< Policy >, meta_any > meta_getter(const meta_ctx &ctx, meta_handle instance)
Gets the value of a given variable.
void meta_reset() noexcept
Resets a type and all its parts.
meta_any forward_as_meta(const meta_ctx &ctx, Type &&value)
Forwards its argument and avoids copies for lvalue references.
bool meta_setter(meta_handle instance, meta_any value)
Sets the value of a given variable.
void invoke(Registry ®, const typename Registry::entity_type entt)
Helper to create a listener that directly invokes a member function.
constexpr auto overload(Type Class::*member) noexcept
Constant utility to disambiguate overloaded members of a class.
meta_type resolve(const meta_ctx &ctx) noexcept
Returns the meta type associated with a given type.
const type_info & type_id() noexcept
Returns the type info object associated to a given type.
@ ref
Aliasing mode, the object points to a non-const element.
constexpr id_type hash() const noexcept
Type hash.
A class to use to push around lists of types, nothing more.