فهرست منبع

meta: added minimal class template support to meta_type

Michele Caini 5 سال پیش
والد
کامیت
5e4c63736b
4فایلهای تغییر یافته به همراه96 افزوده شده و 11 حذف شده
  1. 1 0
      TODO
  2. 42 4
      src/entt/meta/meta.hpp
  3. 40 7
      src/entt/meta/node.hpp
  4. 13 0
      test/entt/meta/meta_type.cpp

+ 1 - 0
TODO

@@ -18,6 +18,7 @@
   - ...
 
 WIP:
+* HP: meta func/ctor size -> arity
 * HP: as_ref should be a qualified function, not a global one (no breaking change, ADL makes it work anyway)
 * HP: merge view and view pack
 * HP: invalid view auto-refresh

+ 42 - 4
src/entt/meta/meta.hpp

@@ -688,8 +688,8 @@ struct meta_ctor {
 
     /**
      * @brief Returns the type of the i-th argument of a constructor.
-     * @param index The index of the argument of which to return the type.
-     * @return The type of the i-th argument of a constructor, if any.
+     * @param index Index of the argument of which to return the type.
+     * @return The type of the i-th argument of a constructor.
      */
     [[nodiscard]] meta_type arg(size_type index) const ENTT_NOEXCEPT;
 
@@ -900,8 +900,8 @@ struct meta_func {
 
     /**
      * @brief Returns the type of the i-th argument of a member function.
-     * @param index The index of the argument of which to return the type.
-     * @return The type of the i-th argument of a member function, if any.
+     * @param index Index of the argument of which to return the type.
+     * @return The type of the i-th argument of a member function.
      */
     [[nodiscard]] inline meta_type arg(size_type index) const ENTT_NOEXCEPT;
 
@@ -1163,6 +1163,44 @@ public:
         return node->is_associative_container;
     }
 
+    /**
+     * @brief Checks whether a type refers to a recognized class template
+     * specialization or not.
+     * @return True if the type is a recognized class template specialization,
+     * false otherwise.
+     */
+    [[nodiscard]] bool is_template_specialization() const ENTT_NOEXCEPT {
+        return node->template_info.is_template_specialization;
+    }
+
+    /**
+     * @brief Returns the number of template arguments, if any.
+     * @return The number of template arguments, if any.
+     */
+    [[nodiscard]] size_type template_arity() const ENTT_NOEXCEPT {
+        return node->template_info.template_arity;
+    }
+
+    /**
+     * @brief Returns a tag for the class template of the underlying type.
+     *
+     * @sa meta_class_template_tag
+     *
+     * @return The tag for the class template of the underlying type.
+     */
+    [[nodiscard]] inline meta_type template_type() const ENTT_NOEXCEPT {
+        return is_template_specialization() ?  node->template_info.template_type() : meta_type{};
+    }
+
+    /**
+     * @brief Returns the type of the i-th template argument of a type.
+     * @param index Index of the template argument of which to return the type.
+     * @return The type of the i-th template argument of a type.
+     */
+    [[nodiscard]] inline meta_type template_arg(size_type index) const ENTT_NOEXCEPT {
+        return index < template_arity() ? node->template_info.template_arg(index) : meta_type{};
+    }
+
     /**
      * @brief Provides the number of dimensions of an array type.
      * @return The number of dimensions in case of array types, 0 otherwise.

+ 40 - 7
src/entt/meta/node.hpp

@@ -2,6 +2,7 @@
 #define ENTT_META_NODE_HPP
 
 
+#include <array>
 #include <cstddef>
 #include <type_traits>
 #include <utility>
@@ -17,6 +18,11 @@
 namespace entt {
 
 
+/*! @brief Utility class to disambiguate class templates. */
+template<template<typename...> typename>
+struct meta_class_template_tag {};
+
+
 class meta_any;
 class meta_type;
 struct meta_handle;
@@ -96,6 +102,15 @@ struct meta_func_node {
 };
 
 
+struct meta_template_info {
+    using size_type = std::size_t;
+    const bool is_template_specialization;
+    const size_type template_arity;
+    meta_type_node *(* const template_type)() ENTT_NOEXCEPT;
+    meta_type_node *(* const template_arg)(const size_type) ENTT_NOEXCEPT;
+};
+
+
 struct meta_type_node {
     using size_type = std::size_t;
     const type_info info;
@@ -117,8 +132,9 @@ struct meta_type_node {
     const bool is_pointer_like;
     const bool is_sequence_container;
     const bool is_associative_container;
+    meta_template_info template_info;
     const size_type rank;
-    size_type(* const extent)(const size_type);
+    size_type(* const extent)(const size_type) ENTT_NOEXCEPT ;
     meta_type_node *(* const remove_pointer)() ENTT_NOEXCEPT;
     meta_type_node *(* const remove_extent)() ENTT_NOEXCEPT;
     meta_ctor_node *def_ctor{nullptr};
@@ -157,15 +173,15 @@ class ENTT_API meta_node {
     static_assert(std::is_same_v<Type, std::remove_cv_t<std::remove_reference_t<Type>>>, "Invalid type");
 
     template<std::size_t... Index>
-    [[nodiscard]] static auto extent(const meta_type_node::size_type dim, std::index_sequence<Index...>) {
+    [[nodiscard]] static auto extent(const meta_type_node::size_type dim, std::index_sequence<Index...>) ENTT_NOEXCEPT {
         meta_type_node::size_type ext{};
         ((ext = (dim == Index ? std::extent_v<Type, Index> : ext)), ...);
         return ext;
     }
 
-    [[nodiscard]] static meta_ctor_node * meta_default_constructor([[maybe_unused]] meta_type_node *type) {
+    [[nodiscard]] static meta_ctor_node * meta_default_constructor([[maybe_unused]] meta_type_node *type) ENTT_NOEXCEPT {
         if constexpr(std::is_default_constructible_v<Type>) {
-            static internal::meta_ctor_node node{
+            static meta_ctor_node node{
                 type,
                 nullptr,
                 nullptr,
@@ -180,8 +196,24 @@ class ENTT_API meta_node {
         }
     }
 
+    template<template<typename...> typename Clazz, typename... Args>
+    [[nodiscard]] static meta_template_info template_info(type_identity<Clazz<Args...>>) ENTT_NOEXCEPT {
+        return {
+            true,
+            sizeof...(Args),
+            &meta_node<meta_class_template_tag<Clazz>>::resolve,
+            [](const std::size_t index) ENTT_NOEXCEPT {
+                return std::array<meta_type_node *, sizeof...(Args)>{{internal::meta_info<Args>::resolve()...}}[index];
+            }
+        };
+    }
+
+    [[nodiscard]] static meta_template_info template_info(...) ENTT_NOEXCEPT {
+        return { false, 0u, nullptr, nullptr };
+    }
+
 public:
-    [[nodiscard]] static internal::meta_type_node * resolve() ENTT_NOEXCEPT {
+    [[nodiscard]] static meta_type_node * resolve() ENTT_NOEXCEPT {
         static meta_type_node node{
             type_id<Type>(),
             {},
@@ -202,10 +234,11 @@ public:
             is_meta_pointer_like_v<Type>,
             has_meta_sequence_container_traits_v<Type>,
             has_meta_associative_container_traits_v<Type>,
+            template_info(type_identity<Type>{}),
             std::rank_v<Type>,
-            [](meta_type_node::size_type dim) { return extent(dim, std::make_index_sequence<std::rank_v<Type>>{}); },
+            [](meta_type_node::size_type dim) ENTT_NOEXCEPT { return extent(dim, std::make_index_sequence<std::rank_v<Type>>{}); },
             &meta_node<std::remove_cv_t<std::remove_pointer_t<Type>>>::resolve,
-            &meta_node<std::remove_cv_t<std::remove_extent_t<Type>>>::resolve,
+            &meta_node<std::remove_cv_t<std::remove_reference_t<std::remove_extent_t<Type>>>>::resolve,
             meta_default_constructor(&node),
             meta_default_constructor(&node)
         };

+ 13 - 0
test/entt/meta/meta_type.cpp

@@ -599,3 +599,16 @@ TEST_F(MetaType, ResetAndReRegistrationAfterReset) {
     ASSERT_TRUE(entt::resolve<property_t>().data("rand"_hs).prop(property_t::value));
     ASSERT_TRUE(entt::resolve<property_t>().data("rand"_hs).prop(property_t::random));
 }
+
+TEST_F(MetaType, ClassTemplate) {
+    ASSERT_FALSE(entt::resolve<int>().is_template_specialization());
+    ASSERT_EQ(entt::resolve<int>().template_arity(), 0u);
+    ASSERT_EQ(entt::resolve<int>().template_type(), entt::meta_type{});
+    ASSERT_EQ(entt::resolve<int>().template_arg(0u), entt::meta_type{});
+
+    ASSERT_TRUE(entt::resolve<std::shared_ptr<int>>().is_template_specialization());
+    ASSERT_EQ(entt::resolve<std::shared_ptr<int>>().template_arity(), 1u);
+    ASSERT_EQ(entt::resolve<std::shared_ptr<int>>().template_type(), entt::resolve<entt::meta_class_template_tag<std::shared_ptr>>());
+    ASSERT_EQ(entt::resolve<std::shared_ptr<int>>().template_arg(0u), entt::resolve<int>());
+    ASSERT_EQ(entt::resolve<std::shared_ptr<int>>().template_arg(1u), entt::meta_type{});
+}