From 80877ad75b816aa42da3ff2c134cc7b14c4d2422 Mon Sep 17 00:00:00 2001 From: Trevor Welsby Date: Fri, 22 Jan 2016 23:20:48 +1000 Subject: [PATCH] Add extra operator[] overload templates to address issue #171 --- src/json.hpp | 80 ++++++++++++++++++++++++++++++++++++++++++----- src/json.hpp.re2c | 80 ++++++++++++++++++++++++++++++++++++++++++----- test/unit.cpp | 49 +++++++++++++++++++++++++++++ 3 files changed, 193 insertions(+), 16 deletions(-) diff --git a/src/json.hpp b/src/json.hpp index 78f67b3a1e..b1f0b15119 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -3272,8 +3272,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 @@ -3293,7 +3291,75 @@ class basic_json @since version 1.0.0 */ template - reference operator[](const T (&key)[n]) + reference operator[](T* (&key)[n]) + { + return operator[](static_cast(key)); + } + + /*! + @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; 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.0 + */ + template + 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 2.0.0 + */ + template + reference operator[](T* key) { // implicitly convert null to object if (is_null()) @@ -3323,8 +3389,6 @@ class basic_json @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 @@ -3341,10 +3405,10 @@ class basic_json with range checking @sa @ref value() for access by value with a default value - @since version 1.0.0 + @since version 2.0.0 */ - template - const_reference operator[](const T (&key)[n]) const + 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 b1f8a09bbf..b329a569a0 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -3272,8 +3272,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 @@ -3293,7 +3291,75 @@ class basic_json @since version 1.0.0 */ template - reference operator[](const T (&key)[n]) + reference operator[](T* (&key)[n]) + { + return operator[](static_cast(key)); + } + + /*! + @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; 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.0 + */ + template + 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 2.0.0 + */ + template + reference operator[](T* key) { // implicitly convert null to object if (is_null()) @@ -3323,8 +3389,6 @@ class basic_json @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 @@ -3341,10 +3405,10 @@ class basic_json with range checking @sa @ref value() for access by value with a default value - @since version 1.0.0 + @since version 2.0.0 */ - template - const_reference operator[](const T (&key)[n]) const + 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 289172234c..26da9951b9 100644 --- a/test/unit.cpp +++ b/test/unit.cpp @@ -12201,5 +12201,54 @@ 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)); + } }