From 7e3245786c63c0923186b2b38c9c874ed2cc3942 Mon Sep 17 00:00:00 2001 From: Trevor Welsby Date: Sat, 23 Jan 2016 17:03:45 +1000 Subject: [PATCH] Fixed issue #171 - added extra operator[] template overloads --- src/json.hpp | 106 +++++++++++++++++++++++++++++++++++++--------- src/json.hpp.re2c | 106 +++++++++++++++++++++++++++++++++++++--------- test/unit.cpp | 48 +++++++++++++++++++++ 3 files changed, 218 insertions(+), 42 deletions(-) diff --git a/src/json.hpp b/src/json.hpp index ac362dcf..63bc8026 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -3062,8 +3062,6 @@ class basic_json the object and filled with a `null` value to make `key` a valid reference. In case the value was `null` before, it is converted to an object. - @note This function is required for compatibility reasons with Clang. - @param[in] key key of the element to access @return reference to the element at key @a key @@ -3083,25 +3081,9 @@ class basic_json @since version 1.0.0 */ template - reference operator[](const T (&key)[n]) + reference operator[](T* (&key)[n]) { - // implicitly convert null to object - if (is_null()) - { - m_type = value_t::object; - m_value = value_t::object; - } - - // at only works for objects - if (is_object()) - { - assert(m_value.object != nullptr); - return m_value.object->operator[](key); - } - else - { - throw std::domain_error("cannot use operator[] with " + type_name()); - } + return operator[](static_cast(key)); } /*! @@ -3134,7 +3116,89 @@ class basic_json @since version 1.0.0 */ template - const_reference operator[](const T (&key)[n]) const + const_reference operator[](T* (&key)[n]) const + { + return operator[](static_cast(key)); + } + + /*! + @brief access specified object element + + Returns a reference to the element at with specified key @a key. + + @note If @a key is not found in the object, then it is silently added to + the object and filled with a `null` value to make `key` a valid reference. + In case the value was `null` before, it is converted to an object. + + @param[in] key key of the element to access + + @return reference to the element at key @a key + + @throw std::domain_error if JSON is not an object or null; example: + `"cannot use operator[] with null"` + + @complexity Logarithmic in the size of the container. + + @liveexample{The example below shows how object elements can be read and + written using the [] operator.,operatorarray__key_type} + + @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.1 + */ + template + reference operator[](T* key) + { + // implicitly convert null to object + if (is_null()) + { + m_type = value_t::object; + m_value = value_t::object; + } + + // at only works for objects + if (is_object()) + { + assert(m_value.object != nullptr); + return m_value.object->operator[](key); + } + else + { + throw std::domain_error("cannot use operator[] with " + type_name()); + } + } + + /*! + @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; example: `"cannot use + operator[] with null"` + + @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.1 + */ + template + const_reference operator[](T* key) const { // at only works for objects if (is_object()) diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index c7ee44f5..a3e7c790 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -3062,8 +3062,6 @@ class basic_json the object and filled with a `null` value to make `key` a valid reference. In case the value was `null` before, it is converted to an object. - @note This function is required for compatibility reasons with Clang. - @param[in] key key of the element to access @return reference to the element at key @a key @@ -3083,25 +3081,9 @@ class basic_json @since version 1.0.0 */ template - reference operator[](const T (&key)[n]) + reference operator[](T* (&key)[n]) { - // implicitly convert null to object - if (is_null()) - { - m_type = value_t::object; - m_value = value_t::object; - } - - // at only works for objects - if (is_object()) - { - assert(m_value.object != nullptr); - return m_value.object->operator[](key); - } - else - { - throw std::domain_error("cannot use operator[] with " + type_name()); - } + return operator[](static_cast(key)); } /*! @@ -3134,7 +3116,89 @@ class basic_json @since version 1.0.0 */ template - const_reference operator[](const T (&key)[n]) const + const_reference operator[](T* (&key)[n]) const + { + return operator[](static_cast(key)); + } + + /*! + @brief access specified object element + + Returns a reference to the element at with specified key @a key. + + @note If @a key is not found in the object, then it is silently added to + the object and filled with a `null` value to make `key` a valid reference. + In case the value was `null` before, it is converted to an object. + + @param[in] key key of the element to access + + @return reference to the element at key @a key + + @throw std::domain_error if JSON is not an object or null; example: + `"cannot use operator[] with null"` + + @complexity Logarithmic in the size of the container. + + @liveexample{The example below shows how object elements can be read and + written using the [] operator.,operatorarray__key_type} + + @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.1 + */ + template + reference operator[](T* key) + { + // implicitly convert null to object + if (is_null()) + { + m_type = value_t::object; + m_value = value_t::object; + } + + // at only works for objects + if (is_object()) + { + assert(m_value.object != nullptr); + return m_value.object->operator[](key); + } + else + { + throw std::domain_error("cannot use operator[] with " + type_name()); + } + } + + /*! + @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; example: `"cannot use + operator[] with null"` + + @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.1 + */ + template + const_reference operator[](T* key) const { // at only works for objects if (is_object()) diff --git a/test/unit.cpp b/test/unit.cpp index 8b3bc19b..773978ec 100644 --- a/test/unit.cpp +++ b/test/unit.cpp @@ -11504,4 +11504,52 @@ TEST_CASE("regression tests") { CHECK(json::parse("\"\\ud80c\\udc60abc\"").get() == u8"\U00013060abc"); } + + SECTION("issue #144 - Cannot index by key of type static constexpr const char*") + { + json j; + + // Non-const access with key as "char []" + char array_key[] = "Key1"; + CHECK_NOTHROW(j[array_key] = 1); + CHECK(j[array_key] == json(1)); + + // Non-const access with key as "const char[]" + const char const_array_key[] = "Key2"; + CHECK_NOTHROW(j[const_array_key] = 2); + CHECK(j[const_array_key] == json(2)); + + // Non-const access with key as "char *" + char _ptr_key[] = "Key3"; + char * ptr_key = &_ptr_key[0]; + CHECK_NOTHROW(j[ptr_key] = 3); + CHECK(j[ptr_key] == json(3)); + + // Non-const access with key as "const char *" + const char * const_ptr_key = "Key4"; + CHECK_NOTHROW(j[const_ptr_key] = 4); + CHECK(j[const_ptr_key] == json(4)); + + // Non-const access with key as "static constexpr const char *" + static constexpr const char* constexpr_ptr_key = "Key5"; + CHECK_NOTHROW(j[constexpr_ptr_key] = 5); + CHECK(j[constexpr_ptr_key] == json(5)); + + const json j_const = j; + + // Non-const access with key as "char []" + CHECK(j_const[array_key] == json(1)); + + // Non-const access with key as "const char[]" + CHECK(j_const[const_array_key] == json(2)); + + // Non-const access with key as "char *" + CHECK(j_const[ptr_key] == json(3)); + + // Non-const access with key as "const char *" + CHECK(j_const[const_ptr_key] == json(4)); + + // Non-const access with key as "static constexpr const char *" + CHECK(j_const[constexpr_ptr_key] == json(5)); + } }