From 3ffedea5c4cbefcf0480e0d7357be09227ea9f03 Mon Sep 17 00:00:00 2001
From: Niels <niels.lohmann@gmail.com>
Date: Thu, 25 Jun 2015 00:40:16 +0200
Subject: [PATCH] minor changes

---
 doc/examples/operatorarray__key_type.cpp      |  30 +++++
 doc/examples/operatorarray__key_type.output   |  19 +++
 .../operatorarray__key_type_const.cpp         |  15 +++
 .../operatorarray__key_type_const.output      |   1 +
 src/json.hpp                                  | 125 ++++++++++++++----
 src/json.hpp.re2c                             | 125 ++++++++++++++----
 test/unit.cpp                                 |  70 ++++++++++
 7 files changed, 339 insertions(+), 46 deletions(-)
 create mode 100644 doc/examples/operatorarray__key_type.cpp
 create mode 100644 doc/examples/operatorarray__key_type.output
 create mode 100644 doc/examples/operatorarray__key_type_const.cpp
 create mode 100644 doc/examples/operatorarray__key_type_const.output

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 <json.hpp>
+
+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 <json.hpp>
+
+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<ObjectType, ArrayType, StringType, BooleanType, NumberIntegerType, NumberFloatType, AllocatorType>;
 
+  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<typename T, std::size_t n>
     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<typename T, std::size_t n>
     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<ObjectType, ArrayType, StringType, BooleanType, NumberIntegerType, NumberFloatType, AllocatorType>;
 
+  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<typename T, std::size_t n>
     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<typename T, std::size_t n>
     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")