Merge branch 'develop' into feature/issue239

This commit is contained in:
Niels 2016-05-11 17:23:01 +02:00
commit 91aa4c9def
6 changed files with 210 additions and 2 deletions

View file

@ -0,0 +1,26 @@
#include <json.hpp>
using json = nlohmann::json;
int main()
{
// create JSON values
json object = {{"one", 1}, {"two", 2}};
json null;
// print values
std::cout << object << '\n';
std::cout << null << '\n';
// add values:
object.push_back({"three", 3}); // object is extended
object += {"four", 4}; // object is extended
null.push_back({"five", 5}); // null is converted to array
// print values
std::cout << object << '\n';
std::cout << null << '\n';
// would throw:
//object.push_back({1, 2, 3});
}

View file

@ -0,0 +1 @@
<a target="_blank" href="http://melpon.org/wandbox/permlink/wZF4dRHjfCyjb3rx"><b>online</b></a>

View file

@ -0,0 +1,4 @@
{"one":1,"two":2}
null
{"four":4,"one":1,"three":3,"two":2}
[["five",5]]

View file

@ -4878,7 +4878,55 @@ class basic_json
reference operator+=(const typename object_t::value_type& val)
{
push_back(val);
return operator[](val.first);
return *this;
}
/*!
@brief add an object to an object
This function allows to use `push_back` with an initializer list. In case
1. the current value is an object,
2. the initializer list @a init contains only two elements, and
3. the first element of @a init is a string,
@a init is converted into an object element and added using
@ref push_back(const typename object_t::value_type&). Otherwise, @a init
is converted to a JSON value and added using @ref push_back(basic_json&&).
@param init an initializer list
@complexity Linear in the size of the initializer list @a init.
@note This function is required to resolve an ambiguous overload error,
because pairs like `{"key", "value"}` can be both interpreted as
`object_t::value_type` or `std::initializer_list<basic_json>`, see
https://github.com/nlohmann/json/issues/235 for more information.
@liveexample{The example shows how initializer lists are treated as
objects when possible.,push_back__initializer_list}
*/
void push_back(std::initializer_list<basic_json> init)
{
if (is_object() and init.size() == 2 and init.begin()->is_string())
{
const string_t key = *init.begin();
push_back(typename object_t::value_type(key, *(init.begin() + 1)));
}
else
{
push_back(basic_json(init));
}
}
/*!
@brief add an object to an object
@copydoc push_back(std::initializer_list<basic_json>)
*/
reference operator+=(std::initializer_list<basic_json> init)
{
push_back(init);
return *this;
}
/*!

View file

@ -4878,7 +4878,55 @@ class basic_json
reference operator+=(const typename object_t::value_type& val)
{
push_back(val);
return operator[](val.first);
return *this;
}
/*!
@brief add an object to an object
This function allows to use `push_back` with an initializer list. In case
1. the current value is an object,
2. the initializer list @a init contains only two elements, and
3. the first element of @a init is a string,
@a init is converted into an object element and added using
@ref push_back(const typename object_t::value_type&). Otherwise, @a init
is converted to a JSON value and added using @ref push_back(basic_json&&).
@param init an initializer list
@complexity Linear in the size of the initializer list @a init.
@note This function is required to resolve an ambiguous overload error,
because pairs like `{"key", "value"}` can be both interpreted as
`object_t::value_type` or `std::initializer_list<basic_json>`, see
https://github.com/nlohmann/json/issues/235 for more information.
@liveexample{The example shows how initializer lists are treated as
objects when possible.,push_back__initializer_list}
*/
void push_back(std::initializer_list<basic_json> init)
{
if (is_object() and init.size() == 2 and init.begin()->is_string())
{
const string_t key = *init.begin();
push_back(typename object_t::value_type(key, *(init.begin() + 1)));
}
else
{
push_back(basic_json(init));
}
}
/*!
@brief add an object to an object
@copydoc push_back(std::initializer_list<basic_json>)
*/
reference operator+=(std::initializer_list<basic_json> init)
{
push_back(init);
return *this;
}
/*!

View file

@ -7920,6 +7920,42 @@ TEST_CASE("modifiers")
"cannot use push_back() with number");
}
}
SECTION("with initializer_list")
{
SECTION("null")
{
json j;
j.push_back({"foo", "bar"});
CHECK(j == json::array({{"foo", "bar"}}));
json k;
k.push_back({1, 2, 3});
CHECK(k == json::array({{1, 2, 3}}));
}
SECTION("array")
{
json j = {1, 2, 3};
j.push_back({"foo", "bar"});
CHECK(j == json({1, 2, 3, {"foo", "bar"}}));
json k = {1, 2, 3};
k.push_back({1, 2, 3});
CHECK(k == json({1, 2, 3, {1, 2, 3}}));
}
SECTION("object")
{
json j = {{"key1", 1}};
j.push_back({"key2", "bar"});
CHECK(j == json({{"key1", 1}, {"key2", "bar"}}));
json k = {{"key1", 1}};
CHECK_THROWS_AS(k.push_back({1, 2, 3, 4}), std::domain_error);
CHECK_THROWS_WITH(k.push_back({1, 2, 3, 4}), "cannot use push_back() with object");
}
}
}
SECTION("operator+=")
@ -8016,6 +8052,42 @@ TEST_CASE("modifiers")
"cannot use push_back() with number");
}
}
SECTION("with initializer_list")
{
SECTION("null")
{
json j;
j += {"foo", "bar"};
CHECK(j == json::array({{"foo", "bar"}}));
json k;
k += {1, 2, 3};
CHECK(k == json::array({{1, 2, 3}}));
}
SECTION("array")
{
json j = {1, 2, 3};
j += {"foo", "bar"};
CHECK(j == json({1, 2, 3, {"foo", "bar"}}));
json k = {1, 2, 3};
k += {1, 2, 3};
CHECK(k == json({1, 2, 3, {1, 2, 3}}));
}
SECTION("object")
{
json j = {{"key1", 1}};
j += {"key2", "bar"};
CHECK(j == json({{"key1", 1}, {"key2", "bar"}}));
json k = {{"key1", 1}};
CHECK_THROWS_AS((k += {1, 2, 3, 4}), std::domain_error);
CHECK_THROWS_WITH((k += {1, 2, 3, 4}), "cannot use push_back() with object");
}
}
}
SECTION("insert")
@ -13992,6 +14064,15 @@ TEST_CASE("regression tests")
CHECK(dest == expected);
}
SECTION("issue ##235 - ambiguous overload for 'push_back' and 'operator+='")
{
json data = {{"key", "value"}};
data.push_back({"key2", "value2"});
data += {"key3", "value3"};
CHECK(data == json({{"key", "value"}, {"key2", "value2"}, {"key3", "value3"}}));
}
}
// special test case to check if memory is leaked if constructor throws