ソースを参照

meta: make meta utility public and freely available to users

Michele Caini 5 年 前
コミット
c3dc32415b
4 ファイル変更330 行追加218 行削除
  1. 1 0
      src/entt/entt.hpp
  2. 21 210
      src/entt/meta/factory.hpp
  3. 12 8
      src/entt/meta/meta.hpp
  4. 296 0
      src/entt/meta/utility.hpp

+ 1 - 0
src/entt/entt.hpp

@@ -35,6 +35,7 @@
 #include "meta/range.hpp"
 #include "meta/range.hpp"
 #include "meta/resolve.hpp"
 #include "meta/resolve.hpp"
 #include "meta/type_traits.hpp"
 #include "meta/type_traits.hpp"
+#include "meta/utility.hpp"
 #include "platform/android-ndk-r17.hpp"
 #include "platform/android-ndk-r17.hpp"
 #include "poly/poly.hpp"
 #include "poly/poly.hpp"
 #include "process/process.hpp"
 #include "process/process.hpp"

+ 21 - 210
src/entt/meta/factory.hpp

@@ -2,9 +2,7 @@
 #define ENTT_META_FACTORY_HPP
 #define ENTT_META_FACTORY_HPP
 
 
 
 
-#include <array>
 #include <cstddef>
 #include <cstddef>
-#include <functional>
 #include <tuple>
 #include <tuple>
 #include <type_traits>
 #include <type_traits>
 #include <utility>
 #include <utility>
@@ -14,199 +12,12 @@
 #include "../core/type_traits.hpp"
 #include "../core/type_traits.hpp"
 #include "meta.hpp"
 #include "meta.hpp"
 #include "policy.hpp"
 #include "policy.hpp"
+#include "utility.hpp"
 
 
 
 
 namespace entt {
 namespace entt {
 
 
 
 
-/**
- * @cond TURN_OFF_DOXYGEN
- * Internal details not to be documented.
- */
-
-
-namespace internal {
-
-
-template<typename, bool, bool>
-struct meta_function_helper;
-
-
-template<typename Ret, typename... Args, bool Const, bool Static>
-struct meta_function_helper<Ret(Args...), Const, Static> {
-    using return_type = Ret;
-    using args_type = type_list<Args...>;
-
-    static constexpr auto is_static = Static;
-    static constexpr auto is_const = Const;
-};
-
-
-template<typename Type, typename Ret, typename... Args, typename Class>
-constexpr meta_function_helper<std::conditional_t<std::is_same_v<Type, Class>, Ret(Args...), Ret(Class &, Args...)>, true, !std::is_same_v<Type, Class>>
-to_meta_function_helper(Ret(Class:: *)(Args...) const);
-
-
-template<typename Type, typename Ret, typename... Args, typename Class>
-constexpr meta_function_helper<std::conditional_t<std::is_same_v<Type, Class>, Ret(Args...), Ret(Class &, Args...)>, false, !std::is_same_v<Type, Class>>
-to_meta_function_helper(Ret(Class:: *)(Args...));
-
-
-template<typename Type, typename Ret, typename... Args>
-constexpr meta_function_helper<Ret(Args...), false, true>
-to_meta_function_helper(Ret(*)(Args...));
-
-
-template<typename Type>
-constexpr void to_meta_function_helper(...);
-
-
-template<typename Type, typename Candidate>
-using meta_function_helper_t = decltype(to_meta_function_helper<Type>(std::declval<Candidate>()));
-
-
-template<typename... Args>
-[[nodiscard]] static auto arg(type_list<Args...>, const std::size_t index) ENTT_NOEXCEPT {
-    return std::array<meta_type_node *, sizeof...(Args)>{{meta_info<Args>::resolve()...}}[index];
-}
-
-
-template<typename Type, typename... Args, std::size_t... Index>
-[[nodiscard]] meta_any construct(meta_any * const args, std::index_sequence<Index...>) {
-    if(((args+Index)->allow_cast<Args>() && ...)) {
-        return Type{(args+Index)->cast<Args>()...};
-    }
-
-    return {};
-}
-
-
-template<typename Type, auto Data>
-[[nodiscard]] bool setter([[maybe_unused]] meta_handle instance, [[maybe_unused]] meta_any value) {
-    if constexpr(!std::is_same_v<decltype(Data), Type> && !std::is_same_v<decltype(Data), std::nullptr_t>) {
-        if constexpr(std::is_function_v<std::remove_reference_t<std::remove_pointer_t<decltype(Data)>>> || std::is_member_function_pointer_v<decltype(Data)>) {
-            using helper_type = meta_function_helper_t<Type, decltype(Data)>;
-            using data_type = type_list_element_t<!std::is_member_function_pointer_v<decltype(Data)>, typename helper_type::args_type>;
-    
-            if(auto * const clazz = instance->try_cast<Type>(); clazz) {
-                if(value.allow_cast<data_type>()) {
-                    std::invoke(Data, *clazz, value.cast<data_type>());
-                    return true;
-                }
-            }
-        } else if constexpr(std::is_member_object_pointer_v<decltype(Data)>) {
-            using data_type = std::remove_reference_t<decltype(std::declval<Type>().*Data)>;
-    
-            if constexpr(!std::is_array_v<data_type> && !std::is_const_v<data_type>) {
-                if(auto * const clazz = instance->try_cast<Type>(); clazz) {
-                    if(value.allow_cast<data_type>()) {
-                        std::invoke(Data, clazz) = value.cast<data_type>();
-                        return true;
-                    }
-                }
-            }
-        } else {
-            using data_type = std::remove_reference_t<decltype(*Data)>;
-    
-            if constexpr(!std::is_array_v<data_type> && !std::is_const_v<data_type>) {
-                if(value.allow_cast<data_type>()) {
-                    *Data = value.cast<data_type>();
-                    return true;
-                }
-            }
-        }
-    }
-
-    return false;
-}
-
-
-template<typename Type, auto Data, typename Policy>
-[[nodiscard]] meta_any getter([[maybe_unused]] meta_handle instance) {
-    [[maybe_unused]] auto dispatch = [](auto &&value) {
-        if constexpr(std::is_same_v<Policy, as_void_t>) {
-            return meta_any{std::in_place_type<void>, std::forward<decltype(value)>(value)};
-        } else if constexpr(std::is_same_v<Policy, as_ref_t>) {
-            return meta_any{std::reference_wrapper{std::forward<decltype(value)>(value)}};
-        } else if constexpr(std::is_same_v<Policy, as_cref_t>) {
-            return meta_any{std::cref(std::forward<decltype(value)>(value))};
-        } else {
-            static_assert(std::is_same_v<Policy, as_is_t>, "Policy not supported");
-            return meta_any{std::forward<decltype(value)>(value)};
-        }
-    };
-
-    if constexpr(std::is_function_v<std::remove_reference_t<std::remove_pointer_t<decltype(Data)>>> || std::is_member_function_pointer_v<decltype(Data)>) {
-        auto * const clazz = instance->try_cast<std::conditional_t<std::is_invocable_v<decltype(Data), const Type &>, const Type, Type>>();
-        return clazz ? dispatch(std::invoke(Data, *clazz)) : meta_any{};
-    } else if constexpr(std::is_member_object_pointer_v<decltype(Data)>) {
-        if constexpr(std::is_array_v<std::remove_cv_t<std::remove_reference_t<decltype(std::declval<Type>().*Data)>>>) {
-            return meta_any{};
-        } else {
-            if(auto * clazz = instance->try_cast<Type>(); clazz) {
-                return dispatch(std::invoke(Data, *clazz));
-            } else {
-                auto * fallback = instance->try_cast<const Type>();
-                return fallback ? dispatch(std::invoke(Data, *fallback)) : meta_any{};
-            }
-        }
-    } else if constexpr(std::is_pointer_v<decltype(Data)>) {
-        if constexpr(std::is_array_v<std::remove_pointer_t<decltype(Data)>>) {
-            return meta_any{};
-        } else {
-            return dispatch(*Data);
-        }
-    } else {
-        return dispatch(Data);
-    }
-}
-
-
-template<typename Type, auto Candidate, typename Policy, std::size_t... Index>
-[[nodiscard]] meta_any invoke([[maybe_unused]] meta_handle instance, meta_any *args, std::index_sequence<Index...>) {
-    using helper_type = meta_function_helper_t<Type, decltype(Candidate)>;
-
-    auto dispatch = [](auto &&... params) {
-        if constexpr(std::is_void_v<std::remove_cv_t<typename helper_type::return_type>> || std::is_same_v<Policy, as_void_t>) {
-            std::invoke(Candidate, std::forward<decltype(params)>(params)...);
-            return meta_any{std::in_place_type<void>};
-        } else if constexpr(std::is_same_v<Policy, as_ref_t>) {
-            return meta_any{std::reference_wrapper{std::invoke(Candidate, std::forward<decltype(params)>(params)...)}};
-        } else if constexpr(std::is_same_v<Policy, as_cref_t>) {
-            return meta_any{std::cref(std::invoke(Candidate, std::forward<decltype(params)>(params)...))};
-        } else {
-            static_assert(std::is_same_v<Policy, as_is_t>, "Policy not supported");
-            return meta_any{std::invoke(Candidate, std::forward<decltype(params)>(params)...)};
-        }
-    };
-
-    if constexpr(std::is_invocable_v<decltype(Candidate), const Type &, type_list_element_t<Index, typename helper_type::args_type>...>) {
-        if(const auto * const clazz = instance->try_cast<const Type>(); clazz && ((args+Index)->allow_cast<type_list_element_t<Index, typename helper_type::args_type>>() && ...)) {
-            return dispatch(*clazz, (args+Index)->cast<type_list_element_t<Index, typename helper_type::args_type>>()...);
-        }
-    } else if constexpr(std::is_invocable_v<decltype(Candidate), Type &, type_list_element_t<Index, typename helper_type::args_type>...>) {
-        if(auto * const clazz = instance->try_cast<Type>(); clazz && ((args+Index)->allow_cast<type_list_element_t<Index, typename helper_type::args_type>>() && ...)) {
-            return dispatch(*clazz, (args+Index)->cast<type_list_element_t<Index, typename helper_type::args_type>>()...);
-        }
-    } else {
-        if(((args+Index)->allow_cast<type_list_element_t<Index, typename helper_type::args_type>>() && ...)) {
-            return dispatch((args+Index)->cast<type_list_element_t<Index, typename helper_type::args_type>>()...);
-        }
-    }
-
-    return meta_any{};
-}
-
-
-}
-
-
-/**
- * Internal details not to be documented.
- * @endcond
- */
-
-
 /**
 /**
  * @brief Meta factory to be used for reflection purposes.
  * @brief Meta factory to be used for reflection purposes.
  *
  *
@@ -477,20 +288,20 @@ public:
      */
      */
     template<auto Candidate, typename Policy = as_is_t>
     template<auto Candidate, typename Policy = as_is_t>
     auto ctor() ENTT_NOEXCEPT {
     auto ctor() ENTT_NOEXCEPT {
-        using helper_type = internal::meta_function_helper_t<Type, decltype(Candidate)>;
-        static_assert(std::is_same_v<std::remove_cv_t<std::remove_reference_t<typename helper_type::return_type>>, Type>, "The function doesn't return an object of the required type");
+        using descriptor = meta_function_helper_t<Type, decltype(Candidate)>;
+        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");
         auto * const type = internal::meta_info<Type>::resolve();
         auto * const type = internal::meta_info<Type>::resolve();
 
 
         static internal::meta_ctor_node node{
         static internal::meta_ctor_node node{
             type,
             type,
             nullptr,
             nullptr,
             nullptr,
             nullptr,
-            helper_type::args_type::size,
+            descriptor::args_type::size,
             [](const typename internal::meta_ctor_node::size_type index) ENTT_NOEXCEPT {
             [](const typename internal::meta_ctor_node::size_type index) ENTT_NOEXCEPT {
-                return internal::arg(typename helper_type::args_type{}, index);
+                return meta_arg(typename descriptor::args_type{}, index);
             },
             },
             [](meta_any * const any) {
             [](meta_any * const any) {
-                return internal::invoke<Type, Candidate, Policy>({}, any, std::make_index_sequence<helper_type::args_type::size>{});
+                return meta_invoke<Type, Candidate, Policy>({}, any, std::make_index_sequence<descriptor::args_type::size>{});
             }
             }
         };
         };
 
 
@@ -513,19 +324,19 @@ public:
      */
      */
     template<typename... Args>
     template<typename... Args>
     auto ctor() ENTT_NOEXCEPT {
     auto ctor() ENTT_NOEXCEPT {
-        using helper_type = internal::meta_function_helper_t<Type, Type(*)(Args...)>;
+        using descriptor = meta_function_helper_t<Type, Type(*)(Args...)>;
         auto * const type = internal::meta_info<Type>::resolve();
         auto * const type = internal::meta_info<Type>::resolve();
 
 
         static internal::meta_ctor_node node{
         static internal::meta_ctor_node node{
             type,
             type,
             nullptr,
             nullptr,
             nullptr,
             nullptr,
-            helper_type::args_type::size,
+            descriptor::args_type::size,
             [](const typename internal::meta_ctor_node::size_type index) ENTT_NOEXCEPT {
             [](const typename internal::meta_ctor_node::size_type index) ENTT_NOEXCEPT {
-                return internal::arg(typename helper_type::args_type{}, index);
+                return meta_arg(typename descriptor::args_type{}, index);
             },
             },
             [](meta_any * const any) {
             [](meta_any * const any) {
-                return internal::construct<Type, Args...>(any, std::make_index_sequence<helper_type::args_type::size>{});
+                return meta_construct<Type, Args...>(any, std::make_index_sequence<descriptor::args_type::size>{});
             }
             }
         };
         };
 
 
@@ -597,8 +408,8 @@ public:
                 std::is_same_v<Type, data_type> || std::is_const_v<data_type>,
                 std::is_same_v<Type, data_type> || std::is_const_v<data_type>,
                 true,
                 true,
                 &internal::meta_info<data_type>::resolve,
                 &internal::meta_info<data_type>::resolve,
-                &internal::setter<Type, Data>,
-                &internal::getter<Type, Data, Policy>
+                &meta_setter<Type, Data>,
+                &meta_getter<Type, Data, Policy>
             };
             };
 
 
             ENTT_ASSERT(!exists(id, type->data));
             ENTT_ASSERT(!exists(id, type->data));
@@ -644,8 +455,8 @@ public:
             std::is_same_v<decltype(Setter), std::nullptr_t> || (std::is_member_object_pointer_v<decltype(Setter)> && std::is_const_v<underlying_type>),
             std::is_same_v<decltype(Setter), std::nullptr_t> || (std::is_member_object_pointer_v<decltype(Setter)> && std::is_const_v<underlying_type>),
             false,
             false,
             &internal::meta_info<underlying_type>::resolve,
             &internal::meta_info<underlying_type>::resolve,
-            &internal::setter<Type, Setter>,
-            &internal::getter<Type, Getter, Policy>
+            &meta_setter<Type, Setter>,
+            &meta_getter<Type, Getter, Policy>
         };
         };
 
 
         ENTT_ASSERT(!exists(id, type->data));
         ENTT_ASSERT(!exists(id, type->data));
@@ -672,7 +483,7 @@ public:
      */
      */
     template<auto Candidate, typename Policy = as_is_t>
     template<auto Candidate, typename Policy = as_is_t>
     auto func(const id_type id) ENTT_NOEXCEPT {
     auto func(const id_type id) ENTT_NOEXCEPT {
-        using helper_type = internal::meta_function_helper_t<Type, decltype(Candidate)>;
+        using descriptor = meta_function_helper_t<Type, decltype(Candidate)>;
         auto * const type = internal::meta_info<Type>::resolve();
         auto * const type = internal::meta_info<Type>::resolve();
 
 
         static internal::meta_func_node node{
         static internal::meta_func_node node{
@@ -680,15 +491,15 @@ public:
             type,
             type,
             nullptr,
             nullptr,
             nullptr,
             nullptr,
-            helper_type::args_type::size,
-            helper_type::is_const,
-            helper_type::is_static,
-            &internal::meta_info<std::conditional_t<std::is_same_v<Policy, as_void_t>, void, typename helper_type::return_type>>::resolve,
+            descriptor::args_type::size,
+            descriptor::is_const,
+            descriptor::is_static,
+            &internal::meta_info<std::conditional_t<std::is_same_v<Policy, as_void_t>, void, typename descriptor::return_type>>::resolve,
             [](const typename internal::meta_func_node::size_type index) ENTT_NOEXCEPT {
             [](const typename internal::meta_func_node::size_type index) ENTT_NOEXCEPT {
-                return internal::arg(typename helper_type::args_type{}, index);
+                return meta_arg(typename descriptor::args_type{}, index);
             },
             },
             [](meta_handle instance, meta_any *args) {
             [](meta_handle instance, meta_any *args) {
-                return internal::invoke<Type, Candidate, Policy>(std::move(instance), args, std::make_index_sequence<helper_type::args_type::size>{});
+                return meta_invoke<Type, Candidate, Policy>(std::move(instance), args, std::make_index_sequence<descriptor::args_type::size>{});
             }
             }
         };
         };
 
 

+ 12 - 8
src/entt/meta/meta.hpp

@@ -70,7 +70,7 @@ struct meta_ctor_node {
     meta_ctor_node * next;
     meta_ctor_node * next;
     meta_prop_node * prop;
     meta_prop_node * prop;
     const size_type size;
     const size_type size;
-    meta_type_node *(* const arg)(const size_type) ENTT_NOEXCEPT;
+    meta_type(* const arg)(const size_type) ENTT_NOEXCEPT;
     meta_any(* const invoke)(meta_any * const);
     meta_any(* const invoke)(meta_any * const);
 };
 };
 
 
@@ -98,7 +98,7 @@ struct meta_func_node {
     const bool is_const;
     const bool is_const;
     const bool is_static;
     const bool is_static;
     meta_type_node *(* const ret)() ENTT_NOEXCEPT;
     meta_type_node *(* const ret)() ENTT_NOEXCEPT;
-    meta_type_node *(* const arg)(const size_type) ENTT_NOEXCEPT;
+    meta_type(* const arg)(const size_type) ENTT_NOEXCEPT;
     meta_any(* const invoke)(meta_handle, meta_any *);
     meta_any(* const invoke)(meta_handle, meta_any *);
 };
 };
 
 
@@ -1172,6 +1172,10 @@ private:
 /*! @brief Opaque wrapper for types. */
 /*! @brief Opaque wrapper for types. */
 class meta_type {
 class meta_type {
     static bool can_cast_or_convert(const internal::meta_type_node *type, const type_info info) ENTT_NOEXCEPT {
     static bool can_cast_or_convert(const internal::meta_type_node *type, const type_info info) ENTT_NOEXCEPT {
+        if(type->info == info) {
+            return true;
+        }
+
         for(const auto *curr = type->conv; curr; curr = curr->next) {
         for(const auto *curr = type->conv; curr; curr = curr->next) {
             if(curr->type()->info == info) {
             if(curr->type()->info == info) {
                 return true;
                 return true;
@@ -1179,7 +1183,7 @@ class meta_type {
         }
         }
 
 
         for(const auto *curr = type->base; curr; curr = curr->next) {
         for(const auto *curr = type->base; curr; curr = curr->next) {
-            if(auto *target = curr->type(); target->info == info || can_cast_or_convert(target, info)) {
+            if(auto *target = curr->type(); can_cast_or_convert(target, info)) {
                 return true;
                 return true;
             }
             }
         }
         }
@@ -1190,7 +1194,7 @@ class meta_type {
     template<typename... Args, auto... Index>
     template<typename... Args, auto... Index>
     [[nodiscard]] static const internal::meta_ctor_node * ctor(const internal::meta_ctor_node *curr, std::index_sequence<Index...>) {
     [[nodiscard]] static const internal::meta_ctor_node * ctor(const internal::meta_ctor_node *curr, std::index_sequence<Index...>) {
         for(; curr; curr = curr->next) {
         for(; curr; curr = curr->next) {
-            if(curr->size == sizeof...(Args) && ([](auto *from, auto *to) { return from->info == to->info || can_cast_or_convert(from, to->info); }(internal::meta_info<Args>::resolve(), curr->arg(Index)) && ...)) {
+            if(curr->size == sizeof...(Args) && (can_cast_or_convert(internal::meta_info<Args>::resolve(), curr->arg(Index).info()) && ...)) {
                 return curr;
                 return curr;
             }
             }
         }
         }
@@ -1506,7 +1510,7 @@ public:
     }
     }
 
 
     /**
     /**
-     * @brief Invokes the function with the given identifier, if possible.
+     * @brief Invokes a function given an identifier, if possible.
      *
      *
      * It must be possible to cast the instance to the parent type of the member
      * It must be possible to cast the instance to the parent type of the member
      * function. Otherwise, invoking the underlying function results in an
      * function. Otherwise, invoking the underlying function results in an
@@ -1531,7 +1535,7 @@ public:
 
 
             for(size_type next{}; next < sz && next == (direct + ext); ++next) {
             for(size_type next{}; next < sz && next == (direct + ext); ++next) {
                 const auto type = args[next].type();
                 const auto type = args[next].type();
-                const auto req = it->arg(next)->info;
+                const auto req = it->arg(next).info();
                 type.info() == req ? ++direct : (ext += can_cast_or_convert(type.node, req));
                 type.info() == req ? ++direct : (ext += can_cast_or_convert(type.node, req));
             }
             }
 
 
@@ -1738,7 +1742,7 @@ bool meta_any::set(const id_type id, Type &&value) {
 
 
 
 
 [[nodiscard]] inline meta_type meta_ctor::arg(size_type index) const ENTT_NOEXCEPT {
 [[nodiscard]] inline meta_type meta_ctor::arg(size_type index) const ENTT_NOEXCEPT {
-    return index < size() ? node->arg(index) : nullptr;
+    return index < size() ? node->arg(index) : meta_type{};
 }
 }
 
 
 
 
@@ -1763,7 +1767,7 @@ bool meta_any::set(const id_type id, Type &&value) {
 
 
 
 
 [[nodiscard]] inline meta_type meta_func::arg(size_type index) const ENTT_NOEXCEPT {
 [[nodiscard]] inline meta_type meta_func::arg(size_type index) const ENTT_NOEXCEPT {
-    return index < size() ? node->arg(index) : nullptr;
+    return index < size() ? node->arg(index) : meta_type{};
 }
 }
 
 
 
 

+ 296 - 0
src/entt/meta/utility.hpp

@@ -0,0 +1,296 @@
+#ifndef ENTT_META_UTILITY_HPP
+#define ENTT_META_UTILITY_HPP
+
+
+#include <array>
+#include <cstddef>
+#include <functional>
+#include <type_traits>
+#include <utility>
+#include "../config/config.h"
+#include "../core/type_traits.hpp"
+#include "meta.hpp"
+#include "policy.hpp"
+
+
+namespace entt {
+
+
+/*! @brief Primary template isn't defined on purpose. */
+template<typename, typename>
+struct meta_function_descriptor;
+
+
+/**
+ * @brief Meta function descriptor.
+ * @tparam Type Reflected type to which the meta function is associated.
+ * @tparam Ret Function return type.
+ * @tparam Class Actual owner of the member function.
+ * @tparam Args Function arguments.
+ */
+template<typename Type, typename Ret, typename Class, typename... Args>
+struct meta_function_descriptor<Type, Ret(Class:: *)(Args...) const> {
+    /*! @brief Meta function return type. */
+    using return_type = Ret;
+    /*! @brief Meta function arguments. */
+    using args_type = std::conditional_t<std::is_same_v<Type, Class>, type_list<Args...>, type_list<const Class &, Args...>>;
+
+    /*! @brief True if the meta function is const, false otherwise. */
+    static constexpr auto is_const = true;
+    /*! @brief True if the meta function is static, false otherwise. */
+    static constexpr auto is_static = !std::is_same_v<Type, Class>;
+};
+
+
+/**
+ * @brief Meta function descriptor.
+ * @tparam Type Reflected type to which the meta function is associated.
+ * @tparam Ret Function return type.
+ * @tparam Class Actual owner of the member function.
+ * @tparam Args Function arguments.
+ */
+template<typename Type, typename Ret, typename Class, typename... Args>
+struct meta_function_descriptor<Type, Ret(Class:: *)(Args...)> {
+    /*! @brief Meta function return type. */
+    using return_type = Ret;
+    /*! @brief Meta function arguments. */
+    using args_type = std::conditional_t<std::is_same_v<Type, Class>, type_list<Args...>, type_list<Class &, Args...>>;
+
+    /*! @brief True if the meta function is const, false otherwise. */
+    static constexpr auto is_const = false;
+    /*! @brief True if the meta function is static, false otherwise. */
+    static constexpr auto is_static = !std::is_same_v<Type, Class>;
+};
+
+
+/**
+ * @brief Meta function descriptor.
+ * @tparam Type Reflected type to which the meta function is associated.
+ * @tparam Ret Function return type.
+ * @tparam Args Function arguments.
+ */
+template<typename Type, typename Ret, typename... Args>
+struct meta_function_descriptor<Type, Ret(*)(Args...)> {
+    /*! @brief Meta function return type. */
+    using return_type = Ret;
+    /*! @brief Meta function arguments. */
+    using args_type = type_list<Args...>;
+
+    /*! @brief True if the meta function is const, false otherwise. */
+    static constexpr auto is_const = false;
+    /*! @brief True if the meta function is static, false otherwise. */
+    static constexpr auto is_static = true;
+};
+
+
+/**
+ * @brief Meta function helper.
+ *
+ * Converts a function type to be associated with a reflected type into its meta
+ * function descriptor.
+ *
+ * @tparam Type Reflected type to which the meta function is associated.
+ * @tparam Candidate The actual function to associate with the reflected type.
+ */
+template<typename Type, typename Candidate>
+class meta_function_helper {
+    template<typename Ret, typename... Args, typename Class>
+    static constexpr meta_function_descriptor<Type, Ret(Class:: *)(Args...) const> get_rid_of_noexcept(Ret(Class:: *)(Args...) const);
+
+    template<typename Ret, typename... Args, typename Class>
+    static constexpr meta_function_descriptor<Type, Ret(Class:: *)(Args...)> get_rid_of_noexcept(Ret(Class:: *)(Args...));
+
+    template<typename Ret, typename... Args>
+    static constexpr meta_function_descriptor<Type, Ret(*)(Args...)> get_rid_of_noexcept(Ret(*)(Args...));
+
+public:
+    /*! @brief The meta function descriptor of the given function. */
+    using type = decltype(get_rid_of_noexcept(std::declval<Candidate>()));
+};
+
+
+/**
+ * @brief Helper type.
+ * @tparam Type Reflected type to which the meta function is associated.
+ * @tparam Candidate The actual function to associate with the reflected type.
+ */
+template<typename Type, typename Candidate>
+using meta_function_helper_t = typename meta_function_helper<Type, Candidate>::type;
+
+
+/**
+ * @brief Returns the meta type of the i-th element of a list of arguments.
+ * @tparam Args Actual types of arguments.
+ * @return The meta type of the i-th element of the list of arguments.
+ */
+template<typename... Args>
+[[nodiscard]] static meta_type meta_arg(type_list<Args...>, const std::size_t index) ENTT_NOEXCEPT {
+    return std::array<internal::meta_type_node *, sizeof...(Args)>{{internal::meta_info<Args>::resolve()...}}[index];
+}
+
+
+/**
+ * @brief Constructs an instance given a list of erased parameters, if possible.
+ * @tparam Type Actual type of the instance to construct.
+ * @tparam Args Types of arguments expected.
+ * @tparam Index Indexes to use to extract erased arguments from their list.
+ * @param args Parameters to use to construct the instance.
+ * @return A meta any containing the new instance, if any.
+ */
+template<typename Type, typename... Args, std::size_t... Index>
+[[nodiscard]] meta_any meta_construct(meta_any * const args, std::index_sequence<Index...>) {
+    if(((args+Index)->allow_cast<Args>() && ...)) {
+        return Type{(args+Index)->cast<Args>()...};
+    }
+
+    return {};
+}
+
+
+/**
+ * @brief Sets the value of a given variable.
+ * @tparam Type Reflected type to which the variable is associated.
+ * @tparam Data The actual variable to set.
+ * @param instance An opaque instance of the underlying type, if required.
+ * @param value Parameter to use to set the variable.
+ * @return True in case of success, false otherwise.
+ */
+template<typename Type, auto Data>
+[[nodiscard]] bool meta_setter([[maybe_unused]] meta_handle instance, [[maybe_unused]] meta_any value) {
+    if constexpr(!std::is_same_v<decltype(Data), Type> && !std::is_same_v<decltype(Data), std::nullptr_t>) {
+        if constexpr(std::is_function_v<std::remove_reference_t<std::remove_pointer_t<decltype(Data)>>> || std::is_member_function_pointer_v<decltype(Data)>) {
+            using descriptor = meta_function_helper_t<Type, decltype(Data)>;
+            using data_type = type_list_element_t<!std::is_member_function_pointer_v<decltype(Data)>, typename descriptor::args_type>;
+
+            if(auto * const clazz = instance->try_cast<Type>(); clazz) {
+                if(value.allow_cast<data_type>()) {
+                    std::invoke(Data, *clazz, value.cast<data_type>());
+                    return true;
+                }
+            }
+        } else if constexpr(std::is_member_object_pointer_v<decltype(Data)>) {
+            using data_type = std::remove_reference_t<decltype(std::declval<Type>().*Data)>;
+
+            if constexpr(!std::is_array_v<data_type> && !std::is_const_v<data_type>) {
+                if(auto * const clazz = instance->try_cast<Type>(); clazz) {
+                    if(value.allow_cast<data_type>()) {
+                        std::invoke(Data, clazz) = value.cast<data_type>();
+                        return true;
+                    }
+                }
+            }
+        } else {
+            using data_type = std::remove_reference_t<decltype(*Data)>;
+
+            if constexpr(!std::is_array_v<data_type> && !std::is_const_v<data_type>) {
+                if(value.allow_cast<data_type>()) {
+                    *Data = value.cast<data_type>();
+                    return true;
+                }
+            }
+        }
+    }
+
+    return false;
+}
+
+
+/**
+ * @brief Gets the value of a given variable.
+ * @tparam Type Reflected type to which the variable is associated.
+ * @tparam Data The actual variable to get.
+ * @tparam Policy Optional policy (no policy set by default).
+ * @param instance An opaque instance of the underlying type, if required.
+ * @return A meta any containing the value of the underlying variable.
+ */
+template<typename Type, auto Data, typename Policy = as_is_t>
+[[nodiscard]] meta_any meta_getter([[maybe_unused]] meta_handle instance) {
+    [[maybe_unused]] auto dispatch = [](auto &&value) {
+        if constexpr(std::is_same_v<Policy, as_void_t>) {
+            return meta_any{std::in_place_type<void>, std::forward<decltype(value)>(value)};
+        } else if constexpr(std::is_same_v<Policy, as_ref_t>) {
+            return meta_any{std::reference_wrapper{std::forward<decltype(value)>(value)}};
+        } else if constexpr(std::is_same_v<Policy, as_cref_t>) {
+            return meta_any{std::cref(std::forward<decltype(value)>(value))};
+        } else {
+            static_assert(std::is_same_v<Policy, as_is_t>, "Policy not supported");
+            return meta_any{std::forward<decltype(value)>(value)};
+        }
+    };
+
+    if constexpr(std::is_function_v<std::remove_reference_t<std::remove_pointer_t<decltype(Data)>>> || std::is_member_function_pointer_v<decltype(Data)>) {
+        auto * const clazz = instance->try_cast<std::conditional_t<std::is_invocable_v<decltype(Data), const Type &>, const Type, Type>>();
+        return clazz ? dispatch(std::invoke(Data, *clazz)) : meta_any{};
+    } else if constexpr(std::is_member_object_pointer_v<decltype(Data)>) {
+        if constexpr(std::is_array_v<std::remove_cv_t<std::remove_reference_t<decltype(std::declval<Type>().*Data)>>>) {
+            return meta_any{};
+        } else {
+            if(auto * clazz = instance->try_cast<Type>(); clazz) {
+                return dispatch(std::invoke(Data, *clazz));
+            } else {
+                auto * fallback = instance->try_cast<const Type>();
+                return fallback ? dispatch(std::invoke(Data, *fallback)) : meta_any{};
+            }
+        }
+    } else if constexpr(std::is_pointer_v<decltype(Data)>) {
+        if constexpr(std::is_array_v<std::remove_pointer_t<decltype(Data)>>) {
+            return meta_any{};
+        } else {
+            return dispatch(*Data);
+        }
+    } else {
+        return dispatch(Data);
+    }
+}
+
+
+/**
+ * @brief Invokes a function given a list of erased parameters, if possible.
+ * @tparam Type Reflected type to which the function is associated.
+ * @tparam Candidate The actual function to invoke.
+ * @tparam Policy Optional policy (no policy set by default).
+ * @tparam Index Indexes to use to extract erased arguments from their list.
+ * @param instance An opaque instance of the underlying type, if required.
+ * @param args Parameters to use to invoke the function.
+ * @return A meta any containing the returned value, if any.
+ */
+template<typename Type, auto Candidate, typename Policy = as_is_t, std::size_t... Index>
+[[nodiscard]] meta_any meta_invoke([[maybe_unused]] meta_handle instance, meta_any *args, std::index_sequence<Index...>) {
+    using descriptor = meta_function_helper_t<Type, decltype(Candidate)>;
+
+    auto dispatch = [](auto &&... params) {
+        if constexpr(std::is_void_v<std::remove_cv_t<typename descriptor::return_type>> || std::is_same_v<Policy, as_void_t>) {
+            std::invoke(Candidate, std::forward<decltype(params)>(params)...);
+            return meta_any{std::in_place_type<void>};
+        } else if constexpr(std::is_same_v<Policy, as_ref_t>) {
+            return meta_any{std::reference_wrapper{std::invoke(Candidate, std::forward<decltype(params)>(params)...)}};
+        } else if constexpr(std::is_same_v<Policy, as_cref_t>) {
+            return meta_any{std::cref(std::invoke(Candidate, std::forward<decltype(params)>(params)...))};
+        } else {
+            static_assert(std::is_same_v<Policy, as_is_t>, "Policy not supported");
+            return meta_any{std::invoke(Candidate, std::forward<decltype(params)>(params)...)};
+        }
+    };
+
+    if constexpr(std::is_invocable_v<decltype(Candidate), const Type &, type_list_element_t<Index, typename descriptor::args_type>...>) {
+        if(const auto * const clazz = instance->try_cast<const Type>(); clazz && ((args+Index)->allow_cast<type_list_element_t<Index, typename descriptor::args_type>>() && ...)) {
+            return dispatch(*clazz, (args+Index)->cast<type_list_element_t<Index, typename descriptor::args_type>>()...);
+        }
+    } else if constexpr(std::is_invocable_v<decltype(Candidate), Type &, type_list_element_t<Index, typename descriptor::args_type>...>) {
+        if(auto * const clazz = instance->try_cast<Type>(); clazz && ((args+Index)->allow_cast<type_list_element_t<Index, typename descriptor::args_type>>() && ...)) {
+            return dispatch(*clazz, (args+Index)->cast<type_list_element_t<Index, typename descriptor::args_type>>()...);
+        }
+    } else {
+        if(((args+Index)->allow_cast<type_list_element_t<Index, typename descriptor::args_type>>() && ...)) {
+            return dispatch((args+Index)->cast<type_list_element_t<Index, typename descriptor::args_type>>()...);
+        }
+    }
+
+    return meta_any{};
+}
+
+
+}
+
+
+#endif