From 4351698c839b9aafd5fb82513d87469a25f55022 Mon Sep 17 00:00:00 2001 From: Niels Date: Mon, 21 Dec 2015 08:42:42 +0100 Subject: [PATCH] re-adding const version operator[] (#135, #159) It was a good idea to implement a const version of operator[] it in the first place. I was a pity that this implementation was flawed. It was a mistake to remove the const version completely. This commit re-introduces the const version. My apologies for all the inconvenience. --- .../operatorarray__key_type_const.cpp | 2 +- .../operatorarray__key_type_const.link | 2 +- src/json.hpp | 81 +++++++++++++++++++ src/json.hpp.re2c | 81 +++++++++++++++++++ test/unit.cpp | 33 ++++++++ 5 files changed, 197 insertions(+), 2 deletions(-) diff --git a/doc/examples/operatorarray__key_type_const.cpp b/doc/examples/operatorarray__key_type_const.cpp index 6d0c91412..a59cca58b 100644 --- a/doc/examples/operatorarray__key_type_const.cpp +++ b/doc/examples/operatorarray__key_type_const.cpp @@ -5,7 +5,7 @@ using namespace nlohmann; int main() { // create a JSON object - json object = + const json object = { {"one", 1}, {"two", 2}, {"three", 2.9} }; diff --git a/doc/examples/operatorarray__key_type_const.link b/doc/examples/operatorarray__key_type_const.link index 0f03498a9..7e740a1b8 100644 --- a/doc/examples/operatorarray__key_type_const.link +++ b/doc/examples/operatorarray__key_type_const.link @@ -1 +1 @@ -online \ No newline at end of file +online \ No newline at end of file diff --git a/src/json.hpp b/src/json.hpp index 6bfb44bff..e11bae2d5 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -2862,6 +2862,45 @@ class basic_json } } + /*! + @brief read-only access specified object element + + Returns a const reference to the element at with specified key @a key. No + bounds checking is performed. + + @warning If the element with key @a key does not exist, the behavior is + undefined. + + @param[in] key key of the element to access + + @return const reference to the element at key @a key + + @throw std::domain_error if JSON is not an object + + @complexity Logarithmic in the size of the container. + + @liveexample{The example below shows how object elements can be read using + the [] operator.,operatorarray__key_type_const} + + @sa @ref at(const typename object_t::key_type&) for access by reference + with range checking + @sa @ref value() for access by value with a default value + + @since version 1.0 + */ + const_reference operator[](const typename object_t::key_type& key) const + { + // [] only works for objects + if (is_object()) + { + return m_value.object->find(key)->second; + } + else + { + throw std::domain_error("cannot use operator[] with " + type_name()); + } + } + /*! @brief access specified object element @@ -2911,6 +2950,48 @@ class basic_json } } + /*! + @brief read-only access specified object element + + Returns a const reference to the element at with specified key @a key. No + bounds checking is performed. + + @warning If the element with key @a key does not exist, the behavior is + undefined. + + @note This function is required for compatibility reasons with Clang. + + @param[in] key key of the element to access + + @return const reference to the element at key @a key + + @throw std::domain_error if JSON is not an object + + @complexity Logarithmic in the size of the container. + + @liveexample{The example below shows how object elements can be read using + the [] operator.,operatorarray__key_type_const} + + @sa @ref at(const typename object_t::key_type&) for access by reference + with range checking + @sa @ref value() for access by value with a default value + + @since version 1.0 + */ + template + const_reference operator[](const T (&key)[n]) const + { + // at only works for objects + if (is_object()) + { + return m_value.object->find(key)->second; + } + else + { + throw std::domain_error("cannot use operator[] with " + type_name()); + } + } + /*! @brief access specified object element with default value diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index 3ab1dfce1..119ec5c2a 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -2862,6 +2862,45 @@ class basic_json } } + /*! + @brief read-only access specified object element + + Returns a const reference to the element at with specified key @a key. No + bounds checking is performed. + + @warning If the element with key @a key does not exist, the behavior is + undefined. + + @param[in] key key of the element to access + + @return const reference to the element at key @a key + + @throw std::domain_error if JSON is not an object + + @complexity Logarithmic in the size of the container. + + @liveexample{The example below shows how object elements can be read using + the [] operator.,operatorarray__key_type_const} + + @sa @ref at(const typename object_t::key_type&) for access by reference + with range checking + @sa @ref value() for access by value with a default value + + @since version 1.0 + */ + const_reference operator[](const typename object_t::key_type& key) const + { + // [] only works for objects + if (is_object()) + { + return m_value.object->find(key)->second; + } + else + { + throw std::domain_error("cannot use operator[] with " + type_name()); + } + } + /*! @brief access specified object element @@ -2911,6 +2950,48 @@ class basic_json } } + /*! + @brief read-only access specified object element + + Returns a const reference to the element at with specified key @a key. No + bounds checking is performed. + + @warning If the element with key @a key does not exist, the behavior is + undefined. + + @note This function is required for compatibility reasons with Clang. + + @param[in] key key of the element to access + + @return const reference to the element at key @a key + + @throw std::domain_error if JSON is not an object + + @complexity Logarithmic in the size of the container. + + @liveexample{The example below shows how object elements can be read using + the [] operator.,operatorarray__key_type_const} + + @sa @ref at(const typename object_t::key_type&) for access by reference + with range checking + @sa @ref value() for access by value with a default value + + @since version 1.0 + */ + template + const_reference operator[](const T (&key)[n]) const + { + // at only works for objects + if (is_object()) + { + return m_value.object->find(key)->second; + } + else + { + throw std::domain_error("cannot use operator[] with " + type_name()); + } + } + /*! @brief access specified object element with default value diff --git a/test/unit.cpp b/test/unit.cpp index b143f31b5..e52128ce8 100644 --- a/test/unit.cpp +++ b/test/unit.cpp @@ -3211,6 +3211,27 @@ TEST_CASE("element access") CHECK(j["array"] == json({1, 2, 3})); CHECK(j[json::object_t::key_type("array")] == j["array"]); + + CHECK(j_const["integer"] == json(1)); + CHECK(j_const[json::object_t::key_type("integer")] == j["integer"]); + + CHECK(j_const["boolean"] == json(true)); + CHECK(j_const[json::object_t::key_type("boolean")] == j["boolean"]); + + CHECK(j_const["null"] == json(nullptr)); + CHECK(j_const[json::object_t::key_type("null")] == j["null"]); + + CHECK(j_const["string"] == json("hello world")); + CHECK(j_const[json::object_t::key_type("string")] == j["string"]); + + CHECK(j_const["floating"] == json(42.23)); + CHECK(j_const[json::object_t::key_type("floating")] == j["floating"]); + + CHECK(j_const["object"] == json(json::object())); + CHECK(j_const[json::object_t::key_type("object")] == j["object"]); + + CHECK(j_const["array"] == json({1, 2, 3})); + CHECK(j_const[json::object_t::key_type("array")] == j["array"]); } SECTION("access on non-object type") @@ -3222,6 +3243,8 @@ TEST_CASE("element access") const json j_const_nonobject(j_nonobject); CHECK_NOTHROW(j_nonobject["foo"]); CHECK_NOTHROW(j_nonobject2[json::object_t::key_type("foo")]); + CHECK_THROWS_AS(j_const_nonobject["foo"], std::domain_error); + CHECK_THROWS_AS(j_const_nonobject[json::object_t::key_type("foo")], std::domain_error); } SECTION("boolean") @@ -3230,6 +3253,8 @@ TEST_CASE("element access") const json j_const_nonobject(j_nonobject); CHECK_THROWS_AS(j_nonobject["foo"], std::domain_error); CHECK_THROWS_AS(j_nonobject[json::object_t::key_type("foo")], std::domain_error); + CHECK_THROWS_AS(j_const_nonobject["foo"], std::domain_error); + CHECK_THROWS_AS(j_const_nonobject[json::object_t::key_type("foo")], std::domain_error); } SECTION("string") @@ -3238,6 +3263,8 @@ TEST_CASE("element access") const json j_const_nonobject(j_nonobject); CHECK_THROWS_AS(j_nonobject["foo"], std::domain_error); CHECK_THROWS_AS(j_nonobject[json::object_t::key_type("foo")], std::domain_error); + CHECK_THROWS_AS(j_const_nonobject["foo"], std::domain_error); + CHECK_THROWS_AS(j_const_nonobject[json::object_t::key_type("foo")], std::domain_error); } SECTION("array") @@ -3246,6 +3273,8 @@ TEST_CASE("element access") const json j_const_nonobject(j_nonobject); CHECK_THROWS_AS(j_nonobject["foo"], std::domain_error); CHECK_THROWS_AS(j_nonobject[json::object_t::key_type("foo")], std::domain_error); + CHECK_THROWS_AS(j_const_nonobject["foo"], std::domain_error); + CHECK_THROWS_AS(j_const_nonobject[json::object_t::key_type("foo")], std::domain_error); } SECTION("number (integer)") @@ -3254,6 +3283,8 @@ TEST_CASE("element access") const json j_const_nonobject(j_nonobject); CHECK_THROWS_AS(j_nonobject["foo"], std::domain_error); CHECK_THROWS_AS(j_nonobject[json::object_t::key_type("foo")], std::domain_error); + CHECK_THROWS_AS(j_const_nonobject["foo"], std::domain_error); + CHECK_THROWS_AS(j_const_nonobject[json::object_t::key_type("foo")], std::domain_error); } SECTION("number (floating-point)") @@ -3262,6 +3293,8 @@ TEST_CASE("element access") const json j_const_nonobject(j_nonobject); CHECK_THROWS_AS(j_nonobject["foo"], std::domain_error); CHECK_THROWS_AS(j_nonobject[json::object_t::key_type("foo")], std::domain_error); + CHECK_THROWS_AS(j_const_nonobject["foo"], std::domain_error); + CHECK_THROWS_AS(j_const_nonobject[json::object_t::key_type("foo")], std::domain_error); } } } -- GitLab