From 461f01823caf2c1d17a1cecee98603c7c58c7710 Mon Sep 17 00:00:00 2001 From: Nicholas Ormrod Date: Fri, 12 Jun 2015 09:13:33 -0700 Subject: [PATCH] Recycle heap on assignment 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 | 24 ++++++++++++++++++------ folly/test/DynamicTest.cpp | 23 +++++++++++++++++++++++ 2 files changed, 41 insertions(+), 6 deletions(-) diff --git a/folly/dynamic.cpp b/folly/dynamic.cpp index 63b73755..abb57adc 100644 --- a/folly/dynamic.cpp +++ b/folly/dynamic.cpp @@ -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() = *o.getAddress() + FB_DYNAMIC_APPLY(type_, FB_X); +#undef FB_X + } else { + destroy(); #define FB_X(T) new (getAddress()) T(*o.getAddress()) - 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() = std::move(*o.getAddress()) + FB_DYNAMIC_APPLY(type_, FB_X); +#undef FB_X + } else { + destroy(); #define FB_X(T) new (getAddress()) T(std::move(*o.getAddress())) - 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; } diff --git a/folly/test/DynamicTest.cpp b/folly/test/DynamicTest.cpp index ba179c1b..6579578e 100644 --- a/folly/test/DynamicTest.cpp +++ b/folly/test/DynamicTest.cpp @@ -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); -- 2.34.1