Recycle heap on assignment
authorNicholas Ormrod <njormrod@fb.com>
Fri, 12 Jun 2015 16:13:33 +0000 (09:13 -0700)
committerSara Golemon <sgolemon@fb.com>
Fri, 12 Jun 2015 20:18:15 +0000 (13:18 -0700)
Summary: For standard containers, assignment tries to reuse heap space.
Dynamic assignment does not - it calls destroy(), and then reconstructs
a new dynamic. In the case that the old and new types are the same (eg
assigning a dynamic-vector to a dynamic-vector) we can call through to
the underlying type's assignment operator.

Reviewed By: @jdelong

Differential Revision: D2148093

folly/dynamic.cpp
folly/test/DynamicTest.cpp

index 63b737558a0e21897d75d6d79a9d282a1e5e4356..abb57adc6cb31cbd59e90d15f2b3edff32d6abe1 100644 (file)
@@ -100,22 +100,34 @@ bool dynamic::operator==(dynamic const& o) const {
 
 dynamic& dynamic::operator=(dynamic const& o) {
   if (&o != this) {
-    destroy();
+    if (type_ == o.type_) {
+#define FB_X(T) *getAddress<T>() = *o.getAddress<T>()
+      FB_DYNAMIC_APPLY(type_, FB_X);
+#undef FB_X
+    } else {
+      destroy();
 #define FB_X(T) new (getAddress<T>()) T(*o.getAddress<T>())
-    FB_DYNAMIC_APPLY(o.type_, FB_X);
+      FB_DYNAMIC_APPLY(o.type_, FB_X);
 #undef FB_X
-    type_ = o.type_;
+      type_ = o.type_;
+    }
   }
   return *this;
 }
 
 dynamic& dynamic::operator=(dynamic&& o) noexcept {
   if (&o != this) {
-    destroy();
+    if (type_ == o.type_) {
+#define FB_X(T) *getAddress<T>() = std::move(*o.getAddress<T>())
+      FB_DYNAMIC_APPLY(type_, FB_X);
+#undef FB_X
+    } else {
+      destroy();
 #define FB_X(T) new (getAddress<T>()) T(std::move(*o.getAddress<T>()))
-    FB_DYNAMIC_APPLY(o.type_, FB_X);
+      FB_DYNAMIC_APPLY(o.type_, FB_X);
 #undef FB_X
-    type_ = o.type_;
+      type_ = o.type_;
+    }
   }
   return *this;
 }
index ba179c1b7333a3ff6e5b7c38df9bcf7cb1461361..6579578e4cbbea58e7802b6223b9217132a61d3b 100644 (file)
@@ -285,6 +285,29 @@ TEST(Dynamic, GetPtr) {
   EXPECT_EQ(dynamic(2), *cobject.get_ptr("two"));
 }
 
+TEST(Dynamic, Assignment) {
+  const dynamic ds[] = { { 1, 2, 3 },
+                         dynamic::object("a", true),
+                         24,
+                         26.5,
+                         true,
+                         "hello", };
+  const dynamic dd[] = { { 5, 6 },
+                         dynamic::object("t", "T")(1, 7),
+                         9000,
+                         3.14159,
+                         false,
+                         "world", };
+  for (const auto& source : ds) {
+    for (const auto& dest : dd) {
+      dynamic tmp(dest);
+      EXPECT_EQ(tmp, dest);
+      tmp = source;
+      EXPECT_EQ(tmp, source);
+    }
+  }
+}
+
 int main(int argc, char** argv) {
   testing::InitGoogleTest(&argc, argv);
   gflags::ParseCommandLineFlags(&argc, &argv, true);