/* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ | | |__ | | | | | | version 2.1.1 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . Copyright (c) 2013-2017 Niels Lohmann . Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef NLOHMANN_JSON_HPP #define NLOHMANN_JSON_HPP #include // all_of, copy, fill, find, for_each, none_of, remove, reverse, transform #include // array #include // assert #include // isdigit #include // and, not, or #include // isfinite, labs, ldexp, signbit #include // nullptr_t, ptrdiff_t, size_t #include // int64_t, uint64_t #include // abort, strtod, strtof, strtold, strtoul, strtoll, strtoull #include // strlen #include // forward_list #include // function, hash, less #include // initializer_list #include // setw #include // istream, ostream #include // advance, begin, back_inserter, bidirectional_iterator_tag, distance, end, inserter, iterator, iterator_traits, next, random_access_iterator_tag, reverse_iterator #include // numeric_limits #include // locale #include // map #include // addressof, allocator, allocator_traits, unique_ptr #include // accumulate #include // stringstream #include // domain_error, invalid_argument, out_of_range #include // getline, stoi, string, to_string #include // add_pointer, conditional, decay, enable_if, false_type, integral_constant, is_arithmetic, is_base_of, is_const, is_constructible, is_convertible, is_default_constructible, is_enum, is_floating_point, is_integral, is_nothrow_move_assignable, is_nothrow_move_constructible, is_pointer, is_reference, is_same, is_scalar, is_signed, remove_const, remove_cv, remove_pointer, remove_reference, true_type, underlying_type #include // declval, forward, make_pair, move, pair, swap #include // vector // exclude unsupported compilers #if defined(__clang__) #if (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) < \ 30400 #error \ "unsupported Clang version - see https://github.com/nlohmann/json#supported-compilers" #endif #elif defined(__GNUC__) #if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40900 #error \ "unsupported GCC version - see https://github.com/nlohmann/json#supported-compilers" #endif #endif // disable float-equal warnings on GCC/clang #if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wfloat-equal" #endif // disable documentation warnings on clang #if defined(__clang__) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wdocumentation" #endif // allow for portable deprecation warnings #if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) #define JSON_DEPRECATED __attribute__((deprecated)) #elif defined(_MSC_VER) #define JSON_DEPRECATED __declspec(deprecated) #else #define JSON_DEPRECATED #endif // allow to disable exceptions #if not defined(JSON_NOEXCEPTION) || defined(__EXCEPTIONS) #define JSON_THROW(exception) throw exception #define JSON_TRY try #define JSON_CATCH(exception) catch (exception) #else #define JSON_THROW(exception) std::abort() #define JSON_TRY if (true) #define JSON_CATCH(exception) if (false) #endif /*! @brief namespace for Niels Lohmann @see https://github.com/nlohmann @since version 1.0.0 */ namespace nlohmann { /*! @brief unnamed namespace with internal helper functions This namespace collects some functions that could not be defined inside the @ref basic_json class. @since version 2.1.0 */ namespace detail { /////////////////////////// // JSON type enumeration // /////////////////////////// /*! @brief the JSON type enumeration This enumeration collects the different JSON types. It is internally used to distinguish the stored values, and the functions @ref basic_json::is_null(), @ref basic_json::is_object(), @ref basic_json::is_array(), @ref basic_json::is_string(), @ref basic_json::is_boolean(), @ref basic_json::is_number() (with @ref basic_json::is_number_integer(), @ref basic_json::is_number_unsigned(), and @ref basic_json::is_number_float()), @ref basic_json::is_discarded(), @ref basic_json::is_primitive(), and @ref basic_json::is_structured() rely on it. @note There are three enumeration entries (number_integer, number_unsigned, and number_float), because the library distinguishes these three types for numbers: @ref basic_json::number_unsigned_t is used for unsigned integers, @ref basic_json::number_integer_t is used for signed integers, and @ref basic_json::number_float_t is used for floating-point numbers or to approximate integers which do not fit in the limits of their respective type. @sa @ref basic_json::basic_json(const value_t value_type) -- create a JSON value with the default value for a given type @since version 1.0.0 */ enum class value_t : uint8_t { null, ///< null value object, ///< object (unordered set of name/value pairs) array, ///< array (ordered collection of values) string, ///< string value boolean, ///< boolean value number_integer, ///< number value (signed integer) number_unsigned, ///< number value (unsigned integer) number_float, ///< number value (floating-point) discarded ///< discarded by the the parser callback function }; /*! @brief comparison operator for JSON types Returns an ordering that is similar to Python: - order: null < boolean < number < object < array < string - furthermore, each type is not smaller than itself @since version 1.0.0 */ inline bool operator<(const value_t lhs, const value_t rhs) noexcept { static constexpr std::array order = { { 0, // null 3, // object 4, // array 5, // string 1, // boolean 2, // integer 2, // unsigned 2, // float } }; // discarded values are not comparable if (lhs == value_t::discarded or rhs == value_t::discarded) { return false; } return order[static_cast(lhs)] < order[static_cast(rhs)]; } ///////////// // helpers // ///////////// // alias templates to reduce boilerplate template using enable_if_t = typename std::enable_if::type; template using uncvref_t = typename std::remove_cv::type>::type; // taken from http://stackoverflow.com/a/26936864/266378 template using is_unscoped_enum = std::integral_constant::value and std::is_enum::value>; /* Implementation of two C++17 constructs: conjunction, negation. This is needed to avoid evaluating all the traits in a condition For example: not std::is_same::value and has_value_type::value will not compile when T = void (on MSVC at least). Whereas conjunction>, has_value_type>::value will stop evaluating if negation<...>::value == false Please note that those constructs must be used with caution, since symbols can become very long quickly (which can slow down compilation and cause MSVC internal compiler errors). Only use it when you have to (see example ahead). */ template struct conjunction : std::true_type { }; template struct conjunction : B1 { }; template struct conjunction : std::conditional, B1>::type { }; template struct negation : std::integral_constant { }; // dispatch utility (taken from ranges-v3) template struct priority_tag : priority_tag { }; template <> struct priority_tag<0> { }; ////////////////// // constructors // ////////////////// template struct external_constructor; template <> struct external_constructor { template static void construct(BasicJsonType &j, typename BasicJsonType::boolean_t b) noexcept { j.m_type = value_t::boolean; j.m_value = b; j.assert_invariant(); } }; template <> struct external_constructor { template static void construct(BasicJsonType &j, const typename BasicJsonType::string_t &s) { j.m_type = value_t::string; j.m_value = s; j.assert_invariant(); } }; template <> struct external_constructor { template static void construct(BasicJsonType &j, typename BasicJsonType::number_float_t val) noexcept { // replace infinity and NAN by null if (not std::isfinite(val)) { j = BasicJsonType{}; } else { j.m_type = value_t::number_float; j.m_value = val; } j.assert_invariant(); } }; template <> struct external_constructor { template static void construct(BasicJsonType &j, typename BasicJsonType::number_unsigned_t val) noexcept { j.m_type = value_t::number_unsigned; j.m_value = val; j.assert_invariant(); } }; template <> struct external_constructor { template static void construct(BasicJsonType &j, typename BasicJsonType::number_integer_t val) noexcept { j.m_type = value_t::number_integer; j.m_value = val; j.assert_invariant(); } }; template <> struct external_constructor { template static void construct(BasicJsonType &j, const typename BasicJsonType::array_t &arr) { j.m_type = value_t::array; j.m_value = arr; j.assert_invariant(); } template < typename BasicJsonType, typename CompatibleArrayType, enable_if_t::value, int> = 0> static void construct(BasicJsonType &j, const CompatibleArrayType &arr) { using std::begin; using std::end; j.m_type = value_t::array; j.m_value.array = j.template create( begin(arr), end(arr)); j.assert_invariant(); } }; template <> struct external_constructor { template static void construct(BasicJsonType &j, const typename BasicJsonType::object_t &obj) { j.m_type = value_t::object; j.m_value = obj; j.assert_invariant(); } template < typename BasicJsonType, typename CompatibleObjectType, enable_if_t::value, int> = 0> static void construct(BasicJsonType &j, const CompatibleObjectType &obj) { using std::begin; using std::end; j.m_type = value_t::object; j.m_value.object = j.template create( begin(obj), end(obj)); j.assert_invariant(); } }; //////////////////////// // has_/is_ functions // //////////////////////// /*! @brief Helper to determine whether there's a key_type for T. This helper is used to tell associative containers apart from other containers such as sequence containers. For instance, `std::map` passes the test as it contains a `mapped_type`, whereas `std::vector` fails the test. @sa http://stackoverflow.com/a/7728728/266378 @since version 1.0.0, overworked in version 2.0.6 */ #define NLOHMANN_JSON_HAS_HELPER(type) \ template struct has_##type \ { \ private: \ template \ static int detect(U &&); \ static void detect(...); \ \ public: \ static constexpr bool value = \ std::is_integral()))>::value; \ } NLOHMANN_JSON_HAS_HELPER(mapped_type); NLOHMANN_JSON_HAS_HELPER(key_type); NLOHMANN_JSON_HAS_HELPER(value_type); NLOHMANN_JSON_HAS_HELPER(iterator); #undef NLOHMANN_JSON_HAS_HELPER template struct is_compatible_object_type_impl : std::false_type { }; template struct is_compatible_object_type_impl { static constexpr auto value = std::is_constructible< typename RealType::key_type, typename CompatibleObjectType::key_type>::value and std::is_constructible< typename RealType::mapped_type, typename CompatibleObjectType::mapped_type>::value; }; template struct is_compatible_object_type { static auto constexpr value = is_compatible_object_type_impl< conjunction>, has_mapped_type, has_key_type>::value, typename BasicJsonType::object_t, CompatibleObjectType>::value; }; template struct is_basic_json_nested_type { static auto constexpr value = std::is_same::value or std::is_same::value or std::is_same::value or std::is_same::value or std::is_same::value; }; template struct is_compatible_array_type { static auto constexpr value = conjunction< negation>, negation>, negation>, negation>, has_value_type, has_iterator>::value; }; template struct is_compatible_integer_type_impl : std::false_type { }; template struct is_compatible_integer_type_impl { // is there an assert somewhere on overflows? using RealLimits = std::numeric_limits; using CompatibleLimits = std::numeric_limits; static constexpr auto value = std::is_constructible::value and CompatibleLimits::is_integer and RealLimits::is_signed == CompatibleLimits::is_signed; }; template struct is_compatible_integer_type { static constexpr auto value = is_compatible_integer_type_impl < std::is_integral::value and not std::is_same::value, RealIntegerType, CompatibleNumberIntegerType > ::value; }; // trait checking if JSONSerializer::from_json(json const&, udt&) exists template struct has_from_json { private: // also check the return type of from_json template ::from_json( std::declval(), std::declval()))>::value>> static int detect(U &&); static void detect(...); public: static constexpr bool value = std::is_integral>()))>::value; }; // This trait checks if JSONSerializer::from_json(json const&) exists // this overload is used for non-default-constructible user-defined-types template struct has_non_default_from_json { private: template ::from_json( std::declval()))>::value>> static int detect(U &&); static void detect(...); public: static constexpr bool value = std::is_integral>()))>::value; }; // This trait checks if BasicJsonType::json_serializer::to_json exists template struct has_to_json { private: template ::to_json( std::declval(), std::declval()))> static int detect(U &&); static void detect(...); public: static constexpr bool value = std::is_integral>()))>::value; }; ///////////// // to_json // ///////////// template ::value, int> = 0> void to_json(BasicJsonType &j, T b) noexcept { external_constructor::construct(j, b); } template ::value, int> = 0> void to_json(BasicJsonType &j, const CompatibleString &s) { external_constructor::construct(j, s); } template ::value, int> = 0> void to_json(BasicJsonType &j, FloatType val) noexcept { external_constructor::construct( j, static_cast(val)); } template ::value, int> = 0> void to_json(BasicJsonType &j, CompatibleNumberUnsignedType val) noexcept { external_constructor::construct( j, static_cast(val)); } template ::value, int> = 0> void to_json(BasicJsonType &j, CompatibleNumberIntegerType val) noexcept { external_constructor::construct( j, static_cast(val)); } template ::value, int> = 0> void to_json(BasicJsonType &j, UnscopedEnumType e) noexcept { external_constructor::construct(j, e); } template ::value or std::is_same::value, int> = 0> void to_json(BasicJsonType &j, const CompatibleArrayType &arr) { external_constructor::construct(j, arr); } template ::value, int> = 0> void to_json(BasicJsonType &j, const CompatibleObjectType &arr) { external_constructor::construct(j, arr); } /////////////// // from_json // /////////////// // overloads for basic_json template parameters template < typename BasicJsonType, typename ArithmeticType, enable_if_t::value and not std::is_same::value, int> = 0> void get_arithmetic_value(const BasicJsonType &j, ArithmeticType &val) { switch (static_cast(j)) { case value_t::number_unsigned: { val = static_cast( *j.template get_ptr< const typename BasicJsonType::number_unsigned_t *>()); break; } case value_t::number_integer: { val = static_cast( *j.template get_ptr< const typename BasicJsonType::number_integer_t *>()); break; } case value_t::number_float: { val = static_cast( *j.template get_ptr< const typename BasicJsonType::number_float_t *>()); break; } default: { JSON_THROW( std::domain_error("type must be number, but is " + j.type_name())); } } } template void from_json(const BasicJsonType &j, typename BasicJsonType::boolean_t &b) { if (not j.is_boolean()) { JSON_THROW( std::domain_error("type must be boolean, but is " + j.type_name())); } b = *j.template get_ptr(); } template void from_json(const BasicJsonType &j, typename BasicJsonType::string_t &s) { if (not j.is_string()) { JSON_THROW( std::domain_error("type must be string, but is " + j.type_name())); } s = *j.template get_ptr(); } template void from_json(const BasicJsonType &j, typename BasicJsonType::number_float_t &val) { get_arithmetic_value(j, val); } template void from_json(const BasicJsonType &j, typename BasicJsonType::number_unsigned_t &val) { get_arithmetic_value(j, val); } template void from_json(const BasicJsonType &j, typename BasicJsonType::number_integer_t &val) { get_arithmetic_value(j, val); } template ::value, int> = 0> void from_json(const BasicJsonType &j, UnscopedEnumType &e) { typename std::underlying_type::type val; get_arithmetic_value(j, val); e = static_cast(val); } template void from_json(const BasicJsonType &j, typename BasicJsonType::array_t &arr) { if (not j.is_array()) { JSON_THROW( std::domain_error("type must be array, but is " + j.type_name())); } arr = *j.template get_ptr(); } // forward_list doesn't have an insert method template void from_json(const BasicJsonType &j, std::forward_list &l) { // do not perform the check when user wants to retrieve jsons // (except when it's null.. ?) if (j.is_null()) { JSON_THROW( std::domain_error("type must be array, but is " + j.type_name())); } if (not std::is_same::value) { if (not j.is_array()) { JSON_THROW(std::domain_error("type must be array, but is " + j.type_name())); } } for (auto it = j.rbegin(), end = j.rend(); it != end; ++it) { l.push_front(it->template get()); } } template void from_json_array_impl(const BasicJsonType &j, CompatibleArrayType &arr, priority_tag<0>) { using std::begin; using std::end; std::transform( j.begin(), j.end(), std::inserter(arr, end(arr)), [](const BasicJsonType &i) { // get() returns *this, this won't call a from_json // method when value_type is BasicJsonType return i.template get(); }); } template auto from_json_array_impl(const BasicJsonType &j, CompatibleArrayType &arr, priority_tag<1>) -> decltype( arr.reserve(std::declval()), void()) { using std::begin; using std::end; arr.reserve(j.size()); std::transform( j.begin(), j.end(), std::inserter(arr, end(arr)), [](const BasicJsonType &i) { // get() returns *this, this won't call a from_json // method when value_type is BasicJsonType return i.template get(); }); } template ::value and not std::is_same::value, int> = 0> void from_json(const BasicJsonType &j, CompatibleArrayType &arr) { if (j.is_null()) { JSON_THROW( std::domain_error("type must be array, but is " + j.type_name())); } // when T == BasicJsonType, do not check if value_t is correct if (not std::is_same::value) { if (not j.is_array()) { JSON_THROW(std::domain_error("type must be array, but is " + j.type_name())); } } from_json_array_impl(j, arr, priority_tag<1>{}); } template ::value, int> = 0> void from_json(const BasicJsonType &j, CompatibleObjectType &obj) { if (not j.is_object()) { JSON_THROW( std::domain_error("type must be object, but is " + j.type_name())); } auto inner_object = j.template get_ptr(); using std::begin; using std::end; // we could avoid the assignment, but this might require a for loop, which // might be less efficient than the container constructor for some // containers (would it?) obj = CompatibleObjectType(begin(*inner_object), end(*inner_object)); } // overload for arithmetic types, not chosen for basic_json template arguments // (BooleanType, etc..); note: Is it really necessary to provide explicit // overloads for boolean_t etc. in case of a custom BooleanType which is not // an arithmetic type? template < typename BasicJsonType, typename ArithmeticType, enable_if_t< std::is_arithmetic::value and not std::is_same::value and not std::is_same::value and not std::is_same::value and not std::is_same::value, int> = 0> void from_json(const BasicJsonType &j, ArithmeticType &val) { switch (static_cast(j)) { case value_t::number_unsigned: { val = static_cast( *j.template get_ptr< const typename BasicJsonType::number_unsigned_t *>()); break; } case value_t::number_integer: { val = static_cast( *j.template get_ptr< const typename BasicJsonType::number_integer_t *>()); break; } case value_t::number_float: { val = static_cast( *j.template get_ptr< const typename BasicJsonType::number_float_t *>()); break; } case value_t::boolean: { val = static_cast( *j.template get_ptr()); break; } default: { JSON_THROW( std::domain_error("type must be number, but is " + j.type_name())); } } } struct to_json_fn { private: template auto call(BasicJsonType &j, T &&val, priority_tag<1>) const noexcept(noexcept(to_json(j, std::forward(val)))) -> decltype(to_json(j, std::forward(val)), void()) { return to_json(j, std::forward(val)); } template void call(BasicJsonType &, T &&, priority_tag<0>) const noexcept { static_assert(sizeof(BasicJsonType) == 0, "could not find to_json() method in T's namespace"); } public: template void operator()(BasicJsonType &j, T &&val) const noexcept(noexcept(std::declval().call(j, std::forward(val), priority_tag<1>{}))) { return call(j, std::forward(val), priority_tag<1>{}); } }; struct from_json_fn { private: template auto call(const BasicJsonType &j, T &val, priority_tag<1>) const noexcept(noexcept(from_json(j, val))) -> decltype(from_json(j, val), void()) { return from_json(j, val); } template void call(const BasicJsonType &, T &, priority_tag<0>) const noexcept { static_assert(sizeof(BasicJsonType) == 0, "could not find from_json() method in T's namespace"); } public: template void operator()(const BasicJsonType &j, T &val) const noexcept(noexcept(std::declval().call(j, val, priority_tag<1>{}))) { return call(j, val, priority_tag<1>{}); } }; // taken from ranges-v3 template struct static_const { static constexpr T value{}; }; template constexpr T static_const::value; } // namespace detail /// namespace to hold default `to_json` / `from_json` functions namespace { constexpr const auto &to_json = detail::static_const::value; constexpr const auto &from_json = detail::static_const::value; } /*! @brief default JSONSerializer template argument This serializer ignores the template arguments and uses ADL ([argument-dependent lookup](http://en.cppreference.com/w/cpp/language/adl)) for serialization. */ template struct adl_serializer { /*! @brief convert a JSON value to any value type This function is usually called by the `get()` function of the @ref basic_json class (either explicit or via conversion operators). @param[in] j JSON value to read from @param[in,out] val value to write to */ template static void from_json(BasicJsonType &&j, ValueType &val) noexcept( noexcept(::nlohmann::from_json(std::forward(j), val))) { ::nlohmann::from_json(std::forward(j), val); } /*! @brief convert any value type to a JSON value This function is usually called by the constructors of the @ref basic_json class. @param[in,out] j JSON value to write to @param[in] val value to read from */ template static void to_json(BasicJsonType &j, ValueType &&val) noexcept( noexcept(::nlohmann::to_json(j, std::forward(val)))) { ::nlohmann::to_json(j, std::forward(val)); } }; /*! @brief a class to store JSON values @tparam ObjectType type for JSON objects (`std::map` by default; will be used in @ref object_t) @tparam ArrayType type for JSON arrays (`std::vector` by default; will be used in @ref array_t) @tparam StringType type for JSON strings and object keys (`std::string` by default; will be used in @ref string_t) @tparam BooleanType type for JSON booleans (`bool` by default; will be used in @ref boolean_t) @tparam NumberIntegerType type for JSON integer numbers (`int64_t` by default; will be used in @ref number_integer_t) @tparam NumberUnsignedType type for JSON unsigned integer numbers (@c `uint64_t` by default; will be used in @ref number_unsigned_t) @tparam NumberFloatType type for JSON floating-point numbers (`double` by default; will be used in @ref number_float_t) @tparam AllocatorType type of the allocator to use (`std::allocator` by default) @tparam JSONSerializer the serializer to resolve internal calls to `to_json()` and `from_json()` (@ref adl_serializer by default) @requirement The class satisfies the following concept requirements: - Basic - [DefaultConstructible](http://en.cppreference.com/w/cpp/concept/DefaultConstructible): JSON values can be default constructed. The result will be a JSON null value. - [MoveConstructible](http://en.cppreference.com/w/cpp/concept/MoveConstructible): A JSON value can be constructed from an rvalue argument. - [CopyConstructible](http://en.cppreference.com/w/cpp/concept/CopyConstructible): A JSON value can be copy-constructed from an lvalue expression. - [MoveAssignable](http://en.cppreference.com/w/cpp/concept/MoveAssignable): A JSON value van be assigned from an rvalue argument. - [CopyAssignable](http://en.cppreference.com/w/cpp/concept/CopyAssignable): A JSON value can be copy-assigned from an lvalue expression. - [Destructible](http://en.cppreference.com/w/cpp/concept/Destructible): JSON values can be destructed. - Layout - [StandardLayoutType](http://en.cppreference.com/w/cpp/concept/StandardLayoutType): JSON values have [standard layout](http://en.cppreference.com/w/cpp/language/data_members#Standard_layout): All non-static data members are private and standard layout types, the class has no virtual functions or (virtual) base classes. - Library-wide - [EqualityComparable](http://en.cppreference.com/w/cpp/concept/EqualityComparable): JSON values can be compared with `==`, see @ref operator==(const_reference,const_reference). - [LessThanComparable](http://en.cppreference.com/w/cpp/concept/LessThanComparable): JSON values can be compared with `<`, see @ref operator<(const_reference,const_reference). - [Swappable](http://en.cppreference.com/w/cpp/concept/Swappable): Any JSON lvalue or rvalue of can be swapped with any lvalue or rvalue of other compatible types, using unqualified function call @ref swap(). - [NullablePointer](http://en.cppreference.com/w/cpp/concept/NullablePointer): JSON values can be compared against `std::nullptr_t` objects which are used to model the `null` value. - Container - [Container](http://en.cppreference.com/w/cpp/concept/Container): JSON values can be used like STL containers and provide iterator access. - [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer); JSON values can be used like STL containers and provide reverse iterator access. @invariant The member variables @a m_value and @a m_type have the following relationship: - If `m_type == value_t::object`, then `m_value.object != nullptr`. - If `m_type == value_t::array`, then `m_value.array != nullptr`. - If `m_type == value_t::string`, then `m_value.string != nullptr`. The invariants are checked by member function assert_invariant(). @internal @note ObjectType trick from http://stackoverflow.com/a/9860911 @endinternal @see [RFC 7159: The JavaScript Object Notation (JSON) Data Interchange Format](http://rfc7159.net/rfc7159) @since version 1.0.0 @nosubgrouping */ template