From: Kevin Hurley Date: Fri, 11 Sep 2015 17:25:14 +0000 (-0700) Subject: Add ability to merge dynamic objects X-Git-Tag: deprecate-dynamic-initializer~420 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=84138864d0f593e23c76deb3b9da430cbb0a4ab2;p=folly.git Add ability to merge dynamic objects Summary: Adding ability to merge dynamic objects with another object. It will just overwrite duplicate keys Reviewed By: @yfeldblum Differential Revision: D2413628 --- diff --git a/folly/dynamic-inl.h b/folly/dynamic-inl.h index 6e2fd62a..ff503c4a 100644 --- a/folly/dynamic-inl.h +++ b/folly/dynamic-inl.h @@ -512,6 +512,41 @@ template inline void dynamic::insert(K&& key, V&& val) { rv.first->second = std::forward(val); } +inline void dynamic::update(const dynamic& mergeObj) { + if (!isObject() || !mergeObj.isObject()) { + throw TypeError("object", type(), mergeObj.type()); + } + + for (const auto& pair : mergeObj.items()) { + (*this)[pair.first] = pair.second; + } +} + +inline void dynamic::update_missing(const dynamic& mergeObj1) { + if (!isObject() || !mergeObj1.isObject()) { + throw TypeError("object", type(), mergeObj1.type()); + } + + // Only add if not already there + for (const auto& pair : mergeObj1.items()) { + if ((*this).find(pair.first) == (*this).items().end()) { + (*this)[pair.first] = pair.second; + } + } +} + +inline dynamic dynamic::merge( + const dynamic& mergeObj1, + const dynamic& mergeObj2) { + + // No checks on type needed here because they are done in update_missing + // Note that we do update_missing here instead of update() because + // it will prevent the extra writes that would occur with update() + auto ret = mergeObj2; + ret.update_missing(mergeObj1); + return ret; +} + inline std::size_t dynamic::erase(dynamic const& key) { auto& obj = get(); return obj.erase(key); diff --git a/folly/dynamic.h b/folly/dynamic.h index bea7fc44..fa494555 100644 --- a/folly/dynamic.h +++ b/folly/dynamic.h @@ -436,6 +436,23 @@ public: */ template void insert(K&&, V&& val); + /* + * These functions merge two folly dynamic objects. + * The "update" and "update_missing" functions extend the object by + * inserting the key/value pairs of mergeObj into the current object. + * For update, if key is duplicated between the two objects, it + * will overwrite with the value of the object being inserted (mergeObj). + * For "update_missing", it will prefer the value in the original object + * + * The "merge" function creates a new object consisting of the key/value + * pairs of both mergeObj1 and mergeObj2 + * If the key is duplicated between the two objects, + * it will prefer value in the second object (mergeObj2) + */ + void update(const dynamic& mergeObj); + void update_missing(const dynamic& other); + static dynamic merge(const dynamic& mergeObj1, const dynamic& mergeObj2); + /* * Erase an element from a dynamic object, by key. * diff --git a/folly/test/DynamicTest.cpp b/folly/test/DynamicTest.cpp index 7ba744fb..97af70be 100644 --- a/folly/test/DynamicTest.cpp +++ b/folly/test/DynamicTest.cpp @@ -98,6 +98,27 @@ TEST(Dynamic, ObjectBasics) { // We don't allow objects as keys in objects. EXPECT_ANY_THROW(newObject[d3] = 12); + + // Merge two objects + dynamic origMergeObj1 = folly::dynamic::object(); + dynamic mergeObj1 = origMergeObj1 = folly::dynamic::object + ("key1", "value1") + ("key2", "value2"); + dynamic mergeObj2 = folly::dynamic::object + ("key2", "value3") + ("key3", "value4"); + dynamic combinedObj = folly::dynamic::object + ("key1", "value1") + ("key2", "value3") + ("key3", "value4"); + auto newMergeObj = dynamic::merge(mergeObj1, mergeObj2); + EXPECT_EQ(newMergeObj, combinedObj); + EXPECT_EQ(mergeObj1, origMergeObj1); // mergeObj1 should be unchanged + + mergeObj1.update(mergeObj2); + EXPECT_EQ(mergeObj1, combinedObj); + dynamic arr = { 1, 2, 3, 4, 5, 6 }; + EXPECT_THROW(mergeObj1.update(arr), std::exception); } TEST(Dynamic, ObjectErase) {