Procházet zdrojové kódy

meta: meta_type::from_void support

Michele Caini před 3 roky
rodič
revize
274a08070f
4 změnil soubory, kde provedl 73 přidání a 0 odebrání
  1. 19 0
      docs/md/meta.md
  2. 14 0
      src/entt/meta/meta.hpp
  3. 12 0
      src/entt/meta/node.hpp
  4. 28 0
      test/entt/meta/meta_type.cpp

+ 19 - 0
docs/md/meta.md

@@ -15,6 +15,7 @@
   * [Template information](#template-information)
   * [Template information](#template-information)
   * [Automatic conversions](#automatic-conversions)
   * [Automatic conversions](#automatic-conversions)
   * [Implicitly generated default constructor](#implicitly-generated-default-constructor)
   * [Implicitly generated default constructor](#implicitly-generated-default-constructor)
+  * [From void to any](#from-void-to-any)
   * [Policies: the more, the less](#policies-the-more-the-less)
   * [Policies: the more, the less](#policies-the-more-the-less)
   * [Named constants and enums](#named-constants-and-enums)
   * [Named constants and enums](#named-constants-and-enums)
   * [Properties and meta objects](#properties-and-meta-objects)
   * [Properties and meta objects](#properties-and-meta-objects)
@@ -783,6 +784,24 @@ useful for building keys without knowing or having to register the actual types.
 In all cases, when users register default constructors, they are preferred both
 In all cases, when users register default constructors, they are preferred both
 during searches and when the `construct` member function is invoked.
 during searches and when the `construct` member function is invoked.
 
 
+## From void to any
+
+Sometimes all a user has is an opaque pointer to an object of a known meta type.
+It would be handy in this case to be able to construct a `meta_any` object from
+them.<br/>
+For this purpose, the `meta_type` class offers a `from_void` member function
+designed to convert an opaque pointer into a `meta_any`:
+
+```cpp
+entt::meta_any any = entt::resolve(id).from_void(element);
+```
+
+It goes without saying that it's not possible to do a check on the actual type.
+Therefore, this call can be considered as a _static cast_ with all the problems
+and undefined behaviors of the case following errors.<br/>
+On the other hand, the ability to construct a `meta_any` from an opaque pointer
+opens the door to some pretty interesting uses that are worth exploring.
+
 ## Policies: the more, the less
 ## Policies: the more, the less
 
 
 Policies are a kind of compile-time directives that can be used when registering
 Policies are a kind of compile-time directives that can be used when registering

+ 14 - 0
src/entt/meta/meta.hpp

@@ -1231,6 +1231,20 @@ public:
         return construct(arguments, sizeof...(Args));
         return construct(arguments, sizeof...(Args));
     }
     }
 
 
+    /**
+     * @brief Wraps an opaque element of the underlying type.
+     * @param element A valid pointer to an element of the underlying type.
+     * @return A wrapper that references the given instance.
+     */
+    meta_any from_void(void *element) {
+        return node->from_void ? node->from_void(element, nullptr) : meta_any{};
+    }
+
+    /*! @copydoc from_void */
+    meta_any from_void(const void *element) {
+        return node->from_void ? node->from_void(nullptr, element) : meta_any{};
+    }
+
     /**
     /**
      * @brief Invokes a function given an identifier, if possible.
      * @brief Invokes a function given an identifier, if possible.
      *
      *

+ 12 - 0
src/entt/meta/node.hpp

@@ -111,6 +111,7 @@ struct meta_type_node {
     meta_type_node *(*const remove_pointer)() noexcept;
     meta_type_node *(*const remove_pointer)() noexcept;
     meta_any (*const default_constructor)();
     meta_any (*const default_constructor)();
     double (*const conversion_helper)(void *, const void *);
     double (*const conversion_helper)(void *, const void *);
+    meta_any (*const from_void)(void *, const void *);
     const meta_template_node *const templ;
     const meta_template_node *const templ;
     meta_ctor_node *ctor{nullptr};
     meta_ctor_node *ctor{nullptr};
     meta_base_node *base{nullptr};
     meta_base_node *base{nullptr};
@@ -149,6 +150,16 @@ class ENTT_API meta_node {
         }
         }
     }
     }
 
 
+    [[nodiscard]] static auto *meta_from_void() noexcept {
+        if constexpr(std::is_same_v<Type, void> || std::is_array_v<Type> || std::is_function_v<Type>) {
+            return static_cast<std::decay_t<decltype(meta_type_node::from_void)>>(nullptr);
+        } else {
+            return +[](void *element, const void *as_const) {
+                return element ? meta_any{std::in_place_type<Type &>, *static_cast<Type *>(element)} : meta_any{std::in_place_type<const Type &>, *static_cast<const Type *>(as_const)};
+            };
+        }
+    }
+
     [[nodiscard]] static meta_template_node *meta_template_info() noexcept {
     [[nodiscard]] static meta_template_node *meta_template_info() noexcept {
         if constexpr(is_complete_v<meta_template_traits<Type>>) {
         if constexpr(is_complete_v<meta_template_traits<Type>>) {
             static meta_template_node node{
             static meta_template_node node{
@@ -184,6 +195,7 @@ public:
             &meta_node<std::remove_cv_t<std::remove_pointer_t<Type>>>::resolve,
             &meta_node<std::remove_cv_t<std::remove_pointer_t<Type>>>::resolve,
             meta_default_constructor(),
             meta_default_constructor(),
             meta_conversion_helper(),
             meta_conversion_helper(),
+            meta_from_void(),
             meta_template_info()
             meta_template_info()
             // tricks clang-format
             // tricks clang-format
         };
         };

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

@@ -465,6 +465,34 @@ TEST_F(MetaType, ConstructArithmeticConversion) {
     ASSERT_EQ(any.cast<clazz_t>().value, 1);
     ASSERT_EQ(any.cast<clazz_t>().value, 1);
 }
 }
 
 
+TEST_F(MetaType, FromVoid) {
+    using namespace entt::literals;
+
+    ASSERT_FALSE(entt::resolve<void>().from_void(static_cast<void *>(nullptr)));
+    ASSERT_FALSE(entt::resolve<void>().from_void(static_cast<const void *>(nullptr)));
+
+    auto type = entt::resolve<double>();
+    double value = 4.2;
+
+    auto as_void = type.from_void(static_cast<void *>(&value));
+    auto as_const_void = type.from_void(static_cast<const void *>(&value));
+
+    ASSERT_TRUE(as_void);
+    ASSERT_TRUE(as_const_void);
+
+    ASSERT_EQ(as_void.type(), entt::resolve<double>());
+    ASSERT_NE(as_void.try_cast<double>(), nullptr);
+
+    ASSERT_EQ(as_const_void.type(), entt::resolve<double>());
+    ASSERT_EQ(as_const_void.try_cast<double>(), nullptr);
+    ASSERT_NE(as_const_void.try_cast<const double>(), nullptr);
+
+    value = 1.2;
+
+    ASSERT_EQ(as_void.cast<double>(), as_const_void.cast<double>());
+    ASSERT_EQ(as_void.cast<double>(), 1.2);
+}
+
 TEST_F(MetaType, Reset) {
 TEST_F(MetaType, Reset) {
     using namespace entt::literals;
     using namespace entt::literals;