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

meta: meta_type::from_void support

Michele Caini 3 лет назад
Родитель
Сommit
274a08070f
4 измененных файлов с 73 добавлено и 0 удалено
  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)
   * [Automatic conversions](#automatic-conversions)
   * [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)
   * [Named constants and enums](#named-constants-and-enums)
   * [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
 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 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));
     }
 
+    /**
+     * @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.
      *

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

@@ -111,6 +111,7 @@ struct meta_type_node {
     meta_type_node *(*const remove_pointer)() noexcept;
     meta_any (*const default_constructor)();
     double (*const conversion_helper)(void *, const void *);
+    meta_any (*const from_void)(void *, const void *);
     const meta_template_node *const templ;
     meta_ctor_node *ctor{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 {
         if constexpr(is_complete_v<meta_template_traits<Type>>) {
             static meta_template_node node{
@@ -184,6 +195,7 @@ public:
             &meta_node<std::remove_cv_t<std::remove_pointer_t<Type>>>::resolve,
             meta_default_constructor(),
             meta_conversion_helper(),
+            meta_from_void(),
             meta_template_info()
             // 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);
 }
 
+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) {
     using namespace entt::literals;