diff --git a/doc/examples/emplace.cpp b/doc/examples/emplace.cpp index 6014a3619a..c3b3c3e357 100644 --- a/doc/examples/emplace.cpp +++ b/doc/examples/emplace.cpp @@ -13,11 +13,18 @@ int main() std::cout << null << '\n'; // add values - object.emplace("three", 3); + 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'; } diff --git a/doc/examples/emplace.link b/doc/examples/emplace.link index e78fd0e518..a9366c3266 100644 --- a/doc/examples/emplace.link +++ b/doc/examples/emplace.link @@ -1 +1 @@ -online \ No newline at end of file +online \ No newline at end of file diff --git a/doc/examples/emplace.output b/doc/examples/emplace.output index 2bc9c00293..83d6f77300 100644 --- a/doc/examples/emplace.output +++ b/doc/examples/emplace.output @@ -1,4 +1,6 @@ {"one":1,"two":2} null {"one":1,"three":3,"two":2} +3 true {"A":"a","B":"b"} +"b" false diff --git a/src/json.hpp b/src/json.hpp index fdc57dff3b..36afd56bc8 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -5075,15 +5075,20 @@ class basic_json } /*! - @brief add an object to an object + @brief add an object to an object if key does not exist - Creates a JSON value from the passed parameters @a args to the JSON - object. If the function is called on a JSON null value, an empty object - is created before appending the value created from @a args. + 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"` @@ -5091,12 +5096,13 @@ class basic_json @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.,emplace} + 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 - void emplace(Args&& ... args) + std::pair emplace(Args&& ... args) { // emplace only works for null objects or arrays if (not(is_null() or is_object())) @@ -5113,7 +5119,13 @@ class basic_json } // add element to array (perfect forwarding) - m_value.object->emplace(std::forward(args)...); + auto res = m_value.object->emplace(std::forward(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}; } /*! diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index 383f4b8fad..b629dc6193 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -5075,15 +5075,20 @@ class basic_json } /*! - @brief add an object to an object + @brief add an object to an object if key does not exist - Creates a JSON value from the passed parameters @a args to the JSON - object. If the function is called on a JSON null value, an empty object - is created before appending the value created from @a args. + 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"` @@ -5091,12 +5096,13 @@ class basic_json @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.,emplace} + 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 - void emplace(Args&& ... args) + std::pair emplace(Args&& ... args) { // emplace only works for null objects or arrays if (not(is_null() or is_object())) @@ -5113,7 +5119,13 @@ class basic_json } // add element to array (perfect forwarding) - m_value.object->emplace(std::forward(args)...); + auto res = m_value.object->emplace(std::forward(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}; } /*! diff --git a/test/src/unit-modifiers.cpp b/test/src/unit-modifiers.cpp index 499edde77b..e715d55fbe 100644 --- a/test/src/unit-modifiers.cpp +++ b/test/src/unit-modifiers.cpp @@ -302,18 +302,47 @@ TEST_CASE("modifiers") { SECTION("null") { + // start with a null value json j; - j.emplace("foo", "bar"); - j.emplace("baz", "bam"); + + // 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"}}; - j.emplace("baz", "bam"); - CHECK(j.type() == json::value_t::object); + + // 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"}})); } }