diff --git a/doc/examples/operatorarray__key_type_const.cpp b/doc/examples/operatorarray__key_type_const.cpp index 6d0c91412f1bc17aad86a03a8afbe2e1474e926e..a59cca58bbe6c9954f31eecd56bbee194e8ed77b 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 0f03498a91f3c522a9c496c657d7ff9b696437aa..7e740a1b828b237a3d055870bb29d8b5608068e1 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 6bfb44bff06c1801b59df060344d707d1f9b33f2..e11bae2d573884449574391becdeca731f9f6288 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 3ab1dfce14d4c5b487009f7fc11b71d4649d97b3..119ec5c2a0847cdeffbbb8f02fd57d3d718f57d5 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 b143f31b5d1848186d0b26b340aa17bc6f3e5229..e52128ce84528ebb8c875c2eadbfa9a6a8fbe5da 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); } } }