1 #ifndef ENTT_META_FACTORY_HPP
2 #define ENTT_META_FACTORY_HPP
10 #include "../config/config.h"
11 #include "../core/fwd.hpp"
12 #include "../core/type_info.hpp"
13 #include "../core/type_traits.hpp"
18 #include "utility.hpp"
38 template<
typename Type,
typename... Spec>
40 void link_prop_if_required(internal::meta_prop_node &node) ENTT_NOEXCEPT {
42 ENTT_ASSERT(std::find_if(range.cbegin(), range.cend(), [&node](
const auto *curr) { return curr->id == node.id; }) == range.cend(),
"Duplicate identifier");
48 template<std::size_t Step = 0,
typename... Property,
typename... Other>
49 void unroll(
choice_t<2>, std::tuple<Property...> property, Other &&...other) ENTT_NOEXCEPT {
50 std::apply([
this](
auto &&...curr) { (this->unroll<Step>(choice<2>, std::forward<Property>(curr)...)); }, property);
51 unroll<Step +
sizeof...(Property)>(choice<2>, std::forward<Other>(other)...);
54 template<std::size_t Step = 0,
typename... Property,
typename... Other>
55 void unroll(
choice_t<1>, std::pair<Property...> property, Other &&...other) ENTT_NOEXCEPT {
56 assign<Step>(std::move(property.first), std::move(property.second));
57 unroll<Step + 1>(choice<2>, std::forward<Other>(other)...);
60 template<std::size_t Step = 0,
typename Property,
typename... Other>
61 void unroll(
choice_t<0>, Property &&property, Other &&...other) ENTT_NOEXCEPT {
62 assign<Step>(std::forward<Property>(property));
63 unroll<Step + 1>(choice<2>, std::forward<Other>(other)...);
69 template<std::
size_t = 0>
73 static internal::meta_prop_node node{
80 property[0u] = std::move(key);
81 property[1u] = std::move(value);
83 link_prop_if_required(node);
105 template<
typename PropertyOrKey,
typename... Value>
107 if constexpr(
sizeof...(Value) == 0) {
108 unroll(choice<2>, std::forward<PropertyOrKey>(property_or_key));
110 assign(std::forward<PropertyOrKey>(property_or_key), std::forward<Value>(value)...);
125 template<
typename... Property>
127 unroll(choice<2>, std::forward<Property>(property)...);
132 internal::meta_prop_node **ref;
139 template<
typename Type>
141 void link_base_if_required(internal::meta_base_node &node) ENTT_NOEXCEPT {
143 node.next = owner->base;
148 void link_conv_if_required(internal::meta_conv_node &node) ENTT_NOEXCEPT {
150 node.next = owner->conv;
155 void link_ctor_if_required(internal::meta_ctor_node &node) ENTT_NOEXCEPT {
157 node.next = owner->ctor;
162 void link_data_if_required(
const id_type id, internal::meta_data_node &node) ENTT_NOEXCEPT {
164 ENTT_ASSERT(std::find_if(range.cbegin(), range.cend(), [
id, &node](
const auto *curr) { return curr != &node && curr->id == id; }) == range.cend(),
"Duplicate identifier");
167 if(std::find(range.cbegin(), range.cend(), &node) == range.cend()) {
168 node.next = owner->data;
173 void link_func_if_required(
const id_type id, internal::meta_func_node &node) ENTT_NOEXCEPT {
177 node.next = owner->func;
182 template<
typename Setter,
auto Getter,
typename Policy, std::size_t... Index>
183 auto data(
const id_type id, std::index_sequence<Index...>) ENTT_NOEXCEPT {
184 using data_type = std::invoke_result_t<decltype(Getter), Type &>;
186 static_assert(Policy::template value<data_type>,
"Invalid return type for the given policy");
188 static internal::meta_data_node node{
191 (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,
195 internal::meta_node<std::remove_cv_t<std::remove_reference_t<data_type>>>::
resolve(),
198 &meta_getter<Type, Getter, Policy>
202 link_data_if_required(
id, node);
203 return meta_factory<Type, Setter, std::integral_constant<decltype(Getter), Getter>>{&node.prop};
209 : owner{internal::meta_node<Type>::resolve()} {}
218 ENTT_ASSERT(std::find_if(range.cbegin(), range.cend(), [
id,
this](
const auto *curr) { return curr != owner && curr->id == id; }) == range.cend(),
"Duplicate identifier");
221 if(std::find(range.cbegin(), range.cend(), owner) == range.cend()) {
222 owner->next = *internal::meta_context::global();
223 *internal::meta_context::global() = owner;
237 template<
typename Base>
239 static_assert(!std::is_same_v<Type, Base> && std::is_base_of_v<Base, Type>,
"Invalid base type");
241 static internal::meta_base_node node{
243 internal::meta_node<Base>::resolve(),
245 if(
auto *ptr = other.data(); ptr) {
246 return forward_as_meta(*
static_cast<Base *
>(
static_cast<Type *
>(ptr)));
249 return forward_as_meta(*
static_cast<const Base *
>(
static_cast<const Type *
>(std::as_const(other).data())));
254 link_base_if_required(node);
270 template<auto Cand
idate>
272 static internal::meta_conv_node node{
274 internal::meta_node<std::remove_cv_t<std::remove_reference_t<std::invoke_result_t<decltype(Candidate), Type &>>>>
::resolve(),
276 return forward_as_meta(std::invoke(Candidate, *
static_cast<const Type *
>(instance.data())));
281 link_conv_if_required(node);
294 template<
typename To>
296 static internal::meta_conv_node node{
298 internal::meta_node<std::remove_cv_t<std::remove_reference_t<To>>>
::resolve(),
303 link_conv_if_required(node);
320 template<auto Cand
idate,
typename Policy = as_is_t>
323 static_assert(Policy::template value<typename descriptor::return_type>,
"Invalid return type for the given policy");
324 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");
326 static internal::meta_ctor_node node{
328 descriptor::args_type::size,
329 &meta_arg<typename descriptor::args_type>,
330 &meta_construct<Type, Candidate, Policy>
334 link_ctor_if_required(node);
348 template<
typename... Args>
352 static internal::meta_ctor_node node{
354 descriptor::args_type::size,
355 &meta_arg<typename descriptor::args_type>,
360 link_ctor_if_required(node);
384 static_assert(std::is_invocable_v<decltype(Func), Type &>,
"The function doesn't accept an object of the type provided");
385 owner->dtor = [](
void *instance) { std::invoke(Func, *
static_cast<Type *
>(instance)); };
402 template<auto Data,
typename Policy = as_is_t>
404 if constexpr(std::is_member_object_pointer_v<decltype(Data)>) {
405 using data_type = std::remove_reference_t<std::invoke_result_t<decltype(Data), Type &>>;
407 static internal::meta_data_node node{
410 std::is_const_v<data_type> ? internal::meta_traits::is_const : internal::meta_traits::is_none,
414 internal::meta_node<std::remove_const_t<data_type>>
::resolve(),
415 &meta_arg<type_list<std::remove_const_t<data_type>>>,
416 &meta_setter<Type, Data>,
417 &meta_getter<Type, Data, Policy>
421 link_data_if_required(
id, node);
422 return meta_factory<Type, std::integral_constant<decltype(Data), Data>, std::integral_constant<decltype(Data), Data>>{&node.prop};
424 using data_type = std::remove_reference_t<std::remove_pointer_t<decltype(Data)>>;
426 static internal::meta_data_node node{
428 ((std::is_same_v<Type, std::remove_const_t<data_type>> || std::is_const_v<data_type>) ? internal::meta_traits::is_const : internal::meta_traits::is_none) | internal::meta_traits::is_static,
432 internal::meta_node<std::remove_const_t<data_type>>
::resolve(),
433 &meta_arg<type_list<std::remove_const_t<data_type>>>,
434 &meta_setter<Type, Data>,
435 &meta_getter<Type, Data, Policy>
439 link_data_if_required(
id, node);
440 return meta_factory<Type, std::integral_constant<decltype(Data), Data>>{&node.prop};
464 template<auto Setter, auto Getter,
typename Policy = as_is_t>
466 using data_type = std::invoke_result_t<decltype(Getter), Type &>;
467 static_assert(Policy::template value<data_type>,
"Invalid return type for the given policy");
469 if constexpr(std::is_same_v<decltype(Setter), std::nullptr_t>) {
470 static internal::meta_data_node node{
473 internal::meta_traits::is_const,
477 internal::meta_node<std::remove_cv_t<std::remove_reference_t<data_type>>>
::resolve(),
478 &meta_arg<type_list<>>,
479 &meta_setter<Type, Setter>,
480 &meta_getter<Type, Getter, Policy>
484 link_data_if_required(
id, node);
485 return meta_factory<Type, std::integral_constant<decltype(Setter), Setter>, std::integral_constant<decltype(Getter), Getter>>{&node.prop};
489 static internal::meta_data_node node{
492 internal::meta_traits::is_none,
496 internal::meta_node<std::remove_cv_t<std::remove_reference_t<data_type>>>
::resolve(),
497 &meta_arg<type_list<type_list_element_t<args_type::size != 1u, args_type>>>,
498 &meta_setter<Type, Setter>,
499 &meta_getter<Type, Getter, Policy>
503 link_data_if_required(
id, node);
504 return meta_factory<Type, std::integral_constant<decltype(Setter), Setter>, std::integral_constant<decltype(Getter), Getter>>{&node.prop};
525 template<
typename Setter, auto Getter,
typename Policy = as_is_t>
527 return data<Setter, Getter, Policy>(
id, std::make_index_sequence<Setter::size>{});
543 template<auto Cand
idate,
typename Policy = as_is_t>
546 static_assert(Policy::template value<typename descriptor::return_type>,
"Invalid return type for the given policy");
548 static internal::meta_func_node node{
550 (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),
553 descriptor::args_type::size,
554 internal::meta_node<std::conditional_t<std::is_same_v<Policy, as_void_t>, void, std::remove_cv_t<std::remove_reference_t<typename descriptor::return_type>>>>
::resolve(),
555 &meta_arg<typename descriptor::args_type>,
556 &meta_invoke<Type, Candidate, Policy>
560 link_func_if_required(
id, node);
561 return meta_factory<Type, std::integral_constant<decltype(Candidate), Candidate>>{&node.prop};
565 internal::meta_type_node *owner;
579 template<
typename Type>
580 [[nodiscard]]
auto meta() ENTT_NOEXCEPT {
581 auto *
const node = internal::meta_node<Type>::resolve();
598 auto clear_chain = [](
auto **curr,
auto... member) {
599 for(; *curr; *curr = std::exchange((*curr)->next,
nullptr)) {
600 if constexpr(
sizeof...(member) != 0u) {
601 static_assert(
sizeof...(member) == 1u,
"Assert in defense of the future me");
602 for(
auto **sub = (&((*curr)->*member), ...); *sub; *sub = std::exchange((*sub)->next,
nullptr)) {}
607 for(
auto **it = internal::meta_context::global(); *it; it = &(*it)->next) {
608 if(
auto *node = *it; node->id == id) {
609 clear_chain(&node->prop);
610 clear_chain(&node->base);
611 clear_chain(&node->conv);
612 clear_chain(&node->ctor);
613 clear_chain(&node->data, &internal::meta_data_node::prop);
614 clear_chain(&node->func, &internal::meta_func_node::prop);
617 node->dtor =
nullptr;
618 *it = std::exchange(node->next,
nullptr);
632 template<
typename Type>
634 meta_reset(internal::meta_node<Type>::resolve()->
id);
643 while(*internal::meta_context::global()) {
644 meta_reset((*internal::meta_context::global())->
id);
meta_type resolve()
Returns the meta type associated with a given type.
std::uint32_t id_type
Alias declaration for type identifiers.
auto meta()
Utility function to use for reflection.
meta_any meta_construct(meta_any *const args)
Tries to construct an instance given a list of erased parameters.
void meta_reset(const id_type id)
Resets a type and all its parts.
typename meta_function_helper< Type, Candidate >::type meta_function_helper_t
Helper type.
meta_any forward_as_meta(Type &&value)
Forwards its argument and avoids copies for lvalue references.
typename type_list_element< Index, List >::type type_list_element_t
Helper type.
bool meta_setter([[maybe_unused]] meta_handle instance, [[maybe_unused]] meta_any value)
Sets the value of a given variable.
Utility class to disambiguate overloaded functions.
Utility class to disambiguate overloaded functions.
A class to use to push around lists of types, nothing more.