Browse Source

meta_any: fixed #180

Michele Caini 7 years ago
parent
commit
45fdab27c9
2 changed files with 55 additions and 23 deletions
  1. 22 16
      src/entt/meta/meta.hpp
  2. 33 7
      test/entt/meta/meta.cpp

+ 22 - 16
src/entt/meta/meta.hpp

@@ -379,9 +379,7 @@ public:
         compare_fn = &compare<actual_type>;
 
         if constexpr(sizeof(actual_type) <= sizeof(void *)) {
-            new (&storage) actual_type{std::forward<Type>(type)};
-            instance = &storage;
-
+            instance = new (&storage) actual_type{std::forward<Type>(type)};
             destroy_fn = &destroy_storage<actual_type>;
             copy_fn = &copy_storage<actual_type>;
         } else {
@@ -440,7 +438,7 @@ public:
      * @return This meta any object.
      */
     meta_any & operator=(meta_any other) {
-        swap(*this, other);
+        swap(other, *this);
         return *this;
     }
 
@@ -550,7 +548,7 @@ public:
             auto any = std::as_const(*this).convert<Type>();
 
             if(any) {
-                std::swap(*this, any);
+                std::swap(any, *this);
                 valid = true;
             }
         }
@@ -584,20 +582,28 @@ public:
     friend void swap(meta_any &lhs, meta_any &rhs) {
         using std::swap;
 
-        std::swap(lhs.storage, rhs.storage);
-        std::swap(lhs.instance, rhs.instance);
-        std::swap(lhs.destroy_fn, rhs.destroy_fn);
+        if(lhs && rhs) {
+            storage_type buffer;
+            void *tmp = lhs.copy_fn(buffer, lhs.instance);
+            lhs.destroy_fn(lhs.storage);
+            lhs.instance = rhs.copy_fn(lhs.storage, rhs.instance);
+            rhs.destroy_fn(rhs.storage);
+            rhs.instance = lhs.copy_fn(rhs.storage, tmp);
+            lhs.destroy_fn(buffer);
+        } else if(lhs) {
+            rhs.instance = lhs.copy_fn(rhs.storage, lhs.instance);
+            lhs.destroy_fn(lhs.storage);
+            lhs.instance = nullptr;
+        } else if(rhs) {
+            lhs.instance = rhs.copy_fn(lhs.storage, rhs.instance);
+            rhs.destroy_fn(rhs.storage);
+            rhs.instance = nullptr;
+        }
+
         std::swap(lhs.node, rhs.node);
+        std::swap(lhs.destroy_fn, rhs.destroy_fn);
         std::swap(lhs.compare_fn, rhs.compare_fn);
         std::swap(lhs.copy_fn, rhs.copy_fn);
-
-        if(lhs.instance == &rhs.storage) {
-            lhs.instance = &lhs.storage;
-        }
-
-        if(rhs.instance == &lhs.storage) {
-            rhs.instance = &rhs.storage;
-        }
     }
 
 private:

+ 33 - 7
test/entt/meta/meta.cpp

@@ -367,15 +367,13 @@ TEST_F(Meta, MetaAnyNoSBOMoveAssignment) {
 
 TEST_F(Meta, MetaAnySBODestruction) {
     ASSERT_EQ(empty_type::counter, 0);
-    entt::meta_any any{empty_type{}};
-    any = {};
+    { entt::meta_any any{empty_type{}}; }
     ASSERT_EQ(empty_type::counter, 1);
 }
 
 TEST_F(Meta, MetaAnyNoSBODestruction) {
     ASSERT_EQ(fat_type::counter, 0);
-    entt::meta_any any{fat_type{}};
-    any = {};
+    { entt::meta_any any{fat_type{}}; }
     ASSERT_EQ(fat_type::counter, 1);
 }
 
@@ -416,6 +414,37 @@ TEST_F(Meta, MetaAnySBOWithNoSBOSwap) {
     ASSERT_EQ(rhs.cast<fat_type>().bar, &value);
 }
 
+TEST_F(Meta, MetaAnySBOWithEmptySwap) {
+    entt::meta_any lhs{'c'};
+    entt::meta_any rhs{};
+
+    std::swap(lhs, rhs);
+
+    ASSERT_FALSE(lhs);
+    ASSERT_TRUE(rhs.can_cast<char>());
+    ASSERT_EQ(rhs.cast<char>(), 'c');
+
+    std::swap(lhs, rhs);
+
+    ASSERT_FALSE(rhs);
+    ASSERT_TRUE(lhs.can_cast<char>());
+    ASSERT_EQ(lhs.cast<char>(), 'c');
+}
+
+TEST_F(Meta, MetaAnyNoSBOWithEmptySwap) {
+    int i;
+    entt::meta_any lhs{fat_type{&i}};
+    entt::meta_any rhs{};
+
+    std::swap(lhs, rhs);
+
+    ASSERT_EQ(rhs.cast<fat_type>().bar, &i);
+
+    std::swap(lhs, rhs);
+
+    ASSERT_EQ(lhs.cast<fat_type>().bar, &i);
+}
+
 TEST_F(Meta, MetaAnyComparable) {
     entt::meta_any any{'c'};
 
@@ -1283,14 +1312,12 @@ TEST_F(Meta, MetaTypeConstructMetaAnyArgs) {
     ASSERT_EQ(any.cast<derived_type>().c, 'c');
 }
 
-
 TEST_F(Meta, MetaTypeConstructInvalidArgs) {
     auto type = entt::resolve<derived_type>();
     auto any = type.construct(entt::meta_any{base_type{}}, entt::meta_any{'c'}, entt::meta_any{42});
     ASSERT_FALSE(any);
 }
 
-
 TEST_F(Meta, MetaTypeConstructCastAndConvert) {
     auto type = entt::resolve<derived_type>();
     auto any = type.construct(entt::meta_any{derived_type{}}, entt::meta_any{42.}, entt::meta_any{'c'});
@@ -1301,7 +1328,6 @@ TEST_F(Meta, MetaTypeConstructCastAndConvert) {
     ASSERT_EQ(any.cast<derived_type>().c, 'c');
 }
 
-
 TEST_F(Meta, MetaTypeDestroyDtor) {
     auto type = entt::resolve<empty_type>();