Commit 1499c179 authored by Amol Bhave's avatar Amol Bhave Committed by Facebook Github Bot

Add heterogenous operations in dynamic::setDefault

Summary:
dynamic::setDefault already calls heterogenous `emplace(...)`, however it does not behave correctly for static constexpr strings.
Add a specialization for StringPiece which solves this.

The current set of tests does not invoke setDefault with an object as a key.
This diffs adds a test that does that.

Reviewed By: shixiao

Differential Revision: D10007262

fbshipit-source-id: 386a44bf6b0a24f81e843695d177d85b280b907d
parent 18fce17c
...@@ -671,24 +671,46 @@ inline dynamic&& dynamic::operator[](StringPiece k) && { ...@@ -671,24 +671,46 @@ inline dynamic&& dynamic::operator[](StringPiece k) && {
return std::move((*this)[k]); return std::move((*this)[k]);
} }
template <class K, class V> template <typename K, typename V>
inline dynamic& dynamic::setDefault(K&& k, V&& v) { dynamic::IfIsNonStringDynamicConvertible<K, dynamic&> dynamic::setDefault(
K&& k,
V&& v) {
auto& obj = get<ObjectImpl>(); auto& obj = get<ObjectImpl>();
return obj.emplace(std::forward<K>(k), std::forward<V>(v)).first->second; return obj.emplace(std::forward<K>(k), std::forward<V>(v)).first->second;
} }
template <class K> template <typename K>
inline dynamic& dynamic::setDefault(K&& k, dynamic&& v) { dynamic::IfIsNonStringDynamicConvertible<K, dynamic&> dynamic::setDefault(
K&& k,
dynamic&& v) {
auto& obj = get<ObjectImpl>(); auto& obj = get<ObjectImpl>();
return obj.emplace(std::forward<K>(k), std::move(v)).first->second; return obj.emplace(std::forward<K>(k), std::move(v)).first->second;
} }
template <class K> template <typename K>
inline dynamic& dynamic::setDefault(K&& k, const dynamic& v) { dynamic::IfIsNonStringDynamicConvertible<K, dynamic&> dynamic::setDefault(
K&& k,
const dynamic& v) {
auto& obj = get<ObjectImpl>(); auto& obj = get<ObjectImpl>();
return obj.emplace(std::forward<K>(k), v).first->second; return obj.emplace(std::forward<K>(k), v).first->second;
} }
template <typename V>
dynamic& dynamic::setDefault(StringPiece k, V&& v) {
auto& obj = get<ObjectImpl>();
return obj.emplace(k, std::forward<V>(v)).first->second;
}
inline dynamic& dynamic::setDefault(StringPiece k, dynamic&& v) {
auto& obj = get<ObjectImpl>();
return obj.emplace(k, std::move(v)).first->second;
}
inline dynamic& dynamic::setDefault(StringPiece k, const dynamic& v) {
auto& obj = get<ObjectImpl>();
return obj.emplace(k, v).first->second;
}
template <typename K> template <typename K>
dynamic::IfIsNonStringDynamicConvertible<K, dynamic const*> dynamic::get_ptr( dynamic::IfIsNonStringDynamicConvertible<K, dynamic const*> dynamic::get_ptr(
K&& k) const& { K&& k) const& {
......
...@@ -502,16 +502,25 @@ struct dynamic : private boost::operators<dynamic> { ...@@ -502,16 +502,25 @@ struct dynamic : private boost::operators<dynamic> {
dynamic getDefault(const dynamic& k, dynamic&& v) const&; dynamic getDefault(const dynamic& k, dynamic&& v) const&;
dynamic getDefault(const dynamic& k, const dynamic& v = dynamic::object) &&; dynamic getDefault(const dynamic& k, const dynamic& v = dynamic::object) &&;
dynamic getDefault(const dynamic& k, dynamic&& v) &&; dynamic getDefault(const dynamic& k, dynamic&& v) &&;
template <class K, class V>
dynamic& setDefault(K&& k, V&& v); template <typename K, typename V>
IfIsNonStringDynamicConvertible<K, dynamic&> setDefault(K&& k, V&& v);
template <typename V>
dynamic& setDefault(StringPiece k, V&& v);
// MSVC 2015 Update 3 needs these extra overloads because if V were a // MSVC 2015 Update 3 needs these extra overloads because if V were a
// defaulted template parameter, it causes MSVC to consider v an rvalue // defaulted template parameter, it causes MSVC to consider v an rvalue
// reference rather than a universal reference, resulting in it not being // reference rather than a universal reference, resulting in it not being
// able to find the correct overload to construct a dynamic with. // able to find the correct overload to construct a dynamic with.
template <class K> template <typename K>
dynamic& setDefault(K&& k, dynamic&& v); IfIsNonStringDynamicConvertible<K, dynamic&> setDefault(K&& k, dynamic&& v);
template <class K> template <typename K>
dynamic& setDefault(K&& k, const dynamic& v = dynamic::object); IfIsNonStringDynamicConvertible<K, dynamic&> setDefault(
K&& k,
const dynamic& v = dynamic::object);
dynamic& setDefault(StringPiece k, dynamic&& v);
dynamic& setDefault(StringPiece k, const dynamic& v = dynamic::object);
/* /*
* Resizes an array so it has at n elements, using the supplied * Resizes an array so it has at n elements, using the supplied
......
...@@ -504,6 +504,17 @@ TEST(Dynamic, GetSetDefaultTest) { ...@@ -504,6 +504,17 @@ TEST(Dynamic, GetSetDefaultTest) {
dynamic d4 = dynamic::array; dynamic d4 = dynamic::array;
EXPECT_ANY_THROW(d4.getDefault("foo", "bar")); EXPECT_ANY_THROW(d4.getDefault("foo", "bar"));
EXPECT_ANY_THROW(d4.setDefault("foo", "bar")); EXPECT_ANY_THROW(d4.setDefault("foo", "bar"));
// Using dynamic keys
dynamic k10{10}, k20{20}, kTrue{true};
dynamic d5 = dynamic::object(k10, "foo");
EXPECT_EQ(d5.setDefault(k10, "bar"), "foo");
EXPECT_EQ(d5.setDefault(k20, "bar"), "bar");
EXPECT_EQ(d5.setDefault(kTrue, "baz"), "baz");
EXPECT_EQ(d5.setDefault(StaticStrings::kA, "foo"), "foo");
EXPECT_EQ(d5.setDefault(StaticStrings::kB, "foo"), "foo");
EXPECT_EQ(d5.setDefault(StaticStrings::kFoo, "bar"), "bar");
EXPECT_EQ(d5.setDefault(StaticStrings::kBar, "foo"), "foo");
} }
TEST(Dynamic, ObjectForwarding) { TEST(Dynamic, ObjectForwarding) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment