EnTT 3.15.0
Loading...
Searching...
No Matches
utility.hpp
1#ifndef ENTT_META_UTILITY_HPP
2#define ENTT_META_UTILITY_HPP
3
4#include <cstddef>
5#include <functional>
6#include <type_traits>
7#include <utility>
8#include "../core/type_traits.hpp"
9#include "../locator/locator.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 std::conditional_t<std::is_base_of_v<Class, Type>, type_list<Args...>, type_list<const Class &, Args...>>,
52 !std::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 std::conditional_t<std::is_base_of_v<Class, Type>, type_list<Args...>, type_list<Class &, Args...>>,
67 !std::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 std::conditional_t<std::is_base_of_v<Class, Type>, type_list<>, type_list<Class &>>,
81 !std::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 std::conditional_t<
96 std::is_same_v<std::remove_cv_t<std::remove_reference_t<MaybeType>>, Type> || std::is_base_of_v<std::remove_cv_t<std::remove_reference_t<MaybeType>>, Type>,
97 type_list<Args...>,
98 type_list<MaybeType, Args...>>,
99 !(std::is_same_v<std::remove_cv_t<std::remove_reference_t<MaybeType>>, Type> || std::is_base_of_v<std::remove_cv_t<std::remove_reference_t<MaybeType>>, Type>),
100 std::is_const_v<std::remove_reference_t<MaybeType>> && (std::is_same_v<std::remove_cv_t<std::remove_reference_t<MaybeType>>, Type> || std::is_base_of_v<std::remove_cv_t<std::remove_reference_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 constexpr 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 constexpr meta_function_descriptor<Type, Ret (Class::*)(Args...)> get_rid_of_noexcept(Ret (Class::*)(Args...));
131
132 template<typename Ret, typename Class, typename = std::enable_if_t<std::is_member_object_pointer_v<Ret Class::*>>>
133 static constexpr meta_function_descriptor<Type, Ret Class::*> get_rid_of_noexcept(Ret Class::*);
134
135 template<typename Ret, typename... Args>
136 static constexpr meta_function_descriptor<Type, Ret (*)(Args...)> get_rid_of_noexcept(Ret (*)(Args...));
137
138 template<typename Class>
139 static constexpr meta_function_descriptor<Class, decltype(&Class::operator())> get_rid_of_noexcept(Class);
140
141public:
143 using type = decltype(get_rid_of_noexcept(std::declval<Candidate>()));
144};
145
151template<typename Type, typename Candidate>
153
167template<typename Policy = as_is_t, typename Type>
168[[nodiscard]] std::enable_if_t<is_meta_policy_v<Policy>, meta_any> meta_dispatch(const meta_ctx &ctx, [[maybe_unused]] Type &&value) {
169 if constexpr(std::is_same_v<Policy, as_void_t>) {
170 return meta_any{ctx, std::in_place_type<void>};
171 } else if constexpr(std::is_same_v<Policy, as_ref_t>) {
172 return meta_any{ctx, std::in_place_type<Type>, value};
173 } else if constexpr(std::is_same_v<Policy, as_cref_t>) {
174 static_assert(std::is_lvalue_reference_v<Type>, "Invalid type");
175 return meta_any{ctx, std::in_place_type<const std::remove_reference_t<Type> &>, std::as_const(value)};
176 } else {
177 return meta_any{ctx, std::forward<Type>(value)};
178 }
179}
180
188template<typename Policy = as_is_t, typename Type>
189[[nodiscard]] std::enable_if_t<is_meta_policy_v<Policy>, meta_any> meta_dispatch(Type &&value) {
190 return meta_dispatch<Policy, Type>(locator<meta_ctx>::value_or(), std::forward<Type>(value));
191}
192
194namespace internal {
195
196template<typename Policy, typename Candidate, typename... Args>
197[[nodiscard]] meta_any meta_invoke_with_args(const meta_ctx &ctx, Candidate &&candidate, Args &&...args) {
198 if constexpr(std::is_void_v<decltype(std::invoke(std::forward<Candidate>(candidate), args...))>) {
199 std::invoke(std::forward<Candidate>(candidate), args...);
200 return meta_any{ctx, std::in_place_type<void>};
201 } else {
202 return meta_dispatch<Policy>(ctx, std::invoke(std::forward<Candidate>(candidate), args...));
203 }
204}
205
206template<typename Type, typename Policy, typename Candidate, std::size_t... Index>
207[[nodiscard]] meta_any meta_invoke(meta_handle instance, Candidate &&candidate, [[maybe_unused]] meta_any *const args, std::index_sequence<Index...>) {
208 using descriptor = meta_function_helper_t<Type, std::remove_reference_t<Candidate>>;
209
210 // NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic) - waiting for C++20 (and std::span)
211 if constexpr(std::is_invocable_v<std::remove_reference_t<Candidate>, const Type &, type_list_element_t<Index, typename descriptor::args_type>...>) {
212 if(const auto *const clazz = instance->try_cast<const Type>(); clazz && ((args + Index)->allow_cast<type_list_element_t<Index, typename descriptor::args_type>>() && ...)) {
213 return meta_invoke_with_args<Policy>(instance->context(), std::forward<Candidate>(candidate), *clazz, (args + Index)->cast<type_list_element_t<Index, typename descriptor::args_type>>()...);
214 }
215 } else if constexpr(std::is_invocable_v<std::remove_reference_t<Candidate>, Type &, type_list_element_t<Index, typename descriptor::args_type>...>) {
216 if(auto *const clazz = instance->try_cast<Type>(); clazz && ((args + Index)->allow_cast<type_list_element_t<Index, typename descriptor::args_type>>() && ...)) {
217 return meta_invoke_with_args<Policy>(instance->context(), std::forward<Candidate>(candidate), *clazz, (args + Index)->cast<type_list_element_t<Index, typename descriptor::args_type>>()...);
218 }
219 } else {
220 if(((args + Index)->allow_cast<type_list_element_t<Index, typename descriptor::args_type>>() && ...)) {
221 return meta_invoke_with_args<Policy>(instance->context(), std::forward<Candidate>(candidate), (args + Index)->cast<type_list_element_t<Index, typename descriptor::args_type>>()...);
222 }
223 }
224 // NOLINTEND(cppcoreguidelines-pro-bounds-pointer-arithmetic)
225
226 return meta_any{meta_ctx_arg, instance->context()};
227}
228
229template<typename Type, typename... Args, std::size_t... Index>
230[[nodiscard]] meta_any meta_construct(const meta_ctx &ctx, meta_any *const args, std::index_sequence<Index...>) {
231 // NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic) - waiting for C++20 (and std::span)
232 if(((args + Index)->allow_cast<Args>() && ...)) {
233 return meta_any{ctx, std::in_place_type<Type>, (args + Index)->cast<Args>()...};
234 }
235 // NOLINTEND(cppcoreguidelines-pro-bounds-pointer-arithmetic)
236
237 return meta_any{meta_ctx_arg, ctx};
238}
239
240} // namespace internal
242
250template<typename Type>
251[[nodiscard]] static meta_type meta_arg(const meta_ctx &ctx, const std::size_t index) noexcept {
252 auto &&context = internal::meta_context::from(ctx);
253 return {ctx, internal::meta_arg_node(context, Type{}, index)};
254}
255
262template<typename Type>
263[[nodiscard]] static meta_type meta_arg(const std::size_t index) noexcept {
264 return meta_arg<Type>(locator<meta_ctx>::value_or(), index);
265}
266
275template<typename Type, auto Data>
276[[nodiscard]] bool meta_setter([[maybe_unused]] meta_handle instance, [[maybe_unused]] meta_any value) {
277 if constexpr(std::is_member_function_pointer_v<decltype(Data)> || std::is_function_v<std::remove_reference_t<std::remove_pointer_t<decltype(Data)>>>) {
278 using descriptor = meta_function_helper_t<Type, decltype(Data)>;
280
281 if(auto *const clazz = instance->try_cast<Type>(); clazz && value.allow_cast<data_type>()) {
282 std::invoke(Data, *clazz, value.cast<data_type>());
283 return true;
284 }
285 } else if constexpr(std::is_member_object_pointer_v<decltype(Data)>) {
286 using data_type = std::remove_reference_t<typename meta_function_helper_t<Type, decltype(Data)>::return_type>;
287
288 if constexpr(!std::is_array_v<data_type> && !std::is_const_v<data_type>) {
289 if(auto *const clazz = instance->try_cast<Type>(); clazz && value.allow_cast<data_type>()) {
290 std::invoke(Data, *clazz) = value.cast<data_type>();
291 return true;
292 }
293 }
294 } else if constexpr(std::is_pointer_v<decltype(Data)>) {
295 using data_type = std::remove_reference_t<decltype(*Data)>;
296
297 if constexpr(!std::is_array_v<data_type> && !std::is_const_v<data_type>) {
298 if(value.allow_cast<data_type>()) {
299 *Data = value.cast<data_type>();
300 return true;
301 }
302 }
303 }
304
305 return false;
306}
307
316template<typename Type, auto Data, typename Policy = as_is_t>
317[[nodiscard]] std::enable_if_t<is_meta_policy_v<Policy>, meta_any> meta_getter(meta_handle instance) {
318 if constexpr(std::is_member_pointer_v<decltype(Data)> || std::is_function_v<std::remove_reference_t<std::remove_pointer_t<decltype(Data)>>>) {
319 if constexpr(!std::is_array_v<std::remove_cv_t<std::remove_reference_t<std::invoke_result_t<decltype(Data), Type &>>>>) {
320 if constexpr(std::is_invocable_v<decltype(Data), Type &>) {
321 if(auto *clazz = instance->try_cast<Type>(); clazz) {
322 return meta_dispatch<Policy>(instance->context(), std::invoke(Data, *clazz));
323 }
324 }
325
326 if constexpr(std::is_invocable_v<decltype(Data), const Type &>) {
327 if(auto *fallback = instance->try_cast<const Type>(); fallback) {
328 return meta_dispatch<Policy>(instance->context(), std::invoke(Data, *fallback));
329 }
330 }
331 }
332
333 return meta_any{meta_ctx_arg, instance->context()};
334 } else if constexpr(std::is_pointer_v<decltype(Data)>) {
335 if constexpr(std::is_array_v<std::remove_pointer_t<decltype(Data)>>) {
336 return meta_any{meta_ctx_arg, instance->context()};
337 } else {
338 return meta_dispatch<Policy>(instance->context(), *Data);
339 }
340 } else {
341 return meta_dispatch<Policy>(instance->context(), Data);
342 }
343}
344
354template<typename Type, auto Data, typename Policy = as_is_t>
355[[deprecated("a context is no longer required, it is inferred from the meta_handle")]] [[nodiscard]] std::enable_if_t<is_meta_policy_v<Policy>, meta_any> meta_getter(const meta_ctx &ctx, meta_handle instance) {
356 return meta_getter<Type, Data, Policy>(meta_handle{ctx, std::move(instance)});
357}
358
369template<typename Type, typename Policy = as_is_t, typename Candidate>
370[[nodiscard]] std::enable_if_t<is_meta_policy_v<Policy>, meta_any> meta_invoke(meta_handle instance, Candidate &&candidate, meta_any *const args) {
371 return internal::meta_invoke<Type, Policy>(std::move(instance), std::forward<Candidate>(candidate), args, std::make_index_sequence<meta_function_helper_t<Type, std::remove_reference_t<Candidate>>::args_type::size>{});
372}
373
385template<typename Type, typename Policy = as_is_t, typename Candidate>
386[[deprecated("a context is no longer required, it is inferred from the meta_handle")]] [[nodiscard]] 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) {
387 return meta_invoke<Type, Policy>(meta_handle{ctx, std::move(instance)}, std::forward<Candidate>(candidate), args);
388}
389
399template<typename Type, auto Candidate, typename Policy = as_is_t>
400[[nodiscard]] std::enable_if_t<is_meta_policy_v<Policy>, meta_any> meta_invoke(meta_handle instance, meta_any *const args) {
401 return internal::meta_invoke<Type, Policy>(std::move(instance), Candidate, args, std::make_index_sequence<meta_function_helper_t<Type, std::remove_reference_t<decltype(Candidate)>>::args_type::size>{});
402}
403
414template<typename Type, auto Candidate, typename Policy = as_is_t>
415[[deprecated("a context is no longer required, it is inferred from the meta_handle")]] [[nodiscard]] std::enable_if_t<is_meta_policy_v<Policy>, meta_any> meta_invoke(const meta_ctx &ctx, meta_handle instance, meta_any *const args) {
416 return meta_invoke<Type, Candidate, Policy>(meta_handle{ctx, std::move(instance)}, args);
417}
418
432template<typename Type, typename... Args>
433[[nodiscard]] meta_any meta_construct(const meta_ctx &ctx, meta_any *const args) {
434 return internal::meta_construct<Type, Args...>(ctx, args, std::index_sequence_for<Args...>{});
435}
436
444template<typename Type, typename... Args>
445[[nodiscard]] meta_any meta_construct(meta_any *const args) {
446 return meta_construct<Type, Args...>(locator<meta_ctx>::value_or(), args);
447}
448
464template<typename Type, typename Policy = as_is_t, typename Candidate>
465[[nodiscard]] meta_any meta_construct(const meta_ctx &ctx, Candidate &&candidate, meta_any *const args) {
466 if constexpr(meta_function_helper_t<Type, Candidate>::is_static || std::is_class_v<std::remove_cv_t<std::remove_reference_t<Candidate>>>) {
467 return internal::meta_invoke<Type, Policy>(meta_handle{meta_ctx_arg, ctx}, std::forward<Candidate>(candidate), args, std::make_index_sequence<meta_function_helper_t<Type, std::remove_reference_t<Candidate>>::args_type::size>{});
468 } else {
469 meta_any handle{ctx, args->as_ref()};
470 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) - waiting for C++20 (and std::span)
471 return internal::meta_invoke<Type, Policy>(handle, std::forward<Candidate>(candidate), args + 1u, std::make_index_sequence<meta_function_helper_t<Type, std::remove_reference_t<Candidate>>::args_type::size>{});
472 }
473}
474
484template<typename Type, typename Policy = as_is_t, typename Candidate>
485[[nodiscard]] std::enable_if_t<is_meta_policy_v<Policy>, meta_any> meta_construct(Candidate &&candidate, meta_any *const args) {
486 return meta_construct<Type, Policy>(locator<meta_ctx>::value_or(), std::forward<Candidate>(candidate), args);
487}
488
503template<typename Type, auto Candidate, typename Policy = as_is_t>
504[[nodiscard]] std::enable_if_t<is_meta_policy_v<Policy>, meta_any> meta_construct(const meta_ctx &ctx, meta_any *const args) {
505 return meta_construct<Type, Policy>(ctx, Candidate, args);
506}
507
516template<typename Type, auto Candidate, typename Policy = as_is_t>
517[[nodiscard]] std::enable_if_t<is_meta_policy_v<Policy>, meta_any> meta_construct(meta_any *const args) {
519}
520
521} // namespace entt
522
523#endif
static Service & value_or(Args &&...args)
Returns a service if available or sets it from a fallback type.
Definition locator.hpp:88
Opaque wrapper for values of any type.
Definition meta.hpp:166
meta_any as_ref() noexcept
Aliasing constructor.
Definition meta.hpp:624
const Type * try_cast() const
Tries to cast an instance to a given type.
Definition meta.hpp:443
const meta_ctx & context() const noexcept
Returns the underlying meta context.
Definition meta.hpp:653
Opaque meta context type.
Definition context.hpp:34
Meta function helper.
Definition utility.hpp:125
decltype(get_rid_of_noexcept(std::declval< Candidate >())) type
The meta function descriptor of the given function.
Definition utility.hpp:143
Opaque wrapper for types.
Definition meta.hpp:1088
EnTT default namespace.
Definition dense_map.hpp:22
typename meta_function_helper< Type, Candidate >::type meta_function_helper_t
Helper type.
Definition utility.hpp:152
basic_handle< registry > handle
Alias declaration for the most common use case.
Definition fwd.hpp:101
std::enable_if_t< is_meta_policy_v< Policy >, meta_any > meta_getter(meta_handle instance)
Gets the value of a given variable.
Definition utility.hpp:317
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:433
std::enable_if_t< is_meta_policy_v< Policy >, 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:370
std::enable_if_t< is_meta_policy_v< Policy >, meta_any > meta_dispatch(const meta_ctx &ctx, Type &&value)
Wraps a value depending on the given policy.
Definition utility.hpp:168
typename type_list_element< Index, List >::type type_list_element_t
Helper type.
constexpr meta_ctx_arg_t meta_ctx_arg
Constant of type meta_context_arg_t used to disambiguate calls.
Definition context.hpp:31
bool meta_setter(meta_handle instance, meta_any value)
Sets the value of a given variable.
Definition utility.hpp:276
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
Opaque pointers to instances of any type.
Definition meta.hpp:688
A class to use to push around lists of types, nothing more.