diff --git a/README.md b/README.md index 95e920f1..68d4a1fb 100644 --- a/README.md +++ b/README.md @@ -382,7 +382,7 @@ I deeply appreciate the help of the following people. - [Colin Hirsch](https://github.com/ColinH) took care of a small namespace issue. - [Huu Nguyen](https://github.com/whoshuu) correct a variable name in the documentation. - [Silverweed](https://github.com/silverweed) overloaded `parse()` to accept an rvalue reference. -- [dariomt](https://github.com/dariomt) fixed a subtlety in MSVC type support. +- [dariomt](https://github.com/dariomt) fixed a subtlety in MSVC type support and implemented the `get_ref()` function to get a reference to stored values. - [ZahlGraf](https://github.com/ZahlGraf) added a workaround that allows compilation using Android NDK. - [whackashoe](https://github.com/whackashoe) replaced a function that was marked as unsafe by Visual Studio. - [406345](https://github.com/406345) fixed two small warnings. diff --git a/doc/examples/get_ref.cpp b/doc/examples/get_ref.cpp index a8a86853..c73cff3e 100644 --- a/doc/examples/get_ref.cpp +++ b/doc/examples/get_ref.cpp @@ -13,13 +13,13 @@ int main() // print the values std::cout << r1 << ' ' << r2 << '\n'; - + // incompatible type throws exception try { auto r3 = value.get_ref(); } - catch(std::domain_error& ex) + catch (std::domain_error& ex) { std::cout << ex.what() << '\n'; } diff --git a/doc/examples/get_ref.link b/doc/examples/get_ref.link new file mode 100644 index 00000000..4c8fd69a --- /dev/null +++ b/doc/examples/get_ref.link @@ -0,0 +1 @@ +online \ No newline at end of file diff --git a/doc/examples/get_ref.output b/doc/examples/get_ref.output new file mode 100644 index 00000000..50bc0df6 --- /dev/null +++ b/doc/examples/get_ref.output @@ -0,0 +1,2 @@ +17 17 +incompatible ReferenceType for get_ref, actual type is number diff --git a/src/json.hpp b/src/json.hpp index 81c02857..343d2356 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -2416,17 +2416,33 @@ class basic_json return is_number_float() ? &m_value.number_float : nullptr; } - /// helper function to implement get_ref without code duplication - /// for const and non-const overloads - /// ThisType will be deduced as 'basic_jason' or 'const basic_json' - template + /*! + @brief helper function to implement get_ref() + + This funcion helps to implement get_ref() without code duplication for + const and non-const overloads + + @tparam ThisType will be deduced as `basic_json` or `const basic_json` + + @throw std::domain_error if ReferenceType does not match underlying value + type of the current JSON + */ + template static ReferenceType get_ref_impl(ThisType& obj) { - using PointerType = typename std::add_pointer::type; // delegate the call to get_ptr<>() + using PointerType = typename std::add_pointer::type; auto ptr = obj.template get_ptr(); - if (ptr) return *ptr; - throw std::domain_error("incompatible ReferenceType for get_ref, actual type is " + obj.type_name()); + + if (ptr != nullptr) + { + return *ptr; + } + else + { + throw std::domain_error("incompatible ReferenceType for get_ref, actual type is " + + obj.type_name()); + } } public: @@ -2576,7 +2592,7 @@ class basic_json return get_impl_ptr(static_cast(nullptr)); } - /*! + /*! @brief get a reference value (implicit) Implict reference access to the internally stored JSON value. No copies are @@ -2585,17 +2601,22 @@ class basic_json @warning Writing data to the referee of the result yields an undefined state. - @tparam ReferenceType reference type; must be a reference to @ref array_t, @ref - object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, or @ref - number_float_t. + @tparam ReferenceType reference type; must be a reference to @ref array_t, + @ref object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, or + @ref number_float_t. - @return reference to the internally stored JSON value if the requested reference - type @a ReferenceType fits to the JSON value; throws std::domain_error otherwise + @return reference to the internally stored JSON value if the requested + reference type @a ReferenceType fits to the JSON value; throws + std::domain_error otherwise - @throw std::domain_error in case passed type @a ReferenceType is incompatible - with the stored JSON value + @throw std::domain_error in case passed type @a ReferenceType is + incompatible with the stored JSON value @complexity Constant. + + @liveexample{The example shows several calls to `get_ref()`.,get_ref} + + @since version 1.0.1 */ template::type = 0> ReferenceType get_ref() { - // delegate call to get_ref_impl - return get_ref_impl(*this); + // delegate call to get_ref_impl + return get_ref_impl(*this); } /*! @@ -2614,12 +2635,12 @@ class basic_json template::value - and std::is_const< typename std::remove_reference::type >::value + and std::is_const::type>::value , int>::type = 0> ReferenceType get_ref() const { - // delegate call to get_ref_impl - return get_ref_impl(*this); + // delegate call to get_ref_impl + return get_ref_impl(*this); } /*! diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index 0838b234..d384f313 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -2416,17 +2416,33 @@ class basic_json return is_number_float() ? &m_value.number_float : nullptr; } - /// helper function to implement get_ref without code duplication - /// for const and non-const overloads - /// ThisType will be deduced as 'basic_jason' or 'const basic_json' - template + /*! + @brief helper function to implement get_ref() + + This funcion helps to implement get_ref() without code duplication for + const and non-const overloads + + @tparam ThisType will be deduced as `basic_json` or `const basic_json` + + @throw std::domain_error if ReferenceType does not match underlying value + type of the current JSON + */ + template static ReferenceType get_ref_impl(ThisType& obj) { - using PointerType = typename std::add_pointer::type; // delegate the call to get_ptr<>() + using PointerType = typename std::add_pointer::type; auto ptr = obj.template get_ptr(); - if (ptr) return *ptr; - throw std::domain_error("incompatible ReferenceType for get_ref, actual type is " + obj.type_name()); + + if (ptr != nullptr) + { + return *ptr; + } + else + { + throw std::domain_error("incompatible ReferenceType for get_ref, actual type is " + + obj.type_name()); + } } public: @@ -2576,7 +2592,7 @@ class basic_json return get_impl_ptr(static_cast(nullptr)); } - /*! + /*! @brief get a reference value (implicit) Implict reference access to the internally stored JSON value. No copies are @@ -2585,17 +2601,22 @@ class basic_json @warning Writing data to the referee of the result yields an undefined state. - @tparam ReferenceType reference type; must be a reference to @ref array_t, @ref - object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, or @ref - number_float_t. + @tparam ReferenceType reference type; must be a reference to @ref array_t, + @ref object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, or + @ref number_float_t. - @return reference to the internally stored JSON value if the requested reference - type @a ReferenceType fits to the JSON value; throws std::domain_error otherwise + @return reference to the internally stored JSON value if the requested + reference type @a ReferenceType fits to the JSON value; throws + std::domain_error otherwise - @throw std::domain_error in case passed type @a ReferenceType is incompatible - with the stored JSON value + @throw std::domain_error in case passed type @a ReferenceType is + incompatible with the stored JSON value @complexity Constant. + + @liveexample{The example shows several calls to `get_ref()`.,get_ref} + + @since version 1.0.1 */ template::type = 0> ReferenceType get_ref() { - // delegate call to get_ref_impl - return get_ref_impl(*this); + // delegate call to get_ref_impl + return get_ref_impl(*this); } /*! @@ -2614,12 +2635,12 @@ class basic_json template::value - and std::is_const< typename std::remove_reference::type >::value + and std::is_const::type>::value , int>::type = 0> ReferenceType get_ref() const { - // delegate call to get_ref_impl - return get_ref_impl(*this); + // delegate call to get_ref_impl + return get_ref_impl(*this); } /*! diff --git a/test/unit.cpp b/test/unit.cpp index 81b341f6..8b3bc19b 100644 --- a/test/unit.cpp +++ b/test/unit.cpp @@ -2604,13 +2604,13 @@ TEST_CASE("pointer access") CHECK(value.get_ptr() == nullptr); } - SECTION("pointer access to const object_t") + SECTION("pointer access to const object_t") { using test_type = json::object_t; const json value = {{"one", 1}, {"two", 2}}; - // this should not compile - // test_type* p1 = value.get_ptr(); + // this should not compile + // test_type* p1 = value.get_ptr(); // check if pointers are returned correctly const test_type* p2 = value.get_ptr(); @@ -2781,14 +2781,14 @@ TEST_CASE("reference access") // check if references are returned correctly test_type& p1 = value.get_ref(); CHECK(&p1 == value.get_ptr()); - CHECK(p1 == value.get()); + CHECK(p1 == value.get()); const test_type& p2 = value.get_ref(); CHECK(&p2 == value.get_ptr()); CHECK(p2 == value.get()); // check if mismatching references throw correctly - CHECK_NOTHROW(value.get_ref()); + CHECK_NOTHROW(value.get_ref()); CHECK_THROWS(value.get_ref()); CHECK_THROWS(value.get_ref()); CHECK_THROWS(value.get_ref()); @@ -2796,13 +2796,13 @@ TEST_CASE("reference access") CHECK_THROWS(value.get_ref()); } - SECTION("const reference access to const object_t") + SECTION("const reference access to const object_t") { using test_type = json::object_t; const json value = {{"one", 1}, {"two", 2}}; - // this should not compile - // test_type& p1 = value.get_ref(); + // this should not compile + // test_type& p1 = value.get_ref(); // check if references are returned correctly const test_type& p2 = value.get_ref(); @@ -2818,7 +2818,7 @@ TEST_CASE("reference access") // check if references are returned correctly test_type& p1 = value.get_ref(); CHECK(&p1 == value.get_ptr()); - CHECK(p1 == value.get()); + CHECK(p1 == value.get()); const test_type& p2 = value.get_ref(); CHECK(&p2 == value.get_ptr()); @@ -2841,7 +2841,7 @@ TEST_CASE("reference access") // check if references are returned correctly test_type& p1 = value.get_ref(); CHECK(&p1 == value.get_ptr()); - CHECK(p1 == value.get()); + CHECK(p1 == value.get()); const test_type& p2 = value.get_ref(); CHECK(&p2 == value.get_ptr()); @@ -2864,7 +2864,7 @@ TEST_CASE("reference access") // check if references are returned correctly test_type& p1 = value.get_ref(); CHECK(&p1 == value.get_ptr()); - CHECK(p1 == value.get()); + CHECK(p1 == value.get()); const test_type& p2 = value.get_ref(); CHECK(&p2 == value.get_ptr()); @@ -2884,10 +2884,10 @@ TEST_CASE("reference access") using test_type = json::number_integer_t; json value = 23; - // check if references are returned correctly + // check if references are returned correctly test_type& p1 = value.get_ref(); CHECK(&p1 == value.get_ptr()); - CHECK(p1 == value.get()); + CHECK(p1 == value.get()); const test_type& p2 = value.get_ref(); CHECK(&p2 == value.get_ptr()); @@ -2907,10 +2907,10 @@ TEST_CASE("reference access") using test_type = json::number_float_t; json value = 42.23; - // check if references are returned correctly + // check if references are returned correctly test_type& p1 = value.get_ref(); CHECK(&p1 == value.get_ptr()); - CHECK(p1 == value.get()); + CHECK(p1 == value.get()); const test_type& p2 = value.get_ref(); CHECK(&p2 == value.get_ptr());