Просмотр исходного кода

added support for free/member functions to meta_conv

Michele Caini 6 лет назад
Родитель
Сommit
0d921dc1fc
4 измененных файлов с 84 добавлено и 13 удалено
  1. 1 5
      TODO
  2. 43 5
      src/entt/meta/factory.hpp
  3. 2 2
      src/entt/meta/meta.hpp
  4. 38 1
      test/entt/meta/meta.cpp

+ 1 - 5
TODO

@@ -17,14 +17,10 @@
 * add take functionality, eg registry.take(entity, other); where it takes the entity and all its components from registry and move them to other
 * add opaque input iterators to views and groups that return tuples <entity, T &...> (proxy), multi-pass guaranteed
 * add fast lane for raw iterations, extend mt doc to describe allowed add/remove with pre-allocations on fast lanes
-* review 64 bit id: user defined area + dedicated member on the registry to set it
-* early out in views using bitmasks with bloom filter like access based on modulus
-  - standard each, use bitmask to speed up the whole thing and avoid accessing the pools to test for the page
-  - iterator based each with a couple of iterators passed from outside (use bitmask + has)
-* stable component handle that isn't affected by reallocations
 * multi component registry::remove and some others?
 * can I use opaque connection also for the emitter?
 * built-in support for dual (or N-) buffering
+* meta: opaque references and pointers
 
 TODO
 * registry::sort also for types that are part of a group (untracked items only)

+ 43 - 5
src/entt/meta/factory.hpp

@@ -244,8 +244,8 @@ public:
             type,
             nullptr,
             &internal::meta_info<To>::resolve,
-            [](void *instance) -> meta_any {
-                return static_cast<To>(*static_cast<Type *>(instance));
+            [](const void *instance) -> meta_any {
+                return static_cast<To>(*static_cast<const Type *>(instance));
             },
             []() ENTT_NOEXCEPT -> meta_conv {
                 return &node;
@@ -260,12 +260,50 @@ public:
         return *this;
     }
 
+    /**
+     * @brief Assigns a meta conversion function to a meta type.
+     *
+     * Conversion functions can be either free functions or member
+     * functions.<br/>
+     * In case of free functions, they must accept a reference to an instance of
+     * the parent type as an argument. Otherwise, they must accept no arguments
+     * at all.
+     *
+     * @tparam Candidate The actual function to use for the conversion.
+     * @return A meta factory for the parent type.
+     */
+    template<auto Candidate>
+    meta_factory conv() ENTT_NOEXCEPT {
+        using conv_type = std::invoke_result_t<decltype(Candidate), Type &>;
+        auto * const type = internal::meta_info<Type>::resolve();
+
+        static internal::meta_conv_node node{
+            &internal::meta_info<Type>::template conv<conv_type>,
+            type,
+            nullptr,
+            &internal::meta_info<conv_type>::resolve,
+            [](const void *instance) -> meta_any {
+                return std::invoke(Candidate, *static_cast<const Type *>(instance));
+            },
+            []() ENTT_NOEXCEPT -> meta_conv {
+                return &node;
+            }
+        };
+
+        node.next = type->conv;
+        ENTT_ASSERT((!internal::meta_info<Type>::template conv<conv_type>));
+        internal::meta_info<Type>::template conv<conv_type> = &node;
+        type->conv = &node;
+
+        return *this;
+    }
+
     /**
      * @brief Assigns a meta constructor to a meta type.
      *
-     * Free functions can be assigned to meta types in the role of
-     * constructors. All that is required is that they return an instance of the
-     * underlying type.<br/>
+     * Free functions can be assigned to meta types in the role of constructors.
+     * All that is required is that they return an instance of the underlying
+     * type.<br/>
      * From a client's point of view, nothing changes if a constructor of a meta
      * type is a built-in one or a free function.
      *

+ 2 - 2
src/entt/meta/meta.hpp

@@ -63,7 +63,7 @@ struct meta_conv_node {
     meta_type_node * const parent;
     meta_conv_node * next;
     meta_type_node *(* const type)() ENTT_NOEXCEPT;
-    meta_any(* const conv)(void *);
+    meta_any(* const conv)(const void *);
     meta_conv(* const meta)() ENTT_NOEXCEPT;
 };
 
@@ -982,7 +982,7 @@ public:
      * @param instance The instance to convert.
      * @return An opaque pointer to the instance to convert.
      */
-    meta_any convert(void *instance) const ENTT_NOEXCEPT {
+    meta_any convert(const void *instance) const ENTT_NOEXCEPT {
         return node->conv(instance);
     }
 

+ 38 - 1
test/entt/meta/meta.cpp

@@ -56,6 +56,9 @@ struct derived_type: base_type {
         : i{value}, c{character}
     {}
 
+    int f() const { return i; }
+    static char g(const derived_type &type) { return type.c; }
+
     const int i{};
     const char c{};
 };
@@ -144,7 +147,9 @@ struct Meta: public ::testing::Test {
         entt::reflect<derived_type>("derived"_hs, std::make_pair(properties::prop_int, 99))
                 .base<base_type>()
                 .ctor<const base_type &, int, char>(std::make_pair(properties::prop_bool, false))
-                .ctor<&derived_factory>(std::make_pair(properties::prop_int, 42));
+                .ctor<&derived_factory>(std::make_pair(properties::prop_int, 42))
+                .conv<&derived_type::f>()
+                .conv<&derived_type::g>();
 
         entt::reflect<empty_type>("empty"_hs)
                 .dtor<&empty_type::destroy>();
@@ -849,6 +854,38 @@ TEST_F(Meta, MetaConv) {
     ASSERT_EQ(any.cast<int>(), 3);
 }
 
+TEST_F(Meta, MetaConvAsFreeFunctions) {
+    auto conv = entt::resolve<derived_type>().conv<int>();
+    derived_type derived{derived_type{}, 42, 'c'};
+
+    ASSERT_TRUE(conv);
+    ASSERT_NE(conv, entt::meta_conv{});
+    ASSERT_EQ(conv.parent(), entt::resolve<derived_type>());
+    ASSERT_EQ(conv.type(), entt::resolve<int>());
+
+    auto any = conv.convert(&derived);
+
+    ASSERT_TRUE(any);
+    ASSERT_EQ(any.type(), entt::resolve<int>());
+    ASSERT_EQ(any.cast<int>(), 42);
+}
+
+TEST_F(Meta, MetaConvAsMemberFunctions) {
+    auto conv = entt::resolve<derived_type>().conv<char>();
+    derived_type derived{derived_type{}, 42, 'c'};
+
+    ASSERT_TRUE(conv);
+    ASSERT_NE(conv, entt::meta_conv{});
+    ASSERT_EQ(conv.parent(), entt::resolve<derived_type>());
+    ASSERT_EQ(conv.type(), entt::resolve<char>());
+
+    auto any = conv.convert(&derived);
+
+    ASSERT_TRUE(any);
+    ASSERT_EQ(any.type(), entt::resolve<char>());
+    ASSERT_EQ(any.cast<char>(), 'c');
+}
+
 TEST_F(Meta, MetaCtor) {
     auto ctor = entt::resolve<derived_type>().ctor<const base_type &, int, char>();