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

meta_any: transfer ownership with from_void - close #1179

Michele Caini 1 год назад
Родитель
Сommit
b971116c21
3 измененных файлов с 41 добавлено и 4 удалено
  1. 3 2
      src/entt/meta/meta.hpp
  2. 3 1
      src/entt/meta/node.hpp
  3. 35 1
      test/entt/meta/meta_type.cpp

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

@@ -1398,10 +1398,11 @@ public:
     /**
      * @brief Wraps an opaque element of the underlying type.
      * @param elem A valid pointer to an element of the underlying type.
+     * @param transfer_ownership True to transfer ownership, false otherwise.
      * @return A wrapper that references the given instance.
      */
-    [[nodiscard]] meta_any from_void(void *elem) const {
-        return ((elem != nullptr) && (node.from_void != nullptr)) ? node.from_void(*ctx, elem, nullptr) : meta_any{meta_ctx_arg, *ctx};
+    [[nodiscard]] meta_any from_void(void *elem, bool transfer_ownership = false) const {
+        return ((elem != nullptr) && (node.from_void != nullptr)) ? node.from_void(*ctx, elem, transfer_ownership ? elem : nullptr) : meta_any{meta_ctx_arg, *ctx};
     }
 
     /*! @copydoc from_void */

+ 3 - 1
src/entt/meta/node.hpp

@@ -289,7 +289,9 @@ template<typename Type>
 
     if constexpr(!std::is_void_v<Type> && !std::is_function_v<Type>) {
         node.from_void = +[](const meta_ctx &ctx, void *elem, const void *celem) {
-            if(elem) {
+            if(elem && celem) { // ownership construction request
+                return meta_any{ctx, std::in_place, static_cast<std::decay_t<Type> *>(elem)};
+            } else if(elem) {
                 return meta_any{ctx, std::in_place_type<std::decay_t<Type> &>, *static_cast<std::decay_t<Type> *>(elem)};
             }
 

+ 35 - 1
test/entt/meta/meta_type.cpp

@@ -96,6 +96,18 @@ struct overloaded_func {
     int value{};
 };
 
+struct from_void_callback {
+    from_void_callback(bool &ref)
+        : cb{&ref} {}
+
+    ~from_void_callback() {
+        *cb = !*cb;
+    }
+
+private:
+    bool *cb;
+};
+
 enum class property_type : entt::id_type {
     value,
     other
@@ -558,12 +570,12 @@ TEST_F(MetaType, FromVoid) {
     ASSERT_FALSE(entt::resolve<double>().from_void(static_cast<double *>(nullptr)));
     ASSERT_FALSE(entt::resolve<double>().from_void(static_cast<const double *>(nullptr)));
 
-    auto type = entt::resolve<double>();
     double value = 4.2;
 
     ASSERT_FALSE(entt::resolve<void>().from_void(static_cast<void *>(&value)));
     ASSERT_FALSE(entt::resolve<void>().from_void(static_cast<const void *>(&value)));
 
+    auto type = entt::resolve<double>();
     auto as_void = type.from_void(static_cast<void *>(&value));
     auto as_const_void = type.from_void(static_cast<const void *>(&value));
 
@@ -583,6 +595,28 @@ TEST_F(MetaType, FromVoid) {
     ASSERT_EQ(as_void.cast<double>(), 1.2);
 }
 
+TEST_F(MetaType, FromVoidOwnership) {
+    bool check = false;
+    auto type = entt::resolve<from_void_callback>();
+    auto instance = std::make_unique<from_void_callback>(check);
+
+    auto any = type.from_void(static_cast<void *>(instance.get()));
+    auto other = type.from_void(static_cast<void *>(instance.release()), true);
+
+    ASSERT_TRUE(any);
+    ASSERT_TRUE(other);
+
+    ASSERT_FALSE(check);
+
+    any.reset();
+
+    ASSERT_FALSE(check);
+
+    other.reset();
+
+    ASSERT_TRUE(check);
+}
+
 TEST_F(MetaType, Reset) {
     using namespace entt::literals;