1 #ifndef ENTT_META_FACTORY_HPP
2 #define ENTT_META_FACTORY_HPP
11 #include "../config/config.h"
12 #include "../core/fwd.hpp"
13 #include "../core/type_info.hpp"
14 #include "../core/type_traits.hpp"
15 #include "internal.hpp"
32 template<
typename,
bool = false>
33 struct meta_function_helper;
36 template<
typename Ret,
typename... Args,
bool Const>
37 struct meta_function_helper<Ret(Args...), Const> {
38 using return_type = std::remove_cv_t<std::remove_reference_t<Ret>>;
39 using args_type = std::tuple<std::remove_cv_t<std::remove_reference_t<Args>>...>;
41 static constexpr
auto is_const = Const;
43 [[nodiscard]]
static auto arg(
typename internal::meta_func_node::size_type index) ENTT_NOEXCEPT {
44 return std::array<meta_type_node *,
sizeof...(Args)>{{meta_info<Args>::resolve()...}}[index];
49 template<
typename Ret,
typename... Args,
typename Class>
50 constexpr meta_function_helper<Ret(Args...),
true>
51 to_meta_function_helper(Ret(Class:: *)(Args...)
const);
54 template<
typename Ret,
typename... Args,
typename Class>
55 constexpr meta_function_helper<Ret(Args...)>
56 to_meta_function_helper(Ret(Class:: *)(Args...));
59 template<
typename Ret,
typename... Args>
60 constexpr meta_function_helper<Ret(Args...)>
61 to_meta_function_helper(Ret(*)(Args...));
64 constexpr
void to_meta_function_helper(...);
67 template<
typename Cand
idate>
68 using meta_function_helper_t = decltype(to_meta_function_helper(std::declval<Candidate>()));
71 template<
typename Type,
typename... Args, std::size_t... Indexes>
72 [[nodiscard]] meta_any construct(meta_any *
const args, std::index_sequence<Indexes...>) {
73 [[maybe_unused]]
auto direct = std::make_tuple((args+Indexes)->try_cast<Args>()...);
74 return ((std::get<Indexes>(direct) || (args+Indexes)->convert<Args>()) && ...)
75 ? Type{(std::get<Indexes>(direct) ? *std::get<Indexes>(direct) : (args+Indexes)->cast<Args>())...}
80 template<
typename Type, auto Data>
81 [[nodiscard]]
bool setter([[maybe_unused]] meta_handle instance, [[maybe_unused]] meta_any value) {
82 bool accepted =
false;
84 if constexpr(std::is_function_v<std::remove_reference_t<std::remove_pointer_t<decltype(Data)>>> || std::is_member_function_pointer_v<decltype(Data)>) {
85 using helper_type = meta_function_helper_t<decltype(Data)>;
86 using data_type = std::tuple_element_t<!std::is_member_function_pointer_v<decltype(Data)>,
typename helper_type::args_type>;
88 if(
auto *
const clazz = instance->try_cast<Type>(); clazz) {
89 if(
auto *
const direct = value.try_cast<data_type>(); direct || value.convert<data_type>()) {
90 std::invoke(Data, *clazz, direct ? *direct : value.cast<data_type>());
94 }
else if constexpr(std::is_member_object_pointer_v<decltype(Data)>) {
95 using data_type = std::remove_cv_t<std::remove_reference_t<decltype(std::declval<Type>().*Data)>>;
97 if constexpr(!std::is_array_v<data_type>) {
98 if(
auto *
const clazz = instance->try_cast<Type>(); clazz) {
99 if(
auto *
const direct = value.try_cast<data_type>(); direct || value.convert<data_type>()) {
100 std::invoke(Data, clazz) = (direct ? *direct : value.cast<data_type>());
106 using data_type = std::remove_cv_t<std::remove_reference_t<decltype(*Data)>>;
108 if constexpr(!std::is_array_v<data_type>) {
109 if(
auto *
const direct = value.try_cast<data_type>(); direct || value.convert<data_type>()) {
110 *Data = (direct ? *direct : value.cast<data_type>());
120 template<
typename Type, auto Data,
typename Policy>
121 [[nodiscard]] meta_any getter([[maybe_unused]] meta_handle instance) {
122 [[maybe_unused]]
auto dispatch = [](
auto &&value) {
123 if constexpr(std::is_same_v<Policy, as_void_t>) {
124 return meta_any{std::in_place_type<void>, std::forward<decltype(value)>(value)};
125 }
else if constexpr(std::is_same_v<Policy, as_ref_t>) {
126 return meta_any{std::ref(std::forward<decltype(value)>(value))};
128 static_assert(std::is_same_v<Policy, as_is_t>,
"Policy not supported");
129 return meta_any{std::forward<decltype(value)>(value)};
133 if constexpr(std::is_function_v<std::remove_reference_t<std::remove_pointer_t<decltype(Data)>>> || std::is_member_function_pointer_v<decltype(Data)>) {
134 auto *
const clazz = instance->try_cast<Type>();
135 return clazz ? dispatch(std::invoke(Data, *clazz)) : meta_any{};
136 }
else if constexpr(std::is_member_object_pointer_v<decltype(Data)>) {
137 if constexpr(std::is_array_v<std::remove_cv_t<std::remove_reference_t<decltype(std::declval<Type>().*Data)>>>) {
140 auto *
const clazz = instance->try_cast<Type>();
141 return clazz ? dispatch(std::invoke(Data, clazz)) : meta_any{};
143 }
else if constexpr(std::is_pointer_v<std::decay_t<decltype(Data)>>) {
144 if constexpr(std::is_array_v<std::remove_pointer_t<decltype(Data)>>) {
147 return dispatch(*Data);
150 return dispatch(Data);
155 template<
typename Type,
auto Candidate,
typename Policy, std::size_t... Indexes>
156 [[nodiscard]] meta_any
invoke([[maybe_unused]] meta_handle instance, meta_any *args, std::index_sequence<Indexes...>) {
157 using helper_type = meta_function_helper_t<decltype(Candidate)>;
159 auto dispatch = [](
auto *... params) {
160 if constexpr(std::is_void_v<typename helper_type::return_type> || std::is_same_v<Policy, as_void_t>) {
161 std::invoke(Candidate, *params...);
162 return meta_any{std::in_place_type<void>};
163 }
else if constexpr(std::is_same_v<Policy, as_ref_t>) {
164 return meta_any{std::ref(std::invoke(Candidate, *params...))};
166 static_assert(std::is_same_v<Policy, as_is_t>,
"Policy not supported");
167 return meta_any{std::invoke(Candidate, *params...)};
171 [[maybe_unused]]
const auto direct = std::make_tuple([](meta_any *any,
auto *value) {
172 using arg_type = std::remove_reference_t<decltype(*value)>;
174 if(!value && any->convert<arg_type>()) {
175 value = any->try_cast<arg_type>();
179 }(args+Indexes, (args+Indexes)->try_cast<std::tuple_element_t<Indexes, typename helper_type::args_type>>())...);
181 if constexpr(std::is_function_v<std::remove_reference_t<std::remove_pointer_t<decltype(Candidate)>>>) {
182 return (std::get<Indexes>(direct) && ...) ? dispatch(std::get<Indexes>(direct)...) : meta_any{};
184 auto *
const clazz = instance->try_cast<Type>();
185 return (clazz && (std::get<Indexes>(direct) && ...)) ? dispatch(clazz, std::get<Indexes>(direct)...) : meta_any{};
207 template<
typename...>
216 template<
typename Type,
typename... Spec>
218 [[nodiscard]]
bool exists(
const meta_any &key,
const internal::meta_prop_node *node) ENTT_NOEXCEPT {
219 return node && (node->key() == key || exists(key, node->next));
222 template<std::size_t Step = 0, std::size_t... Index,
typename... Property,
typename... Other>
223 void unpack(std::index_sequence<Index...>, std::tuple<Property...> property, Other &&... other) {
224 unroll<Step>(choice<3>, std::move(std::get<Index>(property))..., std::forward<Other>(other)...);
227 template<std::size_t Step = 0,
typename... Property,
typename... Other>
228 void unroll(
choice_t<3>, std::tuple<Property...> property, Other &&... other) {
229 unpack<Step>(std::index_sequence_for<Property...>{}, std::move(property), std::forward<Other>(other)...);
232 template<std::size_t Step = 0,
typename... Property,
typename... Other>
233 void unroll(
choice_t<2>, std::pair<Property...> property, Other &&... other) {
234 assign<Step>(std::move(property.first), std::move(property.second));
235 unroll<Step+1>(choice<3>, std::forward<Other>(other)...);
238 template<std::size_t Step = 0,
typename Property,
typename... Other>
239 std::enable_if_t<!std::is_invocable_v<Property>>
240 unroll(
choice_t<1>, Property &&property, Other &&... other) {
241 assign<Step>(std::forward<Property>(property));
242 unroll<Step+1>(choice<3>, std::forward<Other>(other)...);
245 template<std::size_t Step = 0,
typename Func,
typename... Other>
246 void unroll(
choice_t<0>, Func &&invocable, Other &&... other) {
247 unroll<Step>(choice<3>, std::forward<Func>(invocable)(), std::forward<Other>(other)...);
250 template<std::
size_t>
253 template<std::size_t = 0,
typename Key,
typename... Value>
254 void assign(Key &&key, Value &&... value) {
255 static const auto property{std::make_tuple(std::forward<Key>(key), std::forward<Value>(value)...)};
257 static internal::meta_prop_node node{
260 return std::get<0>(property);
263 if constexpr(
sizeof...(Value) == 0) {
266 return std::get<1>(property);
271 ENTT_ASSERT(!exists(node.key(), *curr));
296 template<
typename PropertyOrKey,
typename... Value>
297 auto prop(PropertyOrKey &&property_or_key, Value &&... value) && {
298 if constexpr(
sizeof...(Value) == 0) {
299 unroll(choice<3>, std::forward<PropertyOrKey>(property_or_key));
301 assign(std::forward<PropertyOrKey>(property_or_key), std::forward<Value>(value)...);
304 return meta_factory<Type, Spec..., PropertyOrKey, Value...>{curr};
317 template <
typename... Property>
318 auto props(Property... property) && {
319 unroll(choice<3>, std::forward<Property>(property)...);
324 internal::meta_prop_node **curr;
332 template<
typename Type>
334 template<
typename Node>
335 bool exists(
const Node *candidate,
const Node *node) ENTT_NOEXCEPT {
336 return node && (node == candidate || exists(candidate, node->next));
339 template<
typename Node>
340 bool exists(
const id_type id,
const Node *node) ENTT_NOEXCEPT {
341 return node && (node->id ==
id || exists(
id, node->next));
351 auto *
const node = internal::meta_info<Type>::resolve();
353 ENTT_ASSERT(!exists(
id, *internal::meta_context::global()));
354 ENTT_ASSERT(!exists(node, *internal::meta_context::global()));
356 node->next = *internal::meta_context::global();
357 *internal::meta_context::global() = node;
370 template<
typename Base>
372 static_assert(std::is_base_of_v<Base, Type>,
"Invalid base type");
373 auto *
const type = internal::meta_info<Type>::resolve();
375 static internal::meta_base_node node{
378 &internal::meta_info<Base>::resolve,
379 [](
const void *instance) ENTT_NOEXCEPT ->
const void * {
380 return static_cast<const Base *
>(
static_cast<const Type *
>(instance));
384 ENTT_ASSERT(!exists(&node, type->base));
385 node.next = type->base;
400 template<
typename To>
402 static_assert(std::is_convertible_v<Type, To>,
"Could not convert to the required type");
403 auto *
const type = internal::meta_info<Type>::resolve();
405 static internal::meta_conv_node node{
408 &internal::meta_info<To>::resolve,
409 [](
const void *instance) ->
meta_any {
410 return static_cast<To
>(*
static_cast<const Type *
>(instance));
414 ENTT_ASSERT(!exists(&node, type->conv));
415 node.next = type->conv;
433 template<auto Cand
idate>
435 using conv_type = std::invoke_result_t<decltype(Candidate), Type &>;
436 auto *
const type = internal::meta_info<Type>::resolve();
438 static internal::meta_conv_node node{
441 &internal::meta_info<conv_type>::resolve,
442 [](
const void *instance) ->
meta_any {
443 return std::invoke(Candidate, *
static_cast<const Type *
>(instance));
447 ENTT_ASSERT(!exists(&node, type->conv));
448 node.next = type->conv;
467 template<auto Func,
typename Policy = as_is_t>
469 using helper_type = internal::meta_function_helper_t<decltype(Func)>;
470 static_assert(std::is_same_v<typename helper_type::return_type, Type>,
"The function doesn't return an object of the required type");
471 auto *
const type = internal::meta_info<Type>::resolve();
473 static internal::meta_ctor_node node{
477 std::tuple_size_v<typename helper_type::args_type>,
480 return internal::invoke<Type, Func, Policy>({}, any, std::make_index_sequence<std::tuple_size_v<typename helper_type::args_type>>{});
484 ENTT_ASSERT(!exists(&node, type->ctor));
485 node.next = type->ctor;
488 return meta_factory<Type, std::integral_constant<decltype(Func), Func>>{&node.prop};
501 template<
typename... Args>
503 using helper_type = internal::meta_function_helper_t<Type(*)(Args...)>;
504 auto *
const type = internal::meta_info<Type>::resolve();
506 static internal::meta_ctor_node node{
510 std::tuple_size_v<typename helper_type::args_type>,
513 return internal::construct<Type, std::remove_cv_t<std::remove_reference_t<Args>>...>(any, std::make_index_sequence<std::tuple_size_v<typename helper_type::args_type>>{});
517 ENTT_ASSERT(!exists(&node, type->ctor));
518 node.next = type->ctor;
542 static_assert(std::is_invocable_v<decltype(Func), Type &>,
"The function doesn't accept an object of the type provided");
543 auto *
const type = internal::meta_info<Type>::resolve();
545 ENTT_ASSERT(!type->dtor);
547 type->dtor = [](
void *instance) {
549 std::invoke(Func, *
static_cast<Type *
>(instance));
569 template<auto Data,
typename Policy = as_is_t>
571 if constexpr(std::is_member_object_pointer_v<decltype(Data)>) {
572 return data<Data, Data, Policy>(
id);
574 using data_type = std::remove_pointer_t<std::decay_t<decltype(Data)>>;
575 auto *
const type = internal::meta_info<Type>::resolve();
577 static internal::meta_data_node node{
583 &internal::meta_info<data_type>::resolve,
584 []() -> std::remove_const_t<decltype(internal::meta_data_node::set)> {
585 if constexpr(std::is_same_v<Type, data_type> || std::is_const_v<data_type>) {
588 return &internal::setter<Type, Data>;
591 &internal::getter<Type, Data, Policy>
594 ENTT_ASSERT(!exists(
id, type->data));
595 ENTT_ASSERT(!exists(&node, type->data));
597 node.next = type->data;
600 return meta_factory<Type, std::integral_constant<decltype(Data), Data>>{&node.prop};
624 template<auto Setter, auto Getter,
typename Policy = as_is_t>
626 using underlying_type = std::remove_reference_t<std::invoke_result_t<decltype(Getter), Type &>>;
627 auto *
const type = internal::meta_info<Type>::resolve();
629 static internal::meta_data_node node{
635 &internal::meta_info<underlying_type>::resolve,
636 []() -> std::remove_const_t<decltype(internal::meta_data_node::set)> {
637 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>)) {
640 return &internal::setter<Type, Setter>;
643 &internal::getter<Type, Getter, Policy>
646 ENTT_ASSERT(!exists(
id, type->data));
647 ENTT_ASSERT(!exists(&node, type->data));
649 node.next = type->data;
652 return meta_factory<Type, std::integral_constant<decltype(Setter), Setter>, std::integral_constant<decltype(Getter), Getter>>{&node.prop};
668 template<auto Cand
idate,
typename Policy = as_is_t>
670 using helper_type = internal::meta_function_helper_t<decltype(Candidate)>;
671 auto *
const type = internal::meta_info<Type>::resolve();
673 static internal::meta_func_node node{
678 std::tuple_size_v<typename helper_type::args_type>,
679 helper_type::is_const,
680 !std::is_member_function_pointer_v<decltype(Candidate)>,
681 &internal::meta_info<std::conditional_t<std::is_same_v<Policy, as_void_t>, void,
typename helper_type::return_type>>
::resolve,
684 return internal::invoke<Type, Candidate, Policy>(*instance, args, std::make_index_sequence<std::tuple_size_v<typename helper_type::args_type>>{});
688 ENTT_ASSERT(!exists(
id, type->func));
689 ENTT_ASSERT(!exists(&node, type->func));
691 node.next = type->func;
694 return meta_factory<Type, std::integral_constant<decltype(Candidate), Candidate>>{&node.prop};
710 template<
typename Type>
711 [[nodiscard]]
auto meta() ENTT_NOEXCEPT {
712 auto *
const node = internal::meta_info<Type>::resolve();