EnTT 4.0.0
Loading...
Searching...
No Matches
utility.hpp
1#ifndef ENTT_META_UTILITY_HPP
2#define ENTT_META_UTILITY_HPP
3
4#include "../core/type_traits.hpp"
5#include "../locator/locator.hpp"
6#include "../stl/cstddef.hpp"
7#include "../stl/functional.hpp"
8#include "../stl/type_traits.hpp"
9#include "../stl/utility.hpp"
10#include "meta.hpp"
11#include "node.hpp"
12#include "policy.hpp"
13
14namespace entt {
15
23template<typename Ret, typename Args, bool Static, bool Const>
26 using return_type = Ret;
28 using args_type = Args;
29
31 static constexpr bool is_static = Static;
33 static constexpr bool is_const = Const;
34};
35
37template<typename, typename>
39
47template<typename Type, typename Ret, typename Class, typename... Args>
48struct meta_function_descriptor<Type, Ret (Class::*)(Args...) const>
50 Ret,
51 stl::conditional_t<stl::is_base_of_v<Class, Type>, type_list<Args...>, type_list<const Class &, Args...>>,
52 !stl::is_base_of_v<Class, Type>,
53 true> {};
54
62template<typename Type, typename Ret, typename Class, typename... Args>
63struct meta_function_descriptor<Type, Ret (Class::*)(Args...)>
65 Ret,
66 stl::conditional_t<stl::is_base_of_v<Class, Type>, type_list<Args...>, type_list<Class &, Args...>>,
67 !stl::is_base_of_v<Class, Type>,
68 false> {};
69
76template<typename Type, typename Ret, typename Class>
77struct meta_function_descriptor<Type, Ret Class::*>
79 Ret &,
80 stl::conditional_t<stl::is_base_of_v<Class, Type>, type_list<>, type_list<Class &>>,
81 !stl::is_base_of_v<Class, Type>,
82 false> {};
83
91template<typename Type, typename Ret, typename MaybeType, typename... Args>
92struct meta_function_descriptor<Type, Ret (*)(MaybeType, Args...)>
94 Ret,
95 stl::conditional_t<
96 stl::is_same_v<stl::remove_cvref_t<MaybeType>, Type> || stl::is_base_of_v<stl::remove_cvref_t<MaybeType>, Type>,
97 type_list<Args...>,
98 type_list<MaybeType, Args...>>,
99 !(stl::is_same_v<stl::remove_cvref_t<MaybeType>, Type> || stl::is_base_of_v<stl::remove_cvref_t<MaybeType>, Type>),
100 stl::is_const_v<stl::remove_reference_t<MaybeType>> && (stl::is_same_v<stl::remove_cvref_t<MaybeType>, Type> || stl::is_base_of_v<stl::remove_cvref_t<MaybeType>, Type>)> {};
101
107template<typename Type, typename Ret>
108struct meta_function_descriptor<Type, Ret (*)()>
110 Ret,
112 true,
113 false> {};
114
124template<typename Type, typename Candidate>
126 template<typename Ret, typename... Args, typename Class>
127 static meta_function_descriptor<Type, Ret (Class::*)(Args...) const> get_rid_of_noexcept(Ret (Class::*)(Args...) const);
128
129 template<typename Ret, typename... Args, typename Class>
130 static meta_function_descriptor<Type, Ret (Class::*)(Args...)> get_rid_of_noexcept(Ret (Class::*)(Args...));
131
132 template<typename Ret, typename Class>
133 requires stl::is_member_object_pointer_v<Ret Class::*>
134 static meta_function_descriptor<Type, Ret Class::*> get_rid_of_noexcept(Ret Class::*);
135
136 template<typename Ret, typename... Args>
137 static meta_function_descriptor<Type, Ret (*)(Args...)> get_rid_of_noexcept(Ret (*)(Args...));
138
139 template<typename Class>
140 static meta_function_descriptor<Class, decltype(&Class::operator())> get_rid_of_noexcept(Class);
141
142public:
144 using type = decltype(get_rid_of_noexcept(stl::declval<Candidate>()));
145};
146
152template<typename Type, typename Candidate>
154
168template<meta_policy Policy = as_value_t, typename Type>
169[[nodiscard]] meta_any meta_dispatch(const meta_ctx &ctx, [[maybe_unused]] Type &&value) {
170 if constexpr(stl::is_same_v<Policy, as_cref_t>) {
171 static_assert(stl::is_lvalue_reference_v<Type>, "Invalid type");
172 return meta_any{ctx, stl::in_place_type<const stl::remove_reference_t<Type> &>, stl::as_const(value)};
173 } else if constexpr(stl::is_same_v<Policy, as_ref_t> || (stl::is_same_v<Policy, as_is_t> && stl::is_lvalue_reference_v<Type>)) {
174 return meta_any{ctx, stl::in_place_type<Type>, value};
175 } else if constexpr(stl::is_same_v<Policy, as_void_t>) {
176 return meta_any{ctx, stl::in_place_type<void>};
177 } else {
178 return meta_any{ctx, stl::forward<Type>(value)};
179 }
180}
181
189template<meta_policy Policy = as_value_t, typename Type>
190[[nodiscard]] meta_any meta_dispatch(Type &&value) {
191 return meta_dispatch<Policy, Type>(locator<meta_ctx>::value_or(), stl::forward<Type>(value));
192}
193
195namespace internal {
196
197template<typename Policy, typename Candidate, typename... Args>
198[[nodiscard]] meta_any meta_invoke_with_args(const meta_ctx &ctx, Candidate &&candidate, Args &&...args) {
199 if constexpr(stl::is_void_v<decltype(stl::invoke(stl::forward<Candidate>(candidate), args...))>) {
200 stl::invoke(stl::forward<Candidate>(candidate), args...);
201 return meta_any{ctx, stl::in_place_type<void>};
202 } else {
203 return meta_dispatch<Policy>(ctx, stl::invoke(stl::forward<Candidate>(candidate), args...));
204 }
205}
206
207template<typename Type, typename Policy, typename Candidate, stl::size_t... Index>
208[[nodiscard]] meta_any meta_invoke(meta_any &instance, Candidate &&candidate, [[maybe_unused]] meta_any *const args, stl::index_sequence<Index...>) {
209 using descriptor = meta_function_helper_t<Type, stl::remove_reference_t<Candidate>>;
210
211 // NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic) - waiting for C++20 (and stl::span)
212 if constexpr(stl::is_invocable_v<stl::remove_reference_t<Candidate>, const Type &, type_list_element_t<Index, typename descriptor::args_type>...>) {
213 if(const auto *const clazz = instance.try_cast<const Type>(); clazz && ((args + Index)->allow_cast<type_list_element_t<Index, typename descriptor::args_type>>() && ...)) {
214 return meta_invoke_with_args<Policy>(instance.context(), stl::forward<Candidate>(candidate), *clazz, (args + Index)->cast<type_list_element_t<Index, typename descriptor::args_type>>()...);
215 }
216 } else if constexpr(stl::is_invocable_v<stl::remove_reference_t<Candidate>, Type &, type_list_element_t<Index, typename descriptor::args_type>...>) {
217 if(auto *const clazz = instance.try_cast<Type>(); clazz && ((args + Index)->allow_cast<type_list_element_t<Index, typename descriptor::args_type>>() && ...)) {
218 return meta_invoke_with_args<Policy>(instance.context(), stl::forward<Candidate>(candidate), *clazz, (args + Index)->cast<type_list_element_t<Index, typename descriptor::args_type>>()...);
219 }
220 } else {
221 if(((args + Index)->allow_cast<type_list_element_t<Index, typename descriptor::args_type>>() && ...)) {
222 return meta_invoke_with_args<Policy>(instance.context(), stl::forward<Candidate>(candidate), (args + Index)->cast<type_list_element_t<Index, typename descriptor::args_type>>()...);
223 }
224 }
225 // NOLINTEND(cppcoreguidelines-pro-bounds-pointer-arithmetic)
226
227 return meta_any{meta_ctx_arg, instance.context()};
228}
229
230template<typename Type, typename... Args, stl::size_t... Index>
231[[nodiscard]] meta_any meta_construct(const meta_ctx &ctx, meta_any *const args, stl::index_sequence<Index...>) {
232 // NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic) - waiting for C++20 (and stl::span)
233 if(((args + Index)->allow_cast<Args>() && ...)) {
234 return meta_any{ctx, stl::in_place_type<Type>, (args + Index)->cast<Args>()...};
235 }
236 // NOLINTEND(cppcoreguidelines-pro-bounds-pointer-arithmetic)
237
238 return meta_any{meta_ctx_arg, ctx};
239}
240
241} // namespace internal
243
251template<typename Type>
252[[nodiscard]] meta_type meta_arg(const meta_ctx &ctx, const stl::size_t index) noexcept {
253 const auto &context = internal::meta_context::from(ctx);
254 return {ctx, internal::meta_arg_node(context, Type{}, index)};
255}
256
263template<typename Type>
264[[nodiscard]] meta_type meta_arg(const stl::size_t index) noexcept {
266}
267
276template<typename Type, auto Data>
277[[nodiscard]] bool meta_setter([[maybe_unused]] meta_handle instance, [[maybe_unused]] meta_any *const args) {
278 if constexpr(stl::is_member_function_pointer_v<decltype(Data)> || stl::is_function_v<stl::remove_reference_t<stl::remove_pointer_t<decltype(Data)>>>) {
279 return static_cast<bool>(internal::meta_invoke<Type, as_void_t>(*instance.operator->(), Data, args, stl::make_index_sequence<meta_function_helper_t<Type, decltype(Data)>::args_type::size>{}));
280 } else if constexpr(stl::is_member_object_pointer_v<decltype(Data)>) {
281 using data_type = stl::remove_reference_t<typename meta_function_helper_t<Type, decltype(Data)>::return_type>;
282
283 if constexpr(!stl::is_array_v<data_type> && !stl::is_const_v<data_type>) {
284 if(auto *const clazz = instance->try_cast<Type>(); clazz && args->allow_cast<data_type>()) {
285 stl::invoke(Data, *clazz) = args->cast<data_type>();
286 return true;
287 }
288 }
289
290 return false;
291 } else if constexpr(stl::is_pointer_v<decltype(Data)>) {
292 using data_type = stl::remove_reference_t<decltype(*Data)>;
293
294 if constexpr(!stl::is_array_v<data_type> && !stl::is_const_v<data_type>) {
295 if(args->allow_cast<data_type>()) {
296 *Data = args->cast<data_type>();
297 return true;
298 }
299 }
300
301 return false;
302 } else {
303 return false;
304 }
305}
306
315template<typename Type, auto Data>
316[[nodiscard]] bool meta_setter(meta_handle instance, meta_any value) {
317 return meta_setter<Type, Data>(*instance.operator->(), &value);
318}
319
329template<typename Type, auto Data, meta_policy Policy = as_value_t>
330[[nodiscard]] meta_any meta_getter(meta_handle instance, [[maybe_unused]] meta_any *const args) {
331 if constexpr(stl::is_member_function_pointer_v<decltype(Data)> || stl::is_function_v<stl::remove_reference_t<stl::remove_pointer_t<decltype(Data)>>>) {
332 return internal::meta_invoke<Type, Policy>(*instance.operator->(), Data, args, stl::make_index_sequence<meta_function_helper_t<Type, decltype(Data)>::args_type::size>{});
333 } else if constexpr(stl::is_member_object_pointer_v<decltype(Data)>) {
334 if constexpr(!stl::is_array_v<stl::remove_cvref_t<stl::invoke_result_t<decltype(Data), Type &>>>) {
335 if(auto *clazz = instance->try_cast<Type>(); clazz) {
336 return meta_dispatch<Policy>(instance->context(), stl::invoke(Data, *clazz));
337 } else if(auto *fallback = instance->try_cast<const Type>(); fallback) {
338 return meta_dispatch<Policy>(instance->context(), stl::invoke(Data, *fallback));
339 }
340 }
341
342 return meta_any{meta_ctx_arg, instance->context()};
343 } else if constexpr(stl::is_pointer_v<decltype(Data)>) {
344 if constexpr(stl::is_array_v<stl::remove_pointer_t<decltype(Data)>>) {
345 return meta_any{meta_ctx_arg, instance->context()};
346 } else {
347 return meta_dispatch<Policy>(instance->context(), *Data);
348 }
349 } else {
350 return meta_dispatch<Policy>(instance->context(), Data);
351 }
352}
353
362template<typename Type, auto Data, meta_policy Policy = as_value_t>
363[[nodiscard]] meta_any meta_getter(meta_handle instance) {
364 return meta_getter<Type, Data, Policy>(*instance.operator->(), nullptr);
365}
366
377template<typename Type, meta_policy Policy = as_value_t, typename Candidate>
378[[nodiscard]] meta_any meta_invoke(meta_handle instance, Candidate &&candidate, meta_any *const args) {
379 return internal::meta_invoke<Type, Policy>(*instance.operator->(), stl::forward<Candidate>(candidate), args, stl::make_index_sequence<meta_function_helper_t<Type, stl::remove_reference_t<Candidate>>::args_type::size>{});
380}
381
391template<typename Type, auto Candidate, meta_policy Policy = as_value_t>
392[[nodiscard]] meta_any meta_invoke(meta_handle instance, meta_any *const args) {
393 return internal::meta_invoke<Type, Policy>(*instance.operator->(), Candidate, args, stl::make_index_sequence<meta_function_helper_t<Type, stl::remove_reference_t<decltype(Candidate)>>::args_type::size>{});
394}
395
409template<typename Type, typename... Args>
410[[nodiscard]] meta_any meta_construct(const meta_ctx &ctx, meta_any *const args) {
411 return internal::meta_construct<Type, Args...>(ctx, args, stl::index_sequence_for<Args...>{});
412}
413
421template<typename Type, typename... Args>
422[[nodiscard]] meta_any meta_construct(meta_any *const args) {
423 return meta_construct<Type, Args...>(locator<meta_ctx>::value_or(), args);
424}
425
441template<typename Type, typename Policy = as_value_t, typename Candidate>
442[[nodiscard]] meta_any meta_construct(const meta_ctx &ctx, Candidate &&candidate, meta_any *const args) {
443 if constexpr(meta_function_helper_t<Type, Candidate>::is_static || stl::is_class_v<stl::remove_cvref_t<Candidate>>) {
444 meta_any placeholder{meta_ctx_arg, ctx};
445 return internal::meta_invoke<Type, Policy>(placeholder, stl::forward<Candidate>(candidate), args, stl::make_index_sequence<meta_function_helper_t<Type, stl::remove_reference_t<Candidate>>::args_type::size>{});
446 } else {
447 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) - waiting for C++20 (and stl::span)
448 return internal::meta_invoke<Type, Policy>(*args, stl::forward<Candidate>(candidate), args + 1u, stl::make_index_sequence<meta_function_helper_t<Type, stl::remove_reference_t<Candidate>>::args_type::size>{});
449 }
450}
451
461template<typename Type, meta_policy Policy = as_value_t, typename Candidate>
462[[nodiscard]] meta_any meta_construct(Candidate &&candidate, meta_any *const args) {
463 return meta_construct<Type, Policy>(locator<meta_ctx>::value_or(), stl::forward<Candidate>(candidate), args);
464}
465
480template<typename Type, auto Candidate, meta_policy Policy = as_value_t>
481[[nodiscard]] meta_any meta_construct(const meta_ctx &ctx, meta_any *const args) {
482 return meta_construct<Type, Policy>(ctx, Candidate, args);
483}
484
493template<typename Type, auto Candidate, meta_policy Policy = as_value_t>
497
498} // namespace entt
499
500#endif
static Service & value_or(Args &&...args)
Returns a service if available or sets it from a fallback type.
Definition locator.hpp:90
Opaque wrapper for values of any type.
Definition meta.hpp:176
const Type * try_cast() const
Tries to cast an instance to a given type.
Definition meta.hpp:434
const meta_ctx & context() const noexcept
Returns the underlying meta context.
Definition meta.hpp:645
Meta function helper.
Definition utility.hpp:125
decltype(get_rid_of_noexcept(stl::declval< Candidate >())) type
The meta function descriptor of the given function.
Definition utility.hpp:144
Opaque pointers to instances of any type.
Definition meta.hpp:676
Opaque wrapper for types.
Definition meta.hpp:1026
EnTT default namespace.
Definition dense_map.hpp:25
meta_function_helper< Type, Candidate >::type meta_function_helper_t
Helper type.
Definition utility.hpp:153
meta_any meta_construct(const meta_ctx &ctx, meta_any *const args)
Tries to construct an instance given a list of erased parameters.
Definition utility.hpp:410
meta_any meta_invoke(meta_handle instance, Candidate &&candidate, meta_any *const args)
Tries to invoke an object given a list of erased parameters.
Definition utility.hpp:378
meta_any meta_dispatch(const meta_ctx &ctx, Type &&value)
Wraps a value depending on the given policy.
Definition utility.hpp:169
constexpr meta_ctx_arg_t meta_ctx_arg
Constant of type meta_context_arg_t used to disambiguate calls.
Definition fwd.hpp:39
meta_type meta_arg(const meta_ctx &ctx, const stl::size_t index) noexcept
Returns the meta type of the i-th element of a list of arguments.
Definition utility.hpp:252
meta_any meta_getter(meta_handle instance, meta_any *const args)
Gets the value of a given variable.
Definition utility.hpp:330
bool meta_setter(meta_handle instance, meta_any *const args)
Sets the value of a given variable.
Definition utility.hpp:277
Opaque meta context type.
Definition context.hpp:30
Meta function descriptor traits.
Definition utility.hpp:24
static constexpr bool is_static
True if the meta function is static, false otherwise.
Definition utility.hpp:31
Args args_type
Meta function arguments.
Definition utility.hpp:28
static constexpr bool is_const
True if the meta function is const, false otherwise.
Definition utility.hpp:33
Ret return_type
Meta function return type.
Definition utility.hpp:26
Primary template isn't defined on purpose.
Definition utility.hpp:38
A class to use to push around lists of types, nothing more.