working on #235
This commit is contained in:
parent
fadf286653
commit
9ecf83f630
6 changed files with 210 additions and 2 deletions
26
doc/examples/push_back__initializer_list.cpp
Normal file
26
doc/examples/push_back__initializer_list.cpp
Normal 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});
|
||||||
|
}
|
1
doc/examples/push_back__initializer_list.link
Normal file
1
doc/examples/push_back__initializer_list.link
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<a target="_blank" href="http://melpon.org/wandbox/permlink/wZF4dRHjfCyjb3rx"><b>online</b></a>
|
4
doc/examples/push_back__initializer_list.output
Normal file
4
doc/examples/push_back__initializer_list.output
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
{"one":1,"two":2}
|
||||||
|
null
|
||||||
|
{"four":4,"one":1,"three":3,"two":2}
|
||||||
|
[["five",5]]
|
50
src/json.hpp
50
src/json.hpp
|
@ -4878,7 +4878,55 @@ class basic_json
|
||||||
reference operator+=(const typename object_t::value_type& val)
|
reference operator+=(const typename object_t::value_type& val)
|
||||||
{
|
{
|
||||||
push_back(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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
|
|
@ -4878,7 +4878,55 @@ class basic_json
|
||||||
reference operator+=(const typename object_t::value_type& val)
|
reference operator+=(const typename object_t::value_type& val)
|
||||||
{
|
{
|
||||||
push_back(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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
|
|
@ -7920,6 +7920,42 @@ TEST_CASE("modifiers")
|
||||||
"cannot use push_back() with number");
|
"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+=")
|
SECTION("operator+=")
|
||||||
|
@ -8016,6 +8052,42 @@ TEST_CASE("modifiers")
|
||||||
"cannot use push_back() with number");
|
"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")
|
SECTION("insert")
|
||||||
|
@ -13992,6 +14064,15 @@ TEST_CASE("regression tests")
|
||||||
|
|
||||||
CHECK(dest == expected);
|
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
|
// special test case to check if memory is leaked if constructor throws
|
||||||
|
|
Loading…
Reference in a new issue