Merge branch 'feature/emplace' into develop
This commit is contained in:
commit
8f563a5f81
10 changed files with 364 additions and 1 deletions
30
doc/examples/emplace.cpp
Normal file
30
doc/examples/emplace.cpp
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
#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
|
||||||
|
auto res1 = object.emplace("three", 3);
|
||||||
|
null.emplace("A", "a");
|
||||||
|
null.emplace("B", "b");
|
||||||
|
|
||||||
|
// the following call will not add an object, because there is already
|
||||||
|
// a value stored at key "B"
|
||||||
|
auto res2 = null.emplace("B", "c");
|
||||||
|
|
||||||
|
// print values
|
||||||
|
std::cout << object << '\n';
|
||||||
|
std::cout << *res1.first << " " << std::boolalpha << res1.second << '\n';
|
||||||
|
|
||||||
|
std::cout << null << '\n';
|
||||||
|
std::cout << *res2.first << " " << std::boolalpha << res2.second << '\n';
|
||||||
|
}
|
1
doc/examples/emplace.link
Normal file
1
doc/examples/emplace.link
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<a target="_blank" href="http://melpon.org/wandbox/permlink/B6ILaoysGMliouEO"><b>online</b></a>
|
6
doc/examples/emplace.output
Normal file
6
doc/examples/emplace.output
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
{"one":1,"two":2}
|
||||||
|
null
|
||||||
|
{"one":1,"three":3,"two":2}
|
||||||
|
3 true
|
||||||
|
{"A":"a","B":"b"}
|
||||||
|
"b" false
|
23
doc/examples/emplace_back.cpp
Normal file
23
doc/examples/emplace_back.cpp
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
#include <json.hpp>
|
||||||
|
|
||||||
|
using json = nlohmann::json;
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
// create JSON values
|
||||||
|
json array = {1, 2, 3, 4, 5};
|
||||||
|
json null;
|
||||||
|
|
||||||
|
// print values
|
||||||
|
std::cout << array << '\n';
|
||||||
|
std::cout << null << '\n';
|
||||||
|
|
||||||
|
// add values
|
||||||
|
array.emplace_back(6);
|
||||||
|
null.emplace_back("first");
|
||||||
|
null.emplace_back(3, "second");
|
||||||
|
|
||||||
|
// print values
|
||||||
|
std::cout << array << '\n';
|
||||||
|
std::cout << null << '\n';
|
||||||
|
}
|
1
doc/examples/emplace_back.link
Normal file
1
doc/examples/emplace_back.link
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<a target="_blank" href="http://melpon.org/wandbox/permlink/jdch45YEMX94DvlH"><b>online</b></a>
|
4
doc/examples/emplace_back.output
Normal file
4
doc/examples/emplace_back.output
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
[1,2,3,4,5]
|
||||||
|
null
|
||||||
|
[1,2,3,4,5,6]
|
||||||
|
["first",["second","second","second"]]
|
11
doc/index.md
11
doc/index.md
|
@ -197,7 +197,7 @@ The container functions known from STL have been extended to support the differe
|
||||||
<td class="ok_green">@link nlohmann::basic_json::max_size `max_size` @endlink (returns `0`)</td>
|
<td class="ok_green">@link nlohmann::basic_json::max_size `max_size` @endlink (returns `0`)</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td rowspan="5">modifiers</td>
|
<td rowspan="6">modifiers</td>
|
||||||
<td>`clear`</td>
|
<td>`clear`</td>
|
||||||
<td class="ok_green">@link nlohmann::basic_json::clear `clear` @endlink</td>
|
<td class="ok_green">@link nlohmann::basic_json::clear `clear` @endlink</td>
|
||||||
<td class="ok_green">@link nlohmann::basic_json::clear `clear` @endlink</td>
|
<td class="ok_green">@link nlohmann::basic_json::clear `clear` @endlink</td>
|
||||||
|
@ -233,6 +233,15 @@ The container functions known from STL have been extended to support the differe
|
||||||
<td class="nok_throws">throws `std::domain_error`</td>
|
<td class="nok_throws">throws `std::domain_error`</td>
|
||||||
<td class="ok_green">@link nlohmann::basic_json::push_back(const typename object_t::value_type & val) `push_back` @endlink (creates object)<br>@link nlohmann::basic_json::push_back(const nlohmann::basic_json &) `push_back` @endlink (creates array)</td>
|
<td class="ok_green">@link nlohmann::basic_json::push_back(const typename object_t::value_type & val) `push_back` @endlink (creates object)<br>@link nlohmann::basic_json::push_back(const nlohmann::basic_json &) `push_back` @endlink (creates array)</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>`emplace` / `emplace_back`</td>
|
||||||
|
<td class="ok_green">@link nlohmann::basic_json::emplace() `emplace` @endlink</td>
|
||||||
|
<td class="ok_green">@link nlohmann::basic_json::emplace_back() `emplace_back` @endlink</td>
|
||||||
|
<td class="nok_throws">throws `std::domain_error`</td>
|
||||||
|
<td class="nok_throws">throws `std::domain_error`</td>
|
||||||
|
<td class="nok_throws">throws `std::domain_error`</td>
|
||||||
|
<td class="ok_green">@link nlohmann::basic_json::emplace() `emplace` @endlink (creates object)<br>@link nlohmann::basic_json::emplace_back() `emplace_back` @endlink (creates array)</td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>`swap`</td>
|
<td>`swap`</td>
|
||||||
<td class="ok_green">@link nlohmann::basic_json::swap `swap` @endlink</td>
|
<td class="ok_green">@link nlohmann::basic_json::swap `swap` @endlink</td>
|
||||||
|
|
96
src/json.hpp
96
src/json.hpp
|
@ -5032,6 +5032,102 @@ class basic_json
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief add an object to an array
|
||||||
|
|
||||||
|
Creates a JSON value from the passed parameters @a args to the end of the
|
||||||
|
JSON value. If the function is called on a JSON null value, an empty array
|
||||||
|
is created before appending the value created from @a args.
|
||||||
|
|
||||||
|
@param[in] args arguments to forward to a constructor of @ref basic_json
|
||||||
|
@tparam Args compatible types to create a @ref basic_json object
|
||||||
|
|
||||||
|
@throw std::domain_error when called on a type other than JSON array or
|
||||||
|
null; example: `"cannot use emplace_back() with number"`
|
||||||
|
|
||||||
|
@complexity Amortized constant.
|
||||||
|
|
||||||
|
@liveexample{The example shows how `push_back()` can be used to add
|
||||||
|
elements to a JSON array. Note how the `null` value was silently converted
|
||||||
|
to a JSON array.,emplace_back}
|
||||||
|
|
||||||
|
@since version 2.0.8
|
||||||
|
*/
|
||||||
|
template<class... Args>
|
||||||
|
void emplace_back(Args&& ... args)
|
||||||
|
{
|
||||||
|
// emplace_back only works for null objects or arrays
|
||||||
|
if (not(is_null() or is_array()))
|
||||||
|
{
|
||||||
|
throw std::domain_error("cannot use emplace_back() with " + type_name());
|
||||||
|
}
|
||||||
|
|
||||||
|
// transform null object into an array
|
||||||
|
if (is_null())
|
||||||
|
{
|
||||||
|
m_type = value_t::array;
|
||||||
|
m_value = value_t::array;
|
||||||
|
assert_invariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
// add element to array (perfect forwarding)
|
||||||
|
m_value.array->emplace_back(std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief add an object to an object if key does not exist
|
||||||
|
|
||||||
|
Inserts a new element into a JSON object constructed in-place with the given
|
||||||
|
@a args if there is no element with the key in the container. If the
|
||||||
|
function is called on a JSON null value, an empty object is created before
|
||||||
|
appending the value created from @a args.
|
||||||
|
|
||||||
|
@param[in] args arguments to forward to a constructor of @ref basic_json
|
||||||
|
@tparam Args compatible types to create a @ref basic_json object
|
||||||
|
|
||||||
|
@return a pair consisting of an iterator to the inserted element, or the
|
||||||
|
already-existing element if no insertion happened, and a bool
|
||||||
|
denoting whether the insertion took place.
|
||||||
|
|
||||||
|
@throw std::domain_error when called on a type other than JSON object or
|
||||||
|
null; example: `"cannot use emplace() with number"`
|
||||||
|
|
||||||
|
@complexity Logarithmic in the size of the container, O(log(`size()`)).
|
||||||
|
|
||||||
|
@liveexample{The example shows how `emplace()` can be used to add elements
|
||||||
|
to a JSON object. Note how the `null` value was silently converted to a
|
||||||
|
JSON object. Further note how no value is added if there was already one
|
||||||
|
value stored with the same key.,emplace}
|
||||||
|
|
||||||
|
@since version 2.0.8
|
||||||
|
*/
|
||||||
|
template<class... Args>
|
||||||
|
std::pair<iterator, bool> emplace(Args&& ... args)
|
||||||
|
{
|
||||||
|
// emplace only works for null objects or arrays
|
||||||
|
if (not(is_null() or is_object()))
|
||||||
|
{
|
||||||
|
throw std::domain_error("cannot use emplace() with " + type_name());
|
||||||
|
}
|
||||||
|
|
||||||
|
// transform null object into an object
|
||||||
|
if (is_null())
|
||||||
|
{
|
||||||
|
m_type = value_t::object;
|
||||||
|
m_value = value_t::object;
|
||||||
|
assert_invariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
// add element to array (perfect forwarding)
|
||||||
|
auto res = m_value.object->emplace(std::forward<Args>(args)...);
|
||||||
|
// create result iterator and set iterator to the result of emplace
|
||||||
|
auto it = begin();
|
||||||
|
it.m_it.object_iterator = res.first;
|
||||||
|
|
||||||
|
// return pair of iterator and boolean
|
||||||
|
return {it, res.second};
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@brief inserts element
|
@brief inserts element
|
||||||
|
|
||||||
|
|
|
@ -5032,6 +5032,102 @@ class basic_json
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief add an object to an array
|
||||||
|
|
||||||
|
Creates a JSON value from the passed parameters @a args to the end of the
|
||||||
|
JSON value. If the function is called on a JSON null value, an empty array
|
||||||
|
is created before appending the value created from @a args.
|
||||||
|
|
||||||
|
@param[in] args arguments to forward to a constructor of @ref basic_json
|
||||||
|
@tparam Args compatible types to create a @ref basic_json object
|
||||||
|
|
||||||
|
@throw std::domain_error when called on a type other than JSON array or
|
||||||
|
null; example: `"cannot use emplace_back() with number"`
|
||||||
|
|
||||||
|
@complexity Amortized constant.
|
||||||
|
|
||||||
|
@liveexample{The example shows how `push_back()` can be used to add
|
||||||
|
elements to a JSON array. Note how the `null` value was silently converted
|
||||||
|
to a JSON array.,emplace_back}
|
||||||
|
|
||||||
|
@since version 2.0.8
|
||||||
|
*/
|
||||||
|
template<class... Args>
|
||||||
|
void emplace_back(Args&& ... args)
|
||||||
|
{
|
||||||
|
// emplace_back only works for null objects or arrays
|
||||||
|
if (not(is_null() or is_array()))
|
||||||
|
{
|
||||||
|
throw std::domain_error("cannot use emplace_back() with " + type_name());
|
||||||
|
}
|
||||||
|
|
||||||
|
// transform null object into an array
|
||||||
|
if (is_null())
|
||||||
|
{
|
||||||
|
m_type = value_t::array;
|
||||||
|
m_value = value_t::array;
|
||||||
|
assert_invariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
// add element to array (perfect forwarding)
|
||||||
|
m_value.array->emplace_back(std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief add an object to an object if key does not exist
|
||||||
|
|
||||||
|
Inserts a new element into a JSON object constructed in-place with the given
|
||||||
|
@a args if there is no element with the key in the container. If the
|
||||||
|
function is called on a JSON null value, an empty object is created before
|
||||||
|
appending the value created from @a args.
|
||||||
|
|
||||||
|
@param[in] args arguments to forward to a constructor of @ref basic_json
|
||||||
|
@tparam Args compatible types to create a @ref basic_json object
|
||||||
|
|
||||||
|
@return a pair consisting of an iterator to the inserted element, or the
|
||||||
|
already-existing element if no insertion happened, and a bool
|
||||||
|
denoting whether the insertion took place.
|
||||||
|
|
||||||
|
@throw std::domain_error when called on a type other than JSON object or
|
||||||
|
null; example: `"cannot use emplace() with number"`
|
||||||
|
|
||||||
|
@complexity Logarithmic in the size of the container, O(log(`size()`)).
|
||||||
|
|
||||||
|
@liveexample{The example shows how `emplace()` can be used to add elements
|
||||||
|
to a JSON object. Note how the `null` value was silently converted to a
|
||||||
|
JSON object. Further note how no value is added if there was already one
|
||||||
|
value stored with the same key.,emplace}
|
||||||
|
|
||||||
|
@since version 2.0.8
|
||||||
|
*/
|
||||||
|
template<class... Args>
|
||||||
|
std::pair<iterator, bool> emplace(Args&& ... args)
|
||||||
|
{
|
||||||
|
// emplace only works for null objects or arrays
|
||||||
|
if (not(is_null() or is_object()))
|
||||||
|
{
|
||||||
|
throw std::domain_error("cannot use emplace() with " + type_name());
|
||||||
|
}
|
||||||
|
|
||||||
|
// transform null object into an object
|
||||||
|
if (is_null())
|
||||||
|
{
|
||||||
|
m_type = value_t::object;
|
||||||
|
m_value = value_t::object;
|
||||||
|
assert_invariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
// add element to array (perfect forwarding)
|
||||||
|
auto res = m_value.object->emplace(std::forward<Args>(args)...);
|
||||||
|
// create result iterator and set iterator to the result of emplace
|
||||||
|
auto it = begin();
|
||||||
|
it.m_it.object_iterator = res.first;
|
||||||
|
|
||||||
|
// return pair of iterator and boolean
|
||||||
|
return {it, res.second};
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@brief inserts element
|
@brief inserts element
|
||||||
|
|
||||||
|
|
|
@ -258,6 +258,103 @@ TEST_CASE("modifiers")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SECTION("emplace_back()")
|
||||||
|
{
|
||||||
|
SECTION("to array")
|
||||||
|
{
|
||||||
|
SECTION("null")
|
||||||
|
{
|
||||||
|
json j;
|
||||||
|
j.emplace_back(1);
|
||||||
|
j.emplace_back(2);
|
||||||
|
CHECK(j.type() == json::value_t::array);
|
||||||
|
CHECK(j == json({1, 2}));
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("array")
|
||||||
|
{
|
||||||
|
json j = {1, 2, 3};
|
||||||
|
j.emplace_back("Hello");
|
||||||
|
CHECK(j.type() == json::value_t::array);
|
||||||
|
CHECK(j == json({1, 2, 3, "Hello"}));
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("multiple values")
|
||||||
|
{
|
||||||
|
json j;
|
||||||
|
j.emplace_back(3, "foo");
|
||||||
|
CHECK(j.type() == json::value_t::array);
|
||||||
|
CHECK(j == json({{"foo", "foo", "foo"}}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("other type")
|
||||||
|
{
|
||||||
|
json j = 1;
|
||||||
|
CHECK_THROWS_AS(j.emplace_back("Hello"), std::domain_error);
|
||||||
|
CHECK_THROWS_WITH(j.emplace_back("Hello"), "cannot use emplace_back() with number");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("emplace()")
|
||||||
|
{
|
||||||
|
SECTION("to object")
|
||||||
|
{
|
||||||
|
SECTION("null")
|
||||||
|
{
|
||||||
|
// start with a null value
|
||||||
|
json j;
|
||||||
|
|
||||||
|
// add a new key
|
||||||
|
auto res1 = j.emplace("foo", "bar");
|
||||||
|
CHECK(res1.second == true);
|
||||||
|
CHECK(*res1.first == "bar");
|
||||||
|
|
||||||
|
// the null value is changed to an object
|
||||||
|
CHECK(j.type() == json::value_t::object);
|
||||||
|
|
||||||
|
// add a new key
|
||||||
|
auto res2 = j.emplace("baz", "bam");
|
||||||
|
CHECK(res2.second == true);
|
||||||
|
CHECK(*res2.first == "bam");
|
||||||
|
|
||||||
|
// we try to insert at given key - no change
|
||||||
|
auto res3 = j.emplace("baz", "bad");
|
||||||
|
CHECK(res3.second == false);
|
||||||
|
CHECK(*res3.first == "bam");
|
||||||
|
|
||||||
|
// the final object
|
||||||
|
CHECK(j == json({{"baz", "bam"}, {"foo", "bar"}}));
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("object")
|
||||||
|
{
|
||||||
|
// start with an object
|
||||||
|
json j = {{"foo", "bar"}};
|
||||||
|
|
||||||
|
// add a new key
|
||||||
|
auto res1 = j.emplace("baz", "bam");
|
||||||
|
CHECK(res1.second == true);
|
||||||
|
CHECK(*res1.first == "bam");
|
||||||
|
|
||||||
|
// add an existing key
|
||||||
|
auto res2 = j.emplace("foo", "bad");
|
||||||
|
CHECK(res2.second == false);
|
||||||
|
CHECK(*res2.first == "bar");
|
||||||
|
|
||||||
|
// check final object
|
||||||
|
CHECK(j == json({{"baz", "bam"}, {"foo", "bar"}}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("other type")
|
||||||
|
{
|
||||||
|
json j = 1;
|
||||||
|
CHECK_THROWS_AS(j.emplace("foo", "bar"), std::domain_error);
|
||||||
|
CHECK_THROWS_WITH(j.emplace("foo", "bar"), "cannot use emplace() with number");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
SECTION("operator+=")
|
SECTION("operator+=")
|
||||||
{
|
{
|
||||||
SECTION("to array")
|
SECTION("to array")
|
||||||
|
|
Loading…
Reference in a new issue