diff --git a/doc/examples/operatorarray__key_type.cpp b/doc/examples/operatorarray__key_type.cpp new file mode 100644 index 00000000..6050dc12 --- /dev/null +++ b/doc/examples/operatorarray__key_type.cpp @@ -0,0 +1,30 @@ +#include + +using namespace nlohmann; + +int main() +{ + // create a JSON object + json object = + { + {"one", 1}, {"two", 2}, {"three", 2.9} + }; + + // output element with key "two" + std::cout << object["two"] << "\n\n"; + + // change element with key "three" + object["three"] = 3; + + // output changed array + std::cout << std::setw(4) << object << "\n\n"; + + // mention nonexisting key + object["four"]; + + // write to nonexisting key + object["five"]["really"]["nested"] = true; + + // output changed object + std::cout << std::setw(4) << object << '\n'; +} diff --git a/doc/examples/operatorarray__key_type.output b/doc/examples/operatorarray__key_type.output new file mode 100644 index 00000000..b643587f --- /dev/null +++ b/doc/examples/operatorarray__key_type.output @@ -0,0 +1,19 @@ +2 + +{ + "one": 1, + "three": 3, + "two": 2 +} + +{ + "five": { + "really": { + "nested": true + } + }, + "four": null, + "one": 1, + "three": 3, + "two": 2 +} diff --git a/doc/examples/operatorarray__key_type_const.cpp b/doc/examples/operatorarray__key_type_const.cpp new file mode 100644 index 00000000..6d0c9141 --- /dev/null +++ b/doc/examples/operatorarray__key_type_const.cpp @@ -0,0 +1,15 @@ +#include + +using namespace nlohmann; + +int main() +{ + // create a JSON object + json object = + { + {"one", 1}, {"two", 2}, {"three", 2.9} + }; + + // output element with key "two" + std::cout << object["two"] << '\n'; +} diff --git a/doc/examples/operatorarray__key_type_const.output b/doc/examples/operatorarray__key_type_const.output new file mode 100644 index 00000000..0cfbf088 --- /dev/null +++ b/doc/examples/operatorarray__key_type_const.output @@ -0,0 +1 @@ +2 diff --git a/src/json.hpp b/src/json.hpp index d2f62209..86300376 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -120,7 +120,6 @@ template < > class basic_json { - public: ///////////////////// // container types // ///////////////////// @@ -128,9 +127,12 @@ class basic_json /// @name container types /// @{ + private: + /// workaround type for MSVC using __basic_json = basic_json; + public: /// the type of elements in a basic_json container using value_type = basic_json; @@ -208,8 +210,10 @@ class basic_json /*! @brief the JSON value type enumeration - This enumeration collects the different JSON value types. It is used to - distinguish the stored values in the union @ref json_value. + This enumeration collects the different JSON value types. It is internally + used to distinguish the stored values, and the functions is_null, + is_object, is_array, is_string, is_boolean, is_number, and is_discarded + rely on it. */ enum class value_t : uint8_t { @@ -224,6 +228,7 @@ class basic_json }; + private: //////////////////////// // JSON value storage // //////////////////////// @@ -332,6 +337,8 @@ class basic_json } }; + + public: ////////////////////////// // JSON parser callback // ////////////////////////// @@ -462,7 +469,7 @@ class basic_json @complexity Constant. @throw std::bad_alloc if allocation for object, array, or string value - fails (thrown by the constructors of @ref json_value) + fails @liveexample{The following code shows the constructor for different @ref value_t values,basic_json__value_t} @@ -520,8 +527,7 @@ class basic_json @complexity Linear in the size of the passed @a value. - @throw std::bad_alloc if allocation for object value fails (thrown by - the constructor of @ref json_value) + @throw std::bad_alloc if allocation for object value fails @liveexample{The following code shows the constructor with an @ref object_t parameter.,basic_json__object_t} @@ -546,8 +552,7 @@ class basic_json @complexity Linear in the size of the passed @a value. - @throw std::bad_alloc if allocation for object value fails (thrown by - the constructor of @ref json_value) + @throw std::bad_alloc if allocation for object value fails @liveexample{The following code shows the constructor with several compatible object type parameters.,basic_json__CompatibleObjectType} @@ -578,8 +583,7 @@ class basic_json @complexity Linear in the size of the passed @a value. - @throw std::bad_alloc if allocation for array value fails (thrown by - the constructor of @ref json_value) + @throw std::bad_alloc if allocation for array value fails @liveexample{The following code shows the constructor with an @ref array_t parameter.,basic_json__array_t} @@ -604,8 +608,7 @@ class basic_json @complexity Linear in the size of the passed @a value. - @throw std::bad_alloc if allocation for array value fails (thrown by - the constructor of @ref json_value) + @throw std::bad_alloc if allocation for array value fails @liveexample{The following code shows the constructor with several compatible array type parameters.,basic_json__CompatibleArrayType} @@ -641,8 +644,7 @@ class basic_json @complexity Linear in the size of the passed @a value. - @throw std::bad_alloc if allocation for string value fails (thrown by - the constructor of @ref json_value) + @throw std::bad_alloc if allocation for string value fails @liveexample{The following code shows the constructor with an @ref string_t parameter.,basic_json__string_t} @@ -663,8 +665,7 @@ class basic_json @complexity Linear in the size of the passed @a value. - @throw std::bad_alloc if allocation for string value fails (thrown by - the constructor of @ref json_value) + @throw std::bad_alloc if allocation for string value fails @liveexample{The following code shows the constructor with string literal parameter.,basic_json__string_t_value_type} @@ -688,8 +689,7 @@ class basic_json @complexity Linear in the size of the passed @a value. - @throw std::bad_alloc if allocation for string value fails (thrown by - the constructor of @ref json_value) + @throw std::bad_alloc if allocation for string value fails @liveexample{The following code shows the construction of a string value from a compatible type.,basic_json__CompatibleStringType} @@ -1432,7 +1432,14 @@ class basic_json return ss.str(); } - /// return the type of the object (explicit) + /*! + @brief return the type of the JSON value (explicit) + + Return the type of the JSON value as a value from the @ref value_t + enumeration. + + @return the type of the JSON value + */ value_t type() const noexcept { return m_type; @@ -2179,7 +2186,26 @@ class basic_json return m_value.array->operator[](idx); } - /// access specified element + /*! + @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 + + @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} + */ reference operator[](const typename object_t::key_type& key) { // implicitly convert null to object @@ -2200,7 +2226,22 @@ class basic_json return m_value.object->operator[](key); } - /// access specified element + /*! + @brief access specified object element + + Returns a reference to the element at with specified key @a key. + + @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 + + @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} + */ const_reference operator[](const typename object_t::key_type& key) const { // at only works for objects @@ -2212,7 +2253,28 @@ class basic_json return m_value.object->operator[](key); } - /// access specified element (needed for clang) + /*! + @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. + + @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 + + @throw std::domain_error if JSON is not an object or 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} + */ template reference operator[](const T (&key)[n]) { @@ -2232,7 +2294,24 @@ class basic_json return m_value.object->operator[](key); } - /// access specified element (needed for clang) + /*! + @brief access specified object element + + Returns a reference to the element at with specified key @a key. + + @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 + + @throw std::domain_error if JSON is not an object or 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} + */ template const_reference operator[](const T (&key)[n]) const { diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c index fed27c1d..fee97cd8 100644 --- a/src/json.hpp.re2c +++ b/src/json.hpp.re2c @@ -120,7 +120,6 @@ template < > class basic_json { - public: ///////////////////// // container types // ///////////////////// @@ -128,9 +127,12 @@ class basic_json /// @name container types /// @{ + private: + /// workaround type for MSVC using __basic_json = basic_json; + public: /// the type of elements in a basic_json container using value_type = basic_json; @@ -208,8 +210,10 @@ class basic_json /*! @brief the JSON value type enumeration - This enumeration collects the different JSON value types. It is used to - distinguish the stored values in the union @ref json_value. + This enumeration collects the different JSON value types. It is internally + used to distinguish the stored values, and the functions is_null, + is_object, is_array, is_string, is_boolean, is_number, and is_discarded + rely on it. */ enum class value_t : uint8_t { @@ -224,6 +228,7 @@ class basic_json }; + private: //////////////////////// // JSON value storage // //////////////////////// @@ -332,6 +337,8 @@ class basic_json } }; + + public: ////////////////////////// // JSON parser callback // ////////////////////////// @@ -462,7 +469,7 @@ class basic_json @complexity Constant. @throw std::bad_alloc if allocation for object, array, or string value - fails (thrown by the constructors of @ref json_value) + fails @liveexample{The following code shows the constructor for different @ref value_t values,basic_json__value_t} @@ -520,8 +527,7 @@ class basic_json @complexity Linear in the size of the passed @a value. - @throw std::bad_alloc if allocation for object value fails (thrown by - the constructor of @ref json_value) + @throw std::bad_alloc if allocation for object value fails @liveexample{The following code shows the constructor with an @ref object_t parameter.,basic_json__object_t} @@ -546,8 +552,7 @@ class basic_json @complexity Linear in the size of the passed @a value. - @throw std::bad_alloc if allocation for object value fails (thrown by - the constructor of @ref json_value) + @throw std::bad_alloc if allocation for object value fails @liveexample{The following code shows the constructor with several compatible object type parameters.,basic_json__CompatibleObjectType} @@ -578,8 +583,7 @@ class basic_json @complexity Linear in the size of the passed @a value. - @throw std::bad_alloc if allocation for array value fails (thrown by - the constructor of @ref json_value) + @throw std::bad_alloc if allocation for array value fails @liveexample{The following code shows the constructor with an @ref array_t parameter.,basic_json__array_t} @@ -604,8 +608,7 @@ class basic_json @complexity Linear in the size of the passed @a value. - @throw std::bad_alloc if allocation for array value fails (thrown by - the constructor of @ref json_value) + @throw std::bad_alloc if allocation for array value fails @liveexample{The following code shows the constructor with several compatible array type parameters.,basic_json__CompatibleArrayType} @@ -641,8 +644,7 @@ class basic_json @complexity Linear in the size of the passed @a value. - @throw std::bad_alloc if allocation for string value fails (thrown by - the constructor of @ref json_value) + @throw std::bad_alloc if allocation for string value fails @liveexample{The following code shows the constructor with an @ref string_t parameter.,basic_json__string_t} @@ -663,8 +665,7 @@ class basic_json @complexity Linear in the size of the passed @a value. - @throw std::bad_alloc if allocation for string value fails (thrown by - the constructor of @ref json_value) + @throw std::bad_alloc if allocation for string value fails @liveexample{The following code shows the constructor with string literal parameter.,basic_json__string_t_value_type} @@ -688,8 +689,7 @@ class basic_json @complexity Linear in the size of the passed @a value. - @throw std::bad_alloc if allocation for string value fails (thrown by - the constructor of @ref json_value) + @throw std::bad_alloc if allocation for string value fails @liveexample{The following code shows the construction of a string value from a compatible type.,basic_json__CompatibleStringType} @@ -1432,7 +1432,14 @@ class basic_json return ss.str(); } - /// return the type of the object (explicit) + /*! + @brief return the type of the JSON value (explicit) + + Return the type of the JSON value as a value from the @ref value_t + enumeration. + + @return the type of the JSON value + */ value_t type() const noexcept { return m_type; @@ -2179,7 +2186,26 @@ class basic_json return m_value.array->operator[](idx); } - /// access specified element + /*! + @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 + + @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} + */ reference operator[](const typename object_t::key_type& key) { // implicitly convert null to object @@ -2200,7 +2226,22 @@ class basic_json return m_value.object->operator[](key); } - /// access specified element + /*! + @brief access specified object element + + Returns a reference to the element at with specified key @a key. + + @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 + + @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} + */ const_reference operator[](const typename object_t::key_type& key) const { // at only works for objects @@ -2212,7 +2253,28 @@ class basic_json return m_value.object->operator[](key); } - /// access specified element (needed for clang) + /*! + @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. + + @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 + + @throw std::domain_error if JSON is not an object or 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} + */ template reference operator[](const T (&key)[n]) { @@ -2232,7 +2294,24 @@ class basic_json return m_value.object->operator[](key); } - /// access specified element (needed for clang) + /*! + @brief access specified object element + + Returns a reference to the element at with specified key @a key. + + @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 + + @throw std::domain_error if JSON is not an object or 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} + */ template const_reference operator[](const T (&key)[n]) const { diff --git a/test/unit.cpp b/test/unit.cpp index a960b2be..9d8fb68b 100644 --- a/test/unit.cpp +++ b/test/unit.cpp @@ -8953,6 +8953,76 @@ TEST_CASE("compliance tests from nativejson-benchmark") } } +TEST_CASE("RFC 7159 examples") +{ + // here, we list all JSON values from the RFC 7159 document + + SECTION("7. Strings") + { + CHECK(json::parse("\"\\u005C\"") == json("\\")); + CHECK(json::parse("\"\\uD834\\uDD1E\"") == json("𝄞")); + } + + SECTION("8.3 String Comparison") + { + CHECK(json::parse("\"a\\b\"") == json::parse("\"a\u005Cb\"")); + } + + SECTION("13 Examples") + { + { + auto string1 = R"( + { + "Image": { + "Width": 800, + "Height": 600, + "Title": "View from 15th Floor", + "Thumbnail": { + "Url": "http://www.example.com/image/481989943", + "Height": 125, + "Width": 100 + }, + "Animated" : false, + "IDs": [116, 943, 234, 38793] + } + } + )"; + CHECK_NOTHROW(json(string1)); + } + + { + auto string2 = R"( + [ + { + "precision": "zip", + "Latitude": 37.7668, + "Longitude": -122.3959, + "Address": "", + "City": "SAN FRANCISCO", + "State": "CA", + "Zip": "94107", + "Country": "US" + }, + { + "precision": "zip", + "Latitude": 37.371991, + "Longitude": -122.026020, + "Address": "", + "City": "SUNNYVALE", + "State": "CA", + "Zip": "94085", + "Country": "US" + } + ])"; + CHECK_NOTHROW(json(string2)); + } + + CHECK(json::parse("\"Hello world!\"") == json("Hello world!")); + CHECK(json::parse("42") == json(42)); + CHECK(json::parse("true") == json(true)); + } +} + TEST_CASE("Unicode", "[hide]") { SECTION("full enumeration of Unicode codepoints")