Commit 07dc3ce5 authored by Giuseppe Ottaviano's avatar Giuseppe Ottaviano Committed by Facebook Github Bot 6

Deprecate dynamic::dynamic(std::initializer_list<dynamic>)

Summary:After DR95 the single braces dispatch to the copy constructor
(http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1467),
so it is not possible anymore to initialize a singleton dynamic array
using the braces syntax. The initializer list constructor already had
a special case for empty lists, which unconditionally called the
default constructor if defined.

This diff deprecates the braces syntax and defines the following alternative:
```
dynamic empty = dynamic::array;
dynamic a = dynamic::array(1, 2, "foo");
```

Reviewed By: luciang, yfeldblum

Differential Revision: D3013423

fb-gh-sync-id: a0cf09dfd96e9806044f7c3bf3592c637a9bc932
shipit-source-id: a0cf09dfd96e9806044f7c3bf3592c637a9bc932
parent b873a628
......@@ -30,7 +30,9 @@ namespace folly {
*
* Example:
*
* dynamic d = { { 1, 2, 3 }, { 4, 5 } }; // a vector of vector of int
* dynamic d = dynamic::array(
* dynamic::array(1, 2, 3),
* dynamic::array(4, 5)); // a vector of vector of int
* auto vvi = convertTo<fbvector<fbvector<int>>>(d);
*
* See docs/DynamicConverter.md for supported types and customization
......@@ -319,7 +321,7 @@ struct DynamicConstructor<C,
!std::is_constructible<StringPiece, const C&>::value &&
dynamicconverter_detail::is_range<C>::value>::type> {
static dynamic construct(const C& x) {
dynamic d = {};
dynamic d = dynamic::array;
for (auto& item : x) {
d.push_back(toDynamic(item));
}
......@@ -331,7 +333,7 @@ struct DynamicConstructor<C,
template<typename A, typename B>
struct DynamicConstructor<std::pair<A, B>, void> {
static dynamic construct(const std::pair<A, B>& x) {
dynamic d = {};
dynamic d = dynamic::array;
d.push_back(toDynamic(x.first));
d.push_back(toDynamic(x.second));
return d;
......
......@@ -26,9 +26,9 @@ folly::dynamic;` was used):
dynamic boolean = false;
// Arrays can be initialized with brackets.
dynamic array = { "array ", "of ", 4, " elements" };
dynamic array = dynamic::array("array ", "of ", 4, " elements");
assert(array.size() == 4);
dynamic emptyArray = {};
dynamic emptyArray = dynamic::array;
assert(emptyArray.empty());
// Maps from dynamics to dynamics are called objects. The
......@@ -81,7 +81,7 @@ For more complicated conversions, see [DynamicConverter](DynamicConverter.md).
You can iterate over dynamic arrays as you would over any C++ sequence container.
``` Cpp
dynamic array = {2, 3, "foo"};
dynamic array = dynamic::array(2, 3, "foo");
for (auto& val : array) {
doSomethingWith(val);
......@@ -145,7 +145,7 @@ here's what it looks like:
// Building the same document programatically.
dynamic sonOfAJ = dynamic::object
("key", 12)
("key2", { false, nullptr, true, "yay" });
("key2", dynamic::array(false, nullptr, true, "yay"));
// Printing. (See also folly::toPrettyJson)
auto str = folly::toJson(sonOfAJ);
......
......@@ -189,9 +189,20 @@ private:
dynamic val_;
};
inline void dynamic::array(EmptyArrayTag) {}
template <class... Args>
inline dynamic dynamic::array(Args&& ...args) {
return dynamic(std::initializer_list<dynamic>{std::forward<Args>(args)...},
PrivateTag());
}
// This looks like a case for perfect forwarding, but our use of
// std::initializer_list for constructing dynamic arrays makes it less
// functional than doing this manually.
// TODO(ott, 10300209): When the initializer_list constructor is gone,
// simplify this.
inline dynamic::ObjectMaker dynamic::object() { return ObjectMaker(); }
inline dynamic::ObjectMaker dynamic::object(dynamic&& a, dynamic&& b) {
return ObjectMaker(std::move(a), std::move(b));
......@@ -246,6 +257,12 @@ struct dynamic::const_value_iterator
//////////////////////////////////////////////////////////////////////
inline dynamic::dynamic(void (*)(EmptyArrayTag))
: type_(ARRAY)
{
new (&u_.array) Array();
}
inline dynamic::dynamic(ObjectMaker (*)())
: type_(OBJECT)
{
......@@ -282,17 +299,21 @@ inline dynamic::dynamic(fbstring&& s)
new (&u_.string) fbstring(std::move(s));
}
inline dynamic& dynamic::operator=(std::initializer_list<dynamic> il) {
(*this) = dynamic(il);
return *this;
inline dynamic::dynamic(std::initializer_list<dynamic> il)
: dynamic(std::move(il), PrivateTag()) {
}
inline dynamic::dynamic(std::initializer_list<dynamic> il)
inline dynamic::dynamic(std::initializer_list<dynamic> il, PrivateTag)
: type_(ARRAY)
{
new (&u_.array) Array(il.begin(), il.end());
}
inline dynamic& dynamic::operator=(std::initializer_list<dynamic> il) {
(*this) = dynamic(il, PrivateTag());
return *this;
}
inline dynamic::dynamic(ObjectMaker&& maker)
: type_(OBJECT)
{
......@@ -596,23 +617,23 @@ inline dynamic::const_item_iterator dynamic::erase(const_item_iterator first,
}
inline void dynamic::resize(std::size_t sz, dynamic const& c) {
auto& array = get<Array>();
array.resize(sz, c);
auto& arr = get<Array>();
arr.resize(sz, c);
}
inline void dynamic::push_back(dynamic const& v) {
auto& array = get<Array>();
array.push_back(v);
auto& arr = get<Array>();
arr.push_back(v);
}
inline void dynamic::push_back(dynamic&& v) {
auto& array = get<Array>();
array.push_back(std::move(v));
auto& arr = get<Array>();
arr.push_back(std::move(v));
}
inline void dynamic::pop_back() {
auto& array = get<Array>();
array.pop_back();
auto& arr = get<Array>();
arr.pop_back();
}
//////////////////////////////////////////////////////////////////////
......
......@@ -31,7 +31,7 @@
* dynamic str = "string";
* dynamic map = dynamic::object;
* map[str] = twelve;
* map[str + "another_str"] = { "array", "of", 4, "elements" };
* map[str + "another_str"] = dynamic::array("array", "of", 4, "elements");
* map.insert("null_element", nullptr);
* ++map[str];
* assert(map[str] == 13);
......@@ -39,7 +39,7 @@
* // Building a complex object with a sub array inline:
* dynamic d = dynamic::object
* ("key", "value")
* ("key2", { "a", "array" })
* ("key2", dynamic::array("a", "array"))
* ;
*
* Also see folly/json.h for the serialization and deserialization
......@@ -118,24 +118,34 @@ public:
struct const_item_iterator;
/*
* Creation routines for making dynamic objects. Objects are maps
* from key to value (so named due to json-related origins here).
* Creation routines for making dynamic objects and arrays. Objects
* are maps from key to value (so named due to json-related origins
* here).
*
* Example:
*
* // Make a fairly complex dynamic:
* dynamic d = dynamic::object("key", "value1")
* ("key2", { "value", "with", 4, "words" });
* ("key2", dynamic::array("value",
* "with",
* 4,
* "words"));
*
* // Build an object in a few steps:
* dynamic d = dynamic::object;
* d["key"] = 12;
* d["something_else"] = { 1, 2, 3, nullptr };
* d["something_else"] = dynamic::array(1, 2, 3, nullptr);
*/
private:
struct PrivateTag {};
struct EmptyArrayTag {};
struct ObjectMaker;
public:
static void array(EmptyArrayTag);
template <class... Args>
static dynamic array(Args&& ...args);
static ObjectMaker object();
static ObjectMaker object(dynamic&&, dynamic&&);
static ObjectMaker object(dynamic const&, dynamic&&);
......@@ -152,9 +162,10 @@ public:
/* implicit */ dynamic(fbstring&& val);
/*
* This is part of the plumbing for object(), above. Used to create
* a new object dynamic.
* This is part of the plumbing for array() and object(), above.
* Used to create a new array or object dynamic.
*/
/* implicit */ dynamic(void (*)(EmptyArrayTag));
/* implicit */ dynamic(ObjectMaker (*)());
/* implicit */ dynamic(ObjectMaker const&) = delete;
/* implicit */ dynamic(ObjectMaker&&);
......@@ -166,7 +177,14 @@ public:
*
* dynamic v = { 1, 2, 3, "foo" };
*/
// TODO(ott, 10300209): Remove once all uses have been eradicated.
FOLLY_DEPRECATED(
"Initializer list syntax is deprecated (#10300209). Use dynamic::array.")
/* implicit */ dynamic(std::initializer_list<dynamic> il);
dynamic(std::initializer_list<dynamic> il, PrivateTag);
FOLLY_DEPRECATED(
"Initializer list syntax is deprecated (#10300209). Use dynamic::array.")
dynamic& operator=(std::initializer_list<dynamic> il);
/*
......
......@@ -445,7 +445,7 @@ dynamic parseArray(Input& in) {
assert(*in == '[');
++in;
dynamic ret = {};
dynamic ret = dynamic::array;
in.skipWhitespace();
if (*in == ']') {
......
......@@ -130,7 +130,7 @@ TEST(DynamicConverter, simple_builtins) {
auto i2 = convertTo<std::string>(d2);
EXPECT_EQ(i2, "13");
dynamic d3 = { 12, "Scala" };
dynamic d3 = dynamic::array(12, "Scala");
auto i3 = convertTo<std::pair<int, std::string>>(d3);
EXPECT_EQ(i3.first, 12);
EXPECT_EQ(i3.second, "Scala");
......@@ -142,19 +142,19 @@ TEST(DynamicConverter, simple_builtins) {
}
TEST(DynamicConverter, simple_fbvector) {
dynamic d1 = { 1, 2, 3 };
dynamic d1 = dynamic::array(1, 2, 3);
auto i1 = convertTo<folly::fbvector<int>>(d1);
decltype(i1) i1b = { 1, 2, 3 };
EXPECT_EQ(i1, i1b);
}
TEST(DynamicConverter, simple_container) {
dynamic d1 = { 1, 2, 3 };
dynamic d1 = dynamic::array(1, 2, 3);
auto i1 = convertTo<std::vector<int>>(d1);
decltype(i1) i1b = { 1, 2, 3 };
EXPECT_EQ(i1, i1b);
dynamic d2 = { 1, 3, 5, 2, 4 };
dynamic d2 = dynamic::array(1, 3, 5, 2, 4);
auto i2 = convertTo<std::set<int>>(d2);
decltype(i2) i2b = { 1, 2, 3, 5, 4 };
EXPECT_EQ(i2, i2b);
......@@ -166,7 +166,8 @@ TEST(DynamicConverter, simple_map) {
decltype(i1) i1b = { { 1, "one" }, { 2, "two" } };
EXPECT_EQ(i1, i1b);
dynamic d2 = { { 3, "three" }, { 4, "four" } };
dynamic d2 = dynamic::array(dynamic::array(3, "three"),
dynamic::array(4, "four"));
auto i2 = convertTo<std::unordered_map<int, std::string>>(d2);
decltype(i2) i2b = { { 3, "three" }, { 4, "four" } };
EXPECT_EQ(i2, i2b);
......@@ -178,7 +179,8 @@ TEST(DynamicConverter, map_keyed_by_string) {
decltype(i1) i1b = { { "1", "one" }, { "2", "two" } };
EXPECT_EQ(i1, i1b);
dynamic d2 = { { "3", "three" }, { "4", "four" } };
dynamic d2 = dynamic::array(dynamic::array("3", "three"),
dynamic::array("4", "four"));
auto i2 = convertTo<std::unordered_map<std::string, std::string>>(d2);
decltype(i2) i2b = { { "3", "three" }, { "4", "four" } };
EXPECT_EQ(i2, i2b);
......@@ -193,13 +195,15 @@ TEST(DynamicConverter, map_to_vector_of_pairs) {
}
TEST(DynamicConverter, nested_containers) {
dynamic d1 = { { 1 }, { }, { 2, 3 } };
dynamic d1 = dynamic::array(dynamic::array(1),
dynamic::array(),
dynamic::array(2, 3));
auto i1 = convertTo<folly::fbvector<std::vector<uint8_t>>>(d1);
decltype(i1) i1b = { { 1 }, { }, { 2, 3 } };
EXPECT_EQ(i1, i1b);
dynamic h2a = { "3", ".", "1", "4" };
dynamic h2b = { "2", ".", "7", "2" };
dynamic h2a = dynamic::array("3", ".", "1", "4");
dynamic h2b = dynamic::array("2", ".", "7", "2");
dynamic d2 = dynamic::object(3.14, h2a)(2.72, h2b);
auto i2 = convertTo<std::map<double, std::vector<folly::fbstring>>>(d2);
decltype(i2) i2b =
......@@ -224,7 +228,8 @@ TEST(DynamicConverter, custom_class) {
auto i1 = convertTo<A>(d1);
EXPECT_EQ(i1.i, 17);
dynamic d2 = { dynamic::object("i", 18), dynamic::object("i", 19) };
dynamic d2 = dynamic::array(dynamic::object("i", 18),
dynamic::object("i", 19));
auto i2 = convertTo<std::vector<A>>(d2);
decltype(i2) i2b = { { 18 }, { 19 } };
EXPECT_EQ(i2, i2b);
......@@ -255,21 +260,21 @@ TEST(DynamicConverter, crazy) {
dynamic
ds1 = { "a", "e", "i", "o", "u" },
ds2 = { "2", "3", "5", "7" },
ds3 = { "Hello", "World" };
ds1 = dynamic::array("a", "e", "i", "o", "u"),
ds2 = dynamic::array("2", "3", "5", "7"),
ds3 = dynamic::array("Hello", "World");
dynamic
dv1 = {},
dv2 = { ds1, ds2 },
dv3({ ds3 });
dv1 = dynamic::array,
dv2 = dynamic::array(ds1, ds2),
dv3(dynamic::array(ds3));
dynamic
dm1 = dynamic::object(true, dv1)(false, dv2),
dm2 = { { true, dv3 } };
dm2 = dynamic::array(dynamic::array(true, dv3));
dynamic
df1 = { dm1, dm2 };
df1 = dynamic::array(dm1, dm2);
auto i = convertTo<std::vector<std::unordered_map<bool, std::vector<
......@@ -296,7 +301,7 @@ TEST(DynamicConverter, consts) {
auto i4 = convertTo<const bool>(d4);
EXPECT_EQ(true, i4);
dynamic d5 = { 1, 2 };
dynamic d5 = dynamic::array(1, 2);
auto i5 = convertTo<const std::pair<const int, const int>>(d5);
decltype(i5) i5b = { 1, 2 };
EXPECT_EQ(i5b, i5);
......@@ -334,7 +339,7 @@ TEST(DynamicConverter, construct) {
using std::string;
{
vector<int> c { 1, 2, 3 };
dynamic d = { 1, 2, 3 };
dynamic d = dynamic::array(1, 2, 3);
EXPECT_EQ(d, toDynamic(c));
}
......@@ -352,13 +357,13 @@ TEST(DynamicConverter, construct) {
{
map<string, pair<string, int>> c { { "a", { "b", 3 } } };
dynamic d = dynamic::object("a", dynamic { "b", 3 });
dynamic d = dynamic::object("a", dynamic::array("b", 3));
EXPECT_EQ(d, toDynamic(c));
}
{
map<string, pair<string, int>> c { { "a", { "b", 3 } } };
dynamic d = dynamic::object("a", dynamic { "b", 3 });
dynamic d = dynamic::object("a", dynamic::array("b", 3));
EXPECT_EQ(d, toDynamic(c));
}
......@@ -366,7 +371,8 @@ TEST(DynamicConverter, construct) {
vector<int> vi { 2, 3, 4, 5 };
auto c = std::make_pair(range(vi.begin(), vi.begin() + 3),
range(vi.begin() + 1, vi.begin() + 4));
dynamic d = { { 2, 3, 4 }, { 3, 4, 5 } };
dynamic d = dynamic::array(dynamic::array(2, 3, 4),
dynamic::array(3, 4, 5));
EXPECT_EQ(d, toDynamic(c));
}
}
......
......@@ -30,7 +30,7 @@ using folly::TypeError;
TEST(Dynamic, ArrayGenerator) {
// Make sure arrays can be used with folly::gen.
using namespace folly::gen;
dynamic arr { 1, 2, 3, 4 };
dynamic arr = dynamic::array(1, 2, 3, 4);
EXPECT_EQ(from(arr) | take(3) | member(&dynamic::asInt) | sum, 6);
}
......@@ -102,7 +102,7 @@ TEST(Dynamic, FormattedIO) {
EXPECT_EQ(out.str(), "0xd 1e+02\n");
out.str("");
dynamic arrr = { 1, 2, 3 };
dynamic arrr = dynamic::array(1, 2, 3);
out << arrr;
EXPECT_EQ(out.str(), "[1,2,3]");
......@@ -112,8 +112,9 @@ TEST(Dynamic, FormattedIO) {
EXPECT_EQ(out.str(), R"({"a":12})");
out.str("");
dynamic objy2 = { objy, dynamic::object(12, "str"),
dynamic::object(true, false) };
dynamic objy2 = dynamic::array(objy,
dynamic::object(12, "str"),
dynamic::object(true, false));
out << objy2;
EXPECT_EQ(out.str(), R"([{"a":12},{12:"str"},{true:false}])");
}
......
......@@ -76,7 +76,7 @@ TEST(Dynamic, ObjectBasics) {
EXPECT_TRUE(d3 == nullptr);
d3 = dynamic::object;
EXPECT_TRUE(d3.isObject());
d3["foo"] = { 1, 2, 3 };
d3["foo"] = dynamic::array(1, 2, 3);
EXPECT_EQ(d3.count("foo"), 1);
d3[123] = 321;
......@@ -125,7 +125,7 @@ TEST(Dynamic, ObjectBasics) {
mergeObj1.update(mergeObj2);
EXPECT_EQ(mergeObj1, combinedPreferObj2);
dynamic arr = { 1, 2, 3, 4, 5, 6 };
dynamic arr = dynamic::array(1, 2, 3, 4, 5, 6);
EXPECT_THROW(mergeObj1.update(arr), std::exception);
mergeObj1 = origMergeObj1; // reset it
......@@ -161,7 +161,7 @@ TEST(Dynamic, ObjectErase) {
}
TEST(Dynamic, ArrayErase) {
dynamic arr = { 1, 2, 3, 4, 5, 6 };
dynamic arr = dynamic::array(1, 2, 3, 4, 5, 6);
EXPECT_THROW(arr.erase(1), std::exception);
EXPECT_EQ(arr.size(), 6);
......@@ -184,7 +184,7 @@ TEST(Dynamic, StringBasics) {
}
TEST(Dynamic, ArrayBasics) {
dynamic array = { 1, 2, 3 };
dynamic array = dynamic::array(1, 2, 3);
EXPECT_EQ(array.size(), 3);
EXPECT_EQ(array.at(0), 1);
EXPECT_EQ(array.at(1), 2);
......@@ -202,7 +202,7 @@ TEST(Dynamic, ArrayBasics) {
}
TEST(Dynamic, DeepCopy) {
dynamic val = { "foo", "bar", { "foo1", "bar1" } };
dynamic val = dynamic::array("foo", "bar", dynamic::array("foo1", "bar1"));
EXPECT_EQ(val.at(2).at(0), "foo1");
EXPECT_EQ(val.at(2).at(1), "bar1");
dynamic val2 = val;
......@@ -217,26 +217,23 @@ TEST(Dynamic, DeepCopy) {
EXPECT_EQ(val2.at(2).at(0), "foo3");
EXPECT_EQ(val2.at(2).at(1), "bar3");
dynamic obj = dynamic::object("a", "b")
("c", {"d", "e", "f"})
;
dynamic obj =
dynamic::object("a", "b")
("c", dynamic::array("d", "e", "f"));
EXPECT_EQ(obj.at("a"), "b");
dynamic obj2 = obj;
obj2.at("a") = {1, 2, 3};
obj2.at("a") = dynamic::array(1, 2, 3);
EXPECT_EQ(obj.at("a"), "b");
dynamic expected = {1, 2, 3};
dynamic expected = dynamic::array(1, 2, 3);
EXPECT_EQ(obj2.at("a"), expected);
}
TEST(Dynamic, ArrayReassignment) {
dynamic o = 1;
// After DR95 the single braces dispatch to the copy constructor.
// http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1467
dynamic d1 = {{o}};
dynamic d1 = dynamic::array(o);
EXPECT_EQ(dynamic::ARRAY, d1.type());
d1 = {o};
d1 = dynamic::array(o);
EXPECT_EQ(dynamic::ARRAY, d1.type());
}
......@@ -292,7 +289,7 @@ TEST(Dynamic, GetSetDefaultTest) {
dynamic d2 = dynamic::object("foo", "bar");
EXPECT_EQ(d2.setDefault("foo", "quux"), "bar");
d2.setDefault("bar", dynamic({})).push_back(42);
d2.setDefault("bar", dynamic::array).push_back(42);
EXPECT_EQ(d2["bar"][0], 42);
dynamic d3 = dynamic::object, empty = dynamic::object;
......@@ -301,7 +298,7 @@ TEST(Dynamic, GetSetDefaultTest) {
EXPECT_EQ(d3["foo"]["bar"], "baz");
// we do not allow getDefault/setDefault on arrays
dynamic d4 = dynamic({});
dynamic d4 = dynamic::array;
EXPECT_ANY_THROW(d4.getDefault("foo", "bar"));
EXPECT_ANY_THROW(d4.setDefault("foo", "bar"));
}
......@@ -309,13 +306,13 @@ TEST(Dynamic, GetSetDefaultTest) {
TEST(Dynamic, ObjectForwarding) {
// Make sure dynamic::object can be constructed the same way as any
// dynamic.
dynamic d = dynamic::object("asd", {"foo", "bar"});
dynamic d2 = dynamic::object("key2", {"value", "words"})
dynamic d = dynamic::object("asd", dynamic::array("foo", "bar"));
dynamic d2 = dynamic::object("key2", dynamic::array("value", "words"))
("key", "value1");
}
TEST(Dynamic, GetPtr) {
dynamic array = { 1, 2, "three" };
dynamic array = dynamic::array(1, 2, "three");
EXPECT_TRUE(array.get_ptr(0));
EXPECT_FALSE(array.get_ptr(-1));
EXPECT_FALSE(array.get_ptr(3));
......@@ -334,13 +331,13 @@ TEST(Dynamic, GetPtr) {
}
TEST(Dynamic, Assignment) {
const dynamic ds[] = { { 1, 2, 3 },
const dynamic ds[] = { dynamic::array(1, 2, 3),
dynamic::object("a", true),
24,
26.5,
true,
"hello", };
const dynamic dd[] = { { 5, 6 },
const dynamic dd[] = { dynamic::array(5, 6),
dynamic::object("t", "T")(1, 7),
9000,
3.14159,
......
......@@ -101,14 +101,14 @@ TEST(Json, Parse) {
("junk", 12)
("another", 32.2)
("a",
{
dynamic::array(
dynamic::object("a", "b")
("c", "d"),
12.5,
"Yo Dawg",
{ "heh" },
dynamic::array("heh"),
nullptr
}
)
)
;
......@@ -131,7 +131,7 @@ TEST(Json, ParseTrailingComma) {
on.allow_trailing_comma = true;
off.allow_trailing_comma = false;
dynamic arr { 1, 2 };
dynamic arr = dynamic::array(1, 2);
EXPECT_EQ(arr, parseJson("[1, 2]", on));
EXPECT_EQ(arr, parseJson("[1, 2,]", on));
EXPECT_EQ(arr, parseJson("[1, 2, ]", on));
......@@ -442,14 +442,14 @@ TEST(Json, SortKeys) {
("junk", 12)
("another", 32.2)
("a",
{
dynamic::array(
dynamic::object("a", "b")
("c", "d"),
12.5,
"Yo Dawg",
{ "heh" },
dynamic::array("heh"),
nullptr
}
)
)
;
......@@ -480,14 +480,14 @@ TEST(Json, PrintTo) {
(0, 1)
(1, 2)
("a",
{
dynamic::array(
dynamic::object("a", "b")
("c", "d"),
12.5,
"Yo Dawg",
{ "heh" },
dynamic::array("heh"),
nullptr
}
)
)
;
......
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