Merge branch 'feature/update' into develop

This commit is contained in:
Niels Lohmann 2017-08-16 07:39:30 +02:00
commit 4391bf5615
No known key found for this signature in database
GPG key ID: 7F3CEA63AE251B69
8 changed files with 216 additions and 1 deletions

17
doc/examples/update.cpp Normal file
View file

@ -0,0 +1,17 @@
#include <iostream>
#include "json.hpp"
using json = nlohmann::json;
int main()
{
// create two JSON objects
json o1 = R"( {"color": "red", "price": 17.99} )"_json;
json o2 = R"( {"color": "blue", "speed": 100} )"_json;
// add all keys from o2 to o1 (updating "color")
o1.update(o2);
// output updated object o1
std::cout << std::setw(2) << o1 << '\n';
}

1
doc/examples/update.link Normal file
View file

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

View file

@ -0,0 +1,5 @@
{
"color": "blue",
"price": 17.99,
"speed": 100
}

View file

@ -0,0 +1,17 @@
#include <iostream>
#include "json.hpp"
using json = nlohmann::json;
int main()
{
// create two JSON objects
json o1 = R"( {"color": "red", "price": 17.99} )"_json;
json o2 = R"( {"color": "blue", "speed": 100} )"_json;
// add all keys from o2 to o1 (updating "color")
o1.update(o2.begin(), o2.end());
// output updated object o1
std::cout << std::setw(2) << o1 << '\n';
}

View file

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

View file

@ -0,0 +1,5 @@
{
"color": "blue",
"price": 17.99,
"speed": 100
}

View file

@ -323,6 +323,7 @@ json.exception.type_error.308 | cannot use push_back() with string | The @ref pu
json.exception.type_error.309 | cannot use insert() with | The @ref insert() member functions can only be executed for certain JSON types.
json.exception.type_error.310 | cannot use swap() with number | The @ref swap() member functions can only be executed for certain JSON types.
json.exception.type_error.311 | cannot use emplace_back() with string | The @ref emplace_back() member function can only be executed for certain JSON types.
json.exception.type_error.312 | cannot use update() with string | The @ref update() member functions can only be executed for certain JSON types.
json.exception.type_error.313 | invalid value to unflatten | The @ref unflatten function converts an object whose keys are JSON Pointers back into an arbitrary nested JSON value. The JSON Pointers must not overlap, because then the resulting value would not be well defined.
json.exception.type_error.314 | only objects can be unflattened | The @ref unflatten function only works for an object whose keys are JSON Pointers.
json.exception.type_error.315 | values in object must be primitive | The @ref unflatten function only works for an object whose keys are JSON Pointers and whose values are primitive.
@ -11896,6 +11897,110 @@ class basic_json
m_value.object->insert(first.m_it.object_iterator, last.m_it.object_iterator);
}
/*!
@brief updates a JSON object from another object, overwriting existing keys
Inserts all values from JSON object @a j and overwrites existing keys.
@param[in] j JSON object to read values from
@throw type_error.312 if called on JSON values other than objects; example:
`"cannot use update() with string"`
@complexity O(N*log(size() + N)), where N is the number of elements to
insert.
@liveexample{The example shows how `update()` is used.,update}
@sa https://docs.python.org/3.6/library/stdtypes.html#dict.update
@since version 3.0.0
*/
void update(const_reference j)
{
// implicitly convert null value to an empty object
if (is_null())
{
m_type = value_t::object;
m_value.object = create<object_t>();
assert_invariant();
}
if (JSON_UNLIKELY(not is_object()))
{
JSON_THROW(type_error::create(312, "cannot use update() with " + std::string(type_name())));
}
if (JSON_UNLIKELY(not j.is_object()))
{
JSON_THROW(type_error::create(312, "cannot use update() with " + std::string(j.type_name())));
}
for (auto it = j.begin(); it != j.end(); ++it)
{
m_value.object->operator[](it.key()) = it.value();
}
}
/*!
@brief updates a JSON object from another object, overwriting existing keys
Inserts all values from from range `[first, last)` and overwrites existing
keys.
@param[in] first begin of the range of elements to insert
@param[in] last end of the range of elements to insert
@throw type_error.312 if called on JSON values other than objects; example:
`"cannot use update() with string"`
@throw invalid_iterator.202 if iterator @a first or @a last does does not
point to an object; example: `"iterators first and last must point to
objects"`
@throw invalid_iterator.210 if @a first and @a last do not belong to the
same JSON value; example: `"iterators do not fit"`
@complexity O(N*log(size() + N)), where N is the number of elements to
insert.
@liveexample{The example shows how `update()` is used__range.,update}
@sa https://docs.python.org/3.6/library/stdtypes.html#dict.update
@since version 3.0.0
*/
void update(const_iterator first, const_iterator last)
{
// implicitly convert null value to an empty object
if (is_null())
{
m_type = value_t::object;
m_value.object = create<object_t>();
assert_invariant();
}
if (JSON_UNLIKELY(not is_object()))
{
JSON_THROW(type_error::create(312, "cannot use update() with " + std::string(type_name())));
}
// check if range iterators belong to the same JSON object
if (JSON_UNLIKELY(first.m_object != last.m_object))
{
JSON_THROW(invalid_iterator::create(210, "iterators do not fit"));
}
// passed iterators must belong to objects
if (JSON_UNLIKELY(not first.m_object->is_object()
or not first.m_object->is_object()))
{
JSON_THROW(invalid_iterator::create(202, "iterators first and last must point to objects"));
}
for (auto it = first; it != last; ++it)
{
m_value.object->operator[](it.key()) = it.value();
}
}
/*!
@brief exchanges the values

View file

@ -489,7 +489,7 @@ TEST_CASE("modifiers")
}
}
SECTION("insert")
SECTION("insert()")
{
json j_array = {1, 2, 3, 4};
json j_value = 5;
@ -740,6 +740,70 @@ TEST_CASE("modifiers")
}
}
SECTION("update()")
{
json j_object1 = {{"one", "eins"}, {"two", "zwei"}};
json j_object2 = {{"three", "drei"}, {"two", "zwo"}};
json j_array = {1, 2, 3, 4};
SECTION("const reference")
{
SECTION("proper usage")
{
j_object1.update(j_object2);
CHECK(j_object1 == json({{"one", "eins"}, {"two", "zwo"}, {"three", "drei"}}));
json j_null;
j_null.update(j_object2);
CHECK(j_null == j_object2);
}
SECTION("wrong types")
{
CHECK_THROWS_AS(j_array.update(j_object1), json::type_error&);
CHECK_THROWS_WITH(j_array.update(j_object1), "[json.exception.type_error.312] cannot use update() with array");
CHECK_THROWS_AS(j_object1.update(j_array), json::type_error&);
CHECK_THROWS_WITH(j_object1.update(j_array), "[json.exception.type_error.312] cannot use update() with array");
}
}
SECTION("iterator range")
{
SECTION("proper usage")
{
j_object1.update(j_object2.begin(), j_object2.end());
CHECK(j_object1 == json({{"one", "eins"}, {"two", "zwo"}, {"three", "drei"}}));
json j_null;
j_null.update(j_object2.begin(), j_object2.end());
CHECK(j_null == j_object2);
}
SECTION("empty range")
{
j_object1.update(j_object2.begin(), j_object2.begin());
CHECK(j_object1 == json({{"one", "eins"}, {"two", "zwei"}}));
}
SECTION("invalid iterators")
{
json j_other_array2 = {"first", "second"};
CHECK_THROWS_AS(j_array.update(j_object2.begin(), j_object2.end()), json::type_error&);
CHECK_THROWS_AS(j_object1.update(j_object1.begin(), j_object2.end()), json::invalid_iterator&);
CHECK_THROWS_AS(j_object1.update(j_array.begin(), j_array.end()), json::invalid_iterator&);
CHECK_THROWS_WITH(j_array.update(j_object2.begin(), j_object2.end()),
"[json.exception.type_error.312] cannot use update() with array");
CHECK_THROWS_WITH(j_object1.update(j_object1.begin(), j_object2.end()),
"[json.exception.invalid_iterator.210] iterators do not fit");
CHECK_THROWS_WITH(j_object1.update(j_array.begin(), j_array.end()),
"[json.exception.invalid_iterator.202] iterators first and last must point to objects");
}
}
}
SECTION("swap()")
{
SECTION("json")