diff --git a/resources/3rdparty/modernjson/src/json.hpp b/resources/3rdparty/modernjson/src/json.hpp index 8469a499f..596095aff 100755 --- a/resources/3rdparty/modernjson/src/json.hpp +++ b/resources/3rdparty/modernjson/src/json.hpp @@ -1,7 +1,7 @@ /* __ _____ _____ _____ __| | __| | | | JSON for Modern C++ -| | |__ | | | | | | version 2.0.5 +| | |__ | | | | | | version 2.0.7 |_____|_____|_____|_|___| https://github.com/nlohmann/json Licensed under the MIT License . @@ -29,56 +29,57 @@ SOFTWARE. #ifndef NLOHMANN_JSON_HPP #define NLOHMANN_JSON_HPP -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include // all_of, for_each, transform +#include // array +#include // assert +#include // isdigit +#include // and, not, or +#include // isfinite, signbit +#include // nullptr_t, ptrdiff_t, size_t +#include // int64_t, uint64_t +#include // strtod, strtof, strtold, strtoul +#include // strlen +#include // function, hash, less +#include // initializer_list +#include // setw +#include // istream, ostream +#include // advance, begin, bidirectional_iterator_tag, distance, end, inserter, iterator, iterator_traits, next, random_access_iterator_tag, reverse_iterator +#include // numeric_limits +#include // locale, numpunct +#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, enable_if, is_arithmetic, is_base_of, is_const, is_constructible, is_convertible, is_floating_point, is_integral, is_nothrow_move_assignable, std::is_nothrow_move_constructible, std::is_pointer, std::is_reference, std::is_same, remove_const, remove_pointer, remove_reference +#include // declval, forward, make_pair, move, pair, swap +#include // vector // exclude unsupported compilers #if defined(__clang__) - #define CLANG_VERSION (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) +#define CLANG_VERSION (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) #if CLANG_VERSION < 30400 #error "unsupported Clang version - see https://github.com/nlohmann/json#supported-compilers" #endif #elif defined(__GNUC__) - #define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) - #if GCC_VERSION < 40900 - #error "unsupported GCC version - see https://github.com/nlohmann/json#supported-compilers" - #endif +#define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) +#if GCC_VERSION < 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" +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wfloat-equal" #endif // allow for portable deprecation warnings #if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) - #define JSON_DEPRECATED __attribute__((deprecated)) +#define JSON_DEPRECATED //__attribute__((deprecated)) #elif defined(_MSC_VER) - #define JSON_DEPRECATED __declspec(deprecated) +#define JSON_DEPRECATED __declspec(deprecated) #else #define JSON_DEPRECATED #endif @@ -96,8 +97,8 @@ namespace nlohmann @brief unnamed namespace with internal helper functions @since version 1.0.0 */ -namespace -{ + namespace + { /*! @brief Helper to determine whether there's a key_type for T. @@ -106,17 +107,20 @@ 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 +@since version 1.0.0, overworked in version 2.0.6 */ -template -struct has_mapped_type -{ - private: - template static char test(typename C::mapped_type*); - template static char (&test(...))[2]; - public: - static constexpr bool value = sizeof(test(0)) == 1; -}; + template + struct has_mapped_type + { + private: + template + static int detect(U&&); + + static void detect(...); + public: + static constexpr bool value = + std::is_integral()))>::value; + }; /*! @brief helper class to create locales with decimal point @@ -130,15 +134,15 @@ and fractional parts. @sa https://github.com/nlohmann/json/issues/51#issuecomment-86869315 @since version 2.0.0 */ -struct DecimalSeparator : std::numpunct -{ - char do_decimal_point() const - { - return '.'; - } -}; + struct DecimalSeparator : std::numpunct + { + char do_decimal_point() const + { + return '.'; + } + }; -} + } /*! @brief a class to store JSON values @@ -218,90 +222,90 @@ Format](http://rfc7159.net/rfc7159) @nosubgrouping */ -template < - template class ObjectType = std::map, - template class ArrayType = std::vector, - class StringType = std::string, - class BooleanType = bool, - class NumberIntegerType = std::int64_t, - class NumberUnsignedType = std::uint64_t, - class NumberFloatType = double, - template class AllocatorType = std::allocator + template < + template class ObjectType = std::map, + template class ArrayType = std::vector, + class StringType = std::string, + class BooleanType = bool, + class NumberIntegerType = std::int64_t, + class NumberUnsignedType = std::uint64_t, + class NumberFloatType = double, + template class AllocatorType = std::allocator > -class basic_json -{ - private: - /// workaround type for MSVC - using basic_json_t = basic_json; - - public: - // forward declarations - template class json_reverse_iterator; - class json_pointer; - - ///////////////////// - // container types // - ///////////////////// - - /// @name container types - /// The canonic container types to use @ref basic_json like any other STL - /// container. - /// @{ - - /// the type of elements in a basic_json container - using value_type = basic_json; - - /// the type of an element reference - using reference = value_type&; - /// the type of an element const reference - using const_reference = const value_type&; - - /// a type to represent differences between iterators - using difference_type = std::ptrdiff_t; - /// a type to represent container sizes - using size_type = std::size_t; - - /// the allocator type - using allocator_type = AllocatorType; - - /// the type of an element pointer - using pointer = typename std::allocator_traits::pointer; - /// the type of an element const pointer - using const_pointer = typename std::allocator_traits::const_pointer; - - /// an iterator for a basic_json container - class iterator; - /// a const iterator for a basic_json container - class const_iterator; - /// a reverse iterator for a basic_json container - using reverse_iterator = json_reverse_iterator; - /// a const reverse iterator for a basic_json container - using const_reverse_iterator = json_reverse_iterator; - - /// @} - - - /*! + class basic_json + { + private: + /// workaround type for MSVC + using basic_json_t = basic_json; + + public: + // forward declarations + template class json_reverse_iterator; + class json_pointer; + + ///////////////////// + // container types // + ///////////////////// + + /// @name container types + /// The canonic container types to use @ref basic_json like any other STL + /// container. + /// @{ + + /// the type of elements in a basic_json container + using value_type = basic_json; + + /// the type of an element reference + using reference = value_type&; + /// the type of an element const reference + using const_reference = const value_type&; + + /// a type to represent differences between iterators + using difference_type = std::ptrdiff_t; + /// a type to represent container sizes + using size_type = std::size_t; + + /// the allocator type + using allocator_type = AllocatorType; + + /// the type of an element pointer + using pointer = typename std::allocator_traits::pointer; + /// the type of an element const pointer + using const_pointer = typename std::allocator_traits::const_pointer; + + /// an iterator for a basic_json container + class iterator; + /// a const iterator for a basic_json container + class const_iterator; + /// a reverse iterator for a basic_json container + using reverse_iterator = json_reverse_iterator; + /// a const reverse iterator for a basic_json container + using const_reverse_iterator = json_reverse_iterator; + + /// @} + + + /*! @brief returns the allocator associated with the container */ - static allocator_type get_allocator() - { - return allocator_type(); - } + static allocator_type get_allocator() + { + return allocator_type(); + } - /////////////////////////// - // JSON value data types // - /////////////////////////// + /////////////////////////// + // JSON value data types // + /////////////////////////// - /// @name JSON value data types - /// The data types to store a JSON value. These types are derived from - /// the template arguments passed to class @ref basic_json. - /// @{ + /// @name JSON value data types + /// The data types to store a JSON value. These types are derived from + /// the template arguments passed to class @ref basic_json. + /// @{ - /*! + /*! @brief a type for an object [RFC 7159](http://rfc7159.net/rfc7159) describes JSON objects as follows: @@ -384,13 +388,13 @@ class basic_json 7159](http://rfc7159.net/rfc7159), because any order implements the specified "unordered" nature of JSON objects. */ - using object_t = ObjectType, - AllocatorType>>; + using object_t = ObjectType, + AllocatorType>>; - /*! + /*! @brief a type for an array [RFC 7159](http://rfc7159.net/rfc7159) describes JSON arrays as follows: @@ -434,9 +438,9 @@ class basic_json @since version 1.0.0 */ - using array_t = ArrayType>; + using array_t = ArrayType>; - /*! + /*! @brief a type for a string [RFC 7159](http://rfc7159.net/rfc7159) describes JSON strings as follows: @@ -481,9 +485,9 @@ class basic_json @since version 1.0.0 */ - using string_t = StringType; + using string_t = StringType; - /*! + /*! @brief a type for a boolean [RFC 7159](http://rfc7159.net/rfc7159) implicitly describes a boolean as a @@ -507,9 +511,9 @@ class basic_json @since version 1.0.0 */ - using boolean_t = BooleanType; + using boolean_t = BooleanType; - /*! + /*! @brief a type for a number (integer) [RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows: @@ -579,9 +583,9 @@ class basic_json @since version 1.0.0 */ - using number_integer_t = NumberIntegerType; + using number_integer_t = NumberIntegerType; - /*! + /*! @brief a type for a number (unsigned) [RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows: @@ -650,9 +654,9 @@ class basic_json @since version 2.0.0 */ - using number_unsigned_t = NumberUnsignedType; + using number_unsigned_t = NumberUnsignedType; - /*! + /*! @brief a type for a number (floating-point) [RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows: @@ -718,16 +722,16 @@ class basic_json @since version 1.0.0 */ - using number_float_t = NumberFloatType; + using number_float_t = NumberFloatType; - /// @} + /// @} - /////////////////////////// - // JSON type enumeration // - /////////////////////////// + /////////////////////////// + // JSON type enumeration // + /////////////////////////// - /*! + /*! @brief the JSON type enumeration This enumeration collects the different JSON types. It is internally used @@ -749,42 +753,42 @@ class basic_json @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 - }; + 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 + }; - private: + private: - /// helper for exception-safe object creation - template - static T* create(Args&& ... args) - { - AllocatorType alloc; - auto deleter = [&](T * object) + /// helper for exception-safe object creation + template + static T* create(Args&& ... args) { - alloc.deallocate(object, 1); - }; - std::unique_ptr object(alloc.allocate(1), deleter); - alloc.construct(object.get(), std::forward(args)...); - assert(object.get() != nullptr); - return object.release(); - } + AllocatorType alloc; + auto deleter = [&](T * object) + { + alloc.deallocate(object, 1); + }; + std::unique_ptr object(alloc.allocate(1), deleter); + alloc.construct(object.get(), std::forward(args)...); + assert(object.get() != nullptr); + return object.release(); + } - //////////////////////// - // JSON value storage // - //////////////////////// + //////////////////////// + // JSON value storage // + //////////////////////// - /*! + /*! @brief a JSON value The actual storage for a JSON value of the @ref basic_json class. This @@ -808,107 +812,107 @@ class basic_json @since version 1.0.0 */ - union json_value - { - /// object (stored with pointer to save storage) - object_t* object; - /// array (stored with pointer to save storage) - array_t* array; - /// string (stored with pointer to save storage) - string_t* string; - /// boolean - boolean_t boolean; - /// number (integer) - number_integer_t number_integer; - /// number (unsigned integer) - number_unsigned_t number_unsigned; - /// number (floating-point) - number_float_t number_float; - - /// default constructor (for null values) - json_value() = default; - /// constructor for booleans - json_value(boolean_t v) noexcept : boolean(v) {} - /// constructor for numbers (integer) - json_value(number_integer_t v) noexcept : number_integer(v) {} - /// constructor for numbers (unsigned) - json_value(number_unsigned_t v) noexcept : number_unsigned(v) {} - /// constructor for numbers (floating-point) - json_value(number_float_t v) noexcept : number_float(v) {} - /// constructor for empty values of a given type - json_value(value_t t) - { - switch (t) - { - case value_t::object: + union json_value + { + /// object (stored with pointer to save storage) + object_t* object; + /// array (stored with pointer to save storage) + array_t* array; + /// string (stored with pointer to save storage) + string_t* string; + /// boolean + boolean_t boolean; + /// number (integer) + number_integer_t number_integer; + /// number (unsigned integer) + number_unsigned_t number_unsigned; + /// number (floating-point) + number_float_t number_float; + + /// default constructor (for null values) + json_value() = default; + /// constructor for booleans + json_value(boolean_t v) noexcept : boolean(v) {} + /// constructor for numbers (integer) + json_value(number_integer_t v) noexcept : number_integer(v) {} + /// constructor for numbers (unsigned) + json_value(number_unsigned_t v) noexcept : number_unsigned(v) {} + /// constructor for numbers (floating-point) + json_value(number_float_t v) noexcept : number_float(v) {} + /// constructor for empty values of a given type + json_value(value_t t) + { + switch (t) { - object = create(); - break; - } + case value_t::object: + { + object = create(); + break; + } - case value_t::array: - { - array = create(); - break; - } + case value_t::array: + { + array = create(); + break; + } - case value_t::string: - { - string = create(""); - break; - } + case value_t::string: + { + string = create(""); + break; + } - case value_t::boolean: - { - boolean = boolean_t(false); - break; - } + case value_t::boolean: + { + boolean = boolean_t(false); + break; + } - case value_t::number_integer: - { - number_integer = number_integer_t(0); - break; - } + case value_t::number_integer: + { + number_integer = number_integer_t(0); + break; + } - case value_t::number_unsigned: - { - number_unsigned = number_unsigned_t(0); - break; - } + case value_t::number_unsigned: + { + number_unsigned = number_unsigned_t(0); + break; + } - case value_t::number_float: - { - number_float = number_float_t(0.0); - break; - } + case value_t::number_float: + { + number_float = number_float_t(0.0); + break; + } - default: - { - break; + default: + { + break; + } } } - } - /// constructor for strings - json_value(const string_t& value) - { - string = create(value); - } + /// constructor for strings + json_value(const string_t& value) + { + string = create(value); + } - /// constructor for objects - json_value(const object_t& value) - { - object = create(value); - } + /// constructor for objects + json_value(const object_t& value) + { + object = create(value); + } - /// constructor for arrays - json_value(const array_t& value) - { - array = create(value); - } - }; + /// constructor for arrays + json_value(const array_t& value) + { + array = create(value); + } + }; - /*! + /*! @brief checks the class invariants This function asserts the class invariants. It needs to be called at the @@ -917,19 +921,19 @@ class basic_json value is changed, because the invariant expresses a relationship between @a m_type and @a m_value. */ - void assert_invariant() const - { - assert(m_type != value_t::object or m_value.object != nullptr); - assert(m_type != value_t::array or m_value.array != nullptr); - assert(m_type != value_t::string or m_value.string != nullptr); - } + void assert_invariant() const + { + assert(m_type != value_t::object or m_value.object != nullptr); + assert(m_type != value_t::array or m_value.array != nullptr); + assert(m_type != value_t::string or m_value.string != nullptr); + } - public: - ////////////////////////// - // JSON parser callback // - ////////////////////////// + public: + ////////////////////////// + // JSON parser callback // + ////////////////////////// - /*! + /*! @brief JSON callback events This enumeration lists the parser events that can trigger calling a @@ -939,23 +943,23 @@ class basic_json @since version 1.0.0 */ - enum class parse_event_t : uint8_t - { - /// the parser read `{` and started to process a JSON object - object_start, - /// the parser read `}` and finished processing a JSON object - object_end, - /// the parser read `[` and started to process a JSON array - array_start, - /// the parser read `]` and finished processing a JSON array - array_end, - /// the parser read a key of a value in an object - key, - /// the parser finished reading a JSON value - value - }; + enum class parse_event_t : uint8_t + { + /// the parser read `{` and started to process a JSON object + object_start, + /// the parser read `}` and finished processing a JSON object + object_end, + /// the parser read `[` and started to process a JSON array + array_start, + /// the parser read `]` and finished processing a JSON array + array_end, + /// the parser read a key of a value in an object + key, + /// the parser finished reading a JSON value + value + }; - /*! + /*! @brief per-element parser callback type With a parser callback function, the result of parsing a JSON text can be @@ -1007,21 +1011,21 @@ class basic_json @since version 1.0.0 */ - using parser_callback_t = std::function; + using parser_callback_t = std::function; - ////////////////// - // constructors // - ////////////////// + ////////////////// + // constructors // + ////////////////// - /// @name constructors and destructors - /// Constructors of class @ref basic_json, copy/move constructor, copy - /// assignment, static functions creating objects, and the destructor. - /// @{ + /// @name constructors and destructors + /// Constructors of class @ref basic_json, copy/move constructor, copy + /// assignment, static functions creating objects, and the destructor. + /// @{ - /*! + /*! @brief create an empty value with a given type Create an empty JSON value with a given type. The value will be default @@ -1060,13 +1064,13 @@ class basic_json @since version 1.0.0 */ - basic_json(const value_t value_type) - : m_type(value_type), m_value(value_type) - { - assert_invariant(); - } + basic_json(const value_t value_type) + : m_type(value_type), m_value(value_type) + { + assert_invariant(); + } - /*! + /*! @brief create a null object Create a `null` JSON value. It either takes a null pointer as parameter @@ -1084,13 +1088,13 @@ class basic_json @since version 1.0.0 */ - basic_json(std::nullptr_t = nullptr) noexcept - : basic_json(value_t::null) - { - assert_invariant(); - } + basic_json(std::nullptr_t = nullptr) noexcept + : basic_json(value_t::null) + { + assert_invariant(); + } - /*! + /*! @brief create an object (explicit) Create an object JSON value with a given content. @@ -1109,13 +1113,13 @@ class basic_json @since version 1.0.0 */ - basic_json(const object_t& val) - : m_type(value_t::object), m_value(val) - { - assert_invariant(); - } + basic_json(const object_t& val) + : m_type(value_t::object), m_value(val) + { + assert_invariant(); + } - /*! + /*! @brief create an object (implicit) Create an object JSON value with a given content. This constructor allows @@ -1141,19 +1145,19 @@ class basic_json @since version 1.0.0 */ - template::value and - std::is_constructible::value, int>::type = 0> - basic_json(const CompatibleObjectType& val) - : m_type(value_t::object) - { - using std::begin; - using std::end; - m_value.object = create(begin(val), end(val)); - assert_invariant(); - } + template::value and + std::is_constructible::value, int>::type = 0> + basic_json(const CompatibleObjectType& val) + : m_type(value_t::object) + { + using std::begin; + using std::end; + m_value.object = create(begin(val), end(val)); + assert_invariant(); + } - /*! + /*! @brief create an array (explicit) Create an array JSON value with a given content. @@ -1172,13 +1176,13 @@ class basic_json @since version 1.0.0 */ - basic_json(const array_t& val) - : m_type(value_t::array), m_value(val) - { - assert_invariant(); - } + basic_json(const array_t& val) + : m_type(value_t::array), m_value(val) + { + assert_invariant(); + } - /*! + /*! @brief create an array (implicit) Create an array JSON value with a given content. This constructor allows @@ -1204,24 +1208,24 @@ class basic_json @since version 1.0.0 */ - template::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 and - not std::is_same::value and - std::is_constructible::value, int>::type = 0> - basic_json(const CompatibleArrayType& val) - : m_type(value_t::array) - { - using std::begin; - using std::end; - m_value.array = create(begin(val), end(val)); - assert_invariant(); - } + template::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 and + not std::is_same::value and + std::is_constructible::value, int>::type = 0> + basic_json(const CompatibleArrayType& val) + : m_type(value_t::array) + { + using std::begin; + using std::end; + m_value.array = create(begin(val), end(val)); + assert_invariant(); + } - /*! + /*! @brief create a string (explicit) Create an string JSON value with a given content. @@ -1242,13 +1246,13 @@ class basic_json @since version 1.0.0 */ - basic_json(const string_t& val) - : m_type(value_t::string), m_value(val) - { - assert_invariant(); - } + basic_json(const string_t& val) + : m_type(value_t::string), m_value(val) + { + assert_invariant(); + } - /*! + /*! @brief create a string (explicit) Create a string JSON value with a given content. @@ -1268,13 +1272,13 @@ class basic_json @since version 1.0.0 */ - basic_json(const typename string_t::value_type* val) - : basic_json(string_t(val)) - { - assert_invariant(); - } + basic_json(const typename string_t::value_type* val) + : basic_json(string_t(val)) + { + assert_invariant(); + } - /*! + /*! @brief create a string (implicit) Create a string JSON value with a given content. @@ -1297,15 +1301,15 @@ class basic_json @since version 1.0.0 */ - template::value, int>::type = 0> - basic_json(const CompatibleStringType& val) - : basic_json(string_t(val)) - { - assert_invariant(); - } + template::value, int>::type = 0> + basic_json(const CompatibleStringType& val) + : basic_json(string_t(val)) + { + assert_invariant(); + } - /*! + /*! @brief create a boolean (explicit) Creates a JSON boolean type from a given value. @@ -1319,13 +1323,13 @@ class basic_json @since version 1.0.0 */ - basic_json(boolean_t val) noexcept - : m_type(value_t::boolean), m_value(val) - { - assert_invariant(); - } + basic_json(boolean_t val) noexcept + : m_type(value_t::boolean), m_value(val) + { + assert_invariant(); + } - /*! + /*! @brief create an integer number (explicit) Create an integer number JSON value with a given content. @@ -1348,16 +1352,16 @@ class basic_json @since version 1.0.0 */ - template::value) and - std::is_same::value, int>::type = 0> - basic_json(const number_integer_t val) noexcept - : m_type(value_t::number_integer), m_value(val) - { - assert_invariant(); - } + template::value) and + std::is_same::value, int>::type = 0> + basic_json(const number_integer_t val) noexcept + : m_type(value_t::number_integer), m_value(val) + { + assert_invariant(); + } - /*! + /*! @brief create an integer number from an enum type (explicit) Create an integer number JSON value with a given content. @@ -1382,14 +1386,14 @@ class basic_json @since version 1.0.0 */ - basic_json(const int val) noexcept - : m_type(value_t::number_integer), - m_value(static_cast(val)) - { - assert_invariant(); - } + basic_json(const int val) noexcept + : m_type(value_t::number_integer), + m_value(static_cast(val)) + { + assert_invariant(); + } - /*! + /*! @brief create an integer number (implicit) Create an integer number JSON value with a given content. This constructor @@ -1414,19 +1418,19 @@ class basic_json @since version 1.0.0 */ - template::value and - std::numeric_limits::is_integer and - std::numeric_limits::is_signed, - CompatibleNumberIntegerType>::type = 0> - basic_json(const CompatibleNumberIntegerType val) noexcept - : m_type(value_t::number_integer), - m_value(static_cast(val)) - { - assert_invariant(); - } + template::value and + std::numeric_limits::is_integer and + std::numeric_limits::is_signed, + CompatibleNumberIntegerType>::type = 0> + basic_json(const CompatibleNumberIntegerType val) noexcept + : m_type(value_t::number_integer), + m_value(static_cast(val)) + { + assert_invariant(); + } - /*! + /*! @brief create an unsigned integer number (explicit) Create an unsigned integer number JSON value with a given content. @@ -1443,16 +1447,16 @@ class basic_json @since version 2.0.0 */ - template::value) and - std::is_same::value, int>::type = 0> - basic_json(const number_unsigned_t val) noexcept - : m_type(value_t::number_unsigned), m_value(val) - { - assert_invariant(); - } + template::value) and + std::is_same::value, int>::type = 0> + basic_json(const number_unsigned_t val) noexcept + : m_type(value_t::number_unsigned), m_value(val) + { + assert_invariant(); + } - /*! + /*! @brief create an unsigned number (implicit) Create an unsigned number JSON value with a given content. This @@ -1472,19 +1476,19 @@ class basic_json @since version 2.0.0 */ - template::value and - std::numeric_limits::is_integer and - not std::numeric_limits::is_signed, - CompatibleNumberUnsignedType>::type = 0> - basic_json(const CompatibleNumberUnsignedType val) noexcept - : m_type(value_t::number_unsigned), - m_value(static_cast(val)) - { - assert_invariant(); - } + template::value and + std::numeric_limits::is_integer and + not std::numeric_limits::is_signed, + CompatibleNumberUnsignedType>::type = 0> + basic_json(const CompatibleNumberUnsignedType val) noexcept + : m_type(value_t::number_unsigned), + m_value(static_cast(val)) + { + assert_invariant(); + } - /*! + /*! @brief create a floating-point number (explicit) Create a floating-point number JSON value with a given content. @@ -1508,20 +1512,20 @@ class basic_json @since version 1.0.0 */ - basic_json(const number_float_t val) noexcept - : m_type(value_t::number_float), m_value(val) - { - // replace infinity and NAN by null - if (not std::isfinite(val)) + basic_json(const number_float_t val) noexcept + : m_type(value_t::number_float), m_value(val) { - m_type = value_t::null; - m_value = json_value(); - } + // replace infinity and NAN by null + if (not std::isfinite(val)) + { + m_type = value_t::null; + m_value = json_value(); + } - assert_invariant(); - } + assert_invariant(); + } - /*! + /*! @brief create an floating-point number (implicit) Create an floating-point number JSON value with a given content. This @@ -1552,16 +1556,16 @@ class basic_json @since version 1.0.0 */ - template::value and - std::is_floating_point::value>::type> - basic_json(const CompatibleNumberFloatType val) noexcept - : basic_json(number_float_t(val)) - { - assert_invariant(); - } + template::value and + std::is_floating_point::value>::type> + basic_json(const CompatibleNumberFloatType val) noexcept + : basic_json(number_float_t(val)) + { + assert_invariant(); + } - /*! + /*! @brief create a container (array or object) from an initializer list Creates a JSON value of type array or object from the passed initializer @@ -1630,56 +1634,56 @@ class basic_json @since version 1.0.0 */ - basic_json(std::initializer_list init, - bool type_deduction = true, - value_t manual_type = value_t::array) - { - // check if each element is an array with two elements whose first - // element is a string - bool is_an_object = std::all_of(init.begin(), init.end(), - [](const basic_json & element) + basic_json(std::initializer_list init, + bool type_deduction = true, + value_t manual_type = value_t::array) { - return element.is_array() and element.size() == 2 and element[0].is_string(); - }); + // check if each element is an array with two elements whose first + // element is a string + bool is_an_object = std::all_of(init.begin(), init.end(), + [](const basic_json & element) + { + return element.is_array() and element.size() == 2 and element[0].is_string(); + }); - // adjust type if type deduction is not wanted - if (not type_deduction) - { - // if array is wanted, do not create an object though possible - if (manual_type == value_t::array) + // adjust type if type deduction is not wanted + if (not type_deduction) { - is_an_object = false; - } + // if array is wanted, do not create an object though possible + if (manual_type == value_t::array) + { + is_an_object = false; + } - // if object is wanted but impossible, throw an exception - if (manual_type == value_t::object and not is_an_object) - { - throw std::domain_error("cannot create object from initializer list"); + // if object is wanted but impossible, throw an exception + if (manual_type == value_t::object and not is_an_object) + { + throw std::domain_error("cannot create object from initializer list"); + } } - } - - if (is_an_object) - { - // the initializer list is a list of pairs -> create object - m_type = value_t::object; - m_value = value_t::object; - std::for_each(init.begin(), init.end(), [this](const basic_json & element) + if (is_an_object) { - m_value.object->emplace(*(element[0].m_value.string), element[1]); - }); - } - else - { - // the initializer list describes an array -> create array - m_type = value_t::array; - m_value.array = create(init); - } + // the initializer list is a list of pairs -> create object + m_type = value_t::object; + m_value = value_t::object; - assert_invariant(); - } + std::for_each(init.begin(), init.end(), [this](const basic_json & element) + { + m_value.object->emplace(*(element[0].m_value.string), element[1]); + }); + } + else + { + // the initializer list describes an array -> create array + m_type = value_t::array; + m_value.array = create(init); + } + + assert_invariant(); + } - /*! + /*! @brief explicitly create an array from an initializer list Creates a JSON array value from a given initializer list. That is, given a @@ -1713,13 +1717,13 @@ class basic_json @since version 1.0.0 */ - static basic_json array(std::initializer_list init = - std::initializer_list()) - { - return basic_json(init, false, value_t::array); - } + static basic_json array(std::initializer_list init = + std::initializer_list()) + { + return basic_json(init, false, value_t::array); + } - /*! + /*! @brief explicitly create an object from an initializer list Creates a JSON object value from a given initializer list. The initializer @@ -1753,13 +1757,13 @@ class basic_json @since version 1.0.0 */ - static basic_json object(std::initializer_list init = - std::initializer_list()) - { - return basic_json(init, false, value_t::object); - } + static basic_json object(std::initializer_list init = + std::initializer_list()) + { + return basic_json(init, false, value_t::object); + } - /*! + /*! @brief construct an array with count copies of given value Constructs a JSON array value by creating @a cnt copies of a passed value. @@ -1777,14 +1781,14 @@ class basic_json @since version 1.0.0 */ - basic_json(size_type cnt, const basic_json& val) - : m_type(value_t::array) - { - m_value.array = create(cnt, val); - assert_invariant(); - } + basic_json(size_type cnt, const basic_json& val) + : m_type(value_t::array) + { + m_value.array = create(cnt, val); + assert_invariant(); + } - /*! + /*! @brief construct a JSON container given an iterator range Constructs the JSON value with the contents of the range `[first, last)`. @@ -1821,99 +1825,99 @@ class basic_json @since version 1.0.0 */ - template::value or - std::is_same::value, int>::type = 0> - basic_json(InputIT first, InputIT last) - { - assert(first.m_object != nullptr); - assert(last.m_object != nullptr); - - // make sure iterator fits the current value - if (first.m_object != last.m_object) + template::value or + std::is_same::value, int>::type = 0> + basic_json(InputIT first, InputIT last) { - throw std::domain_error("iterators are not compatible"); - } + assert(first.m_object != nullptr); + assert(last.m_object != nullptr); - // copy type from first iterator - m_type = first.m_object->m_type; + // make sure iterator fits the current value + if (first.m_object != last.m_object) + { + throw std::domain_error("iterators are not compatible"); + } - // check if iterator range is complete for primitive values - switch (m_type) - { - case value_t::boolean: - case value_t::number_float: - case value_t::number_integer: - case value_t::number_unsigned: - case value_t::string: + // copy type from first iterator + m_type = first.m_object->m_type; + + // check if iterator range is complete for primitive values + switch (m_type) { - if (not first.m_it.primitive_iterator.is_begin() or not last.m_it.primitive_iterator.is_end()) + case value_t::boolean: + case value_t::number_float: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::string: { - throw std::out_of_range("iterators out of range"); + if (not first.m_it.primitive_iterator.is_begin() or not last.m_it.primitive_iterator.is_end()) + { + throw std::out_of_range("iterators out of range"); + } + break; } - break; - } - default: - { - break; + default: + { + break; + } } - } - switch (m_type) - { - case value_t::number_integer: + switch (m_type) { - m_value.number_integer = first.m_object->m_value.number_integer; - break; - } + case value_t::number_integer: + { + m_value.number_integer = first.m_object->m_value.number_integer; + break; + } - case value_t::number_unsigned: - { - m_value.number_unsigned = first.m_object->m_value.number_unsigned; - break; - } + case value_t::number_unsigned: + { + m_value.number_unsigned = first.m_object->m_value.number_unsigned; + break; + } - case value_t::number_float: - { - m_value.number_float = first.m_object->m_value.number_float; - break; - } + case value_t::number_float: + { + m_value.number_float = first.m_object->m_value.number_float; + break; + } - case value_t::boolean: - { - m_value.boolean = first.m_object->m_value.boolean; - break; - } + case value_t::boolean: + { + m_value.boolean = first.m_object->m_value.boolean; + break; + } - case value_t::string: - { - m_value = *first.m_object->m_value.string; - break; - } + case value_t::string: + { + m_value = *first.m_object->m_value.string; + break; + } - case value_t::object: - { - m_value.object = create(first.m_it.object_iterator, last.m_it.object_iterator); - break; - } + case value_t::object: + { + m_value.object = create(first.m_it.object_iterator, last.m_it.object_iterator); + break; + } - case value_t::array: - { - m_value.array = create(first.m_it.array_iterator, last.m_it.array_iterator); - break; - } + case value_t::array: + { + m_value.array = create(first.m_it.array_iterator, last.m_it.array_iterator); + break; + } - default: - { - throw std::domain_error("cannot use construct with iterators from " + first.m_object->type_name()); + default: + { + throw std::domain_error("cannot use construct with iterators from " + first.m_object->type_name()); + } } - } - assert_invariant(); - } + assert_invariant(); + } - /*! + /*! @brief construct a JSON value given an input stream @param[in,out] i stream to read a serialized JSON value from @@ -1941,18 +1945,18 @@ class basic_json @since version 2.0.0, deprecated in version 2.0.3, to be removed in version 3.0.0 */ - JSON_DEPRECATED - explicit basic_json(std::istream& i, const parser_callback_t cb = nullptr) - { - *this = parser(i, cb).parse(); - assert_invariant(); - } + JSON_DEPRECATED + explicit basic_json(std::istream& i, const parser_callback_t cb = nullptr) + { + *this = parser(i, cb).parse(); + assert_invariant(); + } - /////////////////////////////////////// - // other constructors and destructor // - /////////////////////////////////////// + /////////////////////////////////////// + // other constructors and destructor // + /////////////////////////////////////// - /*! + /*! @brief copy constructor Creates a copy of a given JSON value. @@ -1974,66 +1978,66 @@ class basic_json @since version 1.0.0 */ - basic_json(const basic_json& other) - : m_type(other.m_type) - { - // check of passed value is valid - other.assert_invariant(); - - switch (m_type) + basic_json(const basic_json& other) + : m_type(other.m_type) { - case value_t::object: - { - m_value = *other.m_value.object; - break; - } + // check of passed value is valid + other.assert_invariant(); - case value_t::array: + switch (m_type) { - m_value = *other.m_value.array; - break; - } + case value_t::object: + { + m_value = *other.m_value.object; + break; + } - case value_t::string: - { - m_value = *other.m_value.string; - break; - } + case value_t::array: + { + m_value = *other.m_value.array; + break; + } - case value_t::boolean: - { - m_value = other.m_value.boolean; - break; - } + case value_t::string: + { + m_value = *other.m_value.string; + break; + } - case value_t::number_integer: - { - m_value = other.m_value.number_integer; - break; - } + case value_t::boolean: + { + m_value = other.m_value.boolean; + break; + } - case value_t::number_unsigned: - { - m_value = other.m_value.number_unsigned; - break; - } + case value_t::number_integer: + { + m_value = other.m_value.number_integer; + break; + } - case value_t::number_float: - { - m_value = other.m_value.number_float; - break; - } + case value_t::number_unsigned: + { + m_value = other.m_value.number_unsigned; + break; + } - default: - { - break; + case value_t::number_float: + { + m_value = other.m_value.number_float; + break; + } + + default: + { + break; + } } - } - assert_invariant(); - } + assert_invariant(); + } - /*! + /*! @brief move constructor Move constructor. Constructs a JSON value with the contents of the given @@ -2051,21 +2055,21 @@ class basic_json @since version 1.0.0 */ - basic_json(basic_json&& other) noexcept - : m_type(std::move(other.m_type)), - m_value(std::move(other.m_value)) - { - // check that passed value is valid - other.assert_invariant(); + basic_json(basic_json&& other) noexcept + : m_type(std::move(other.m_type)), + m_value(std::move(other.m_value)) + { + // check that passed value is valid + other.assert_invariant(); - // invalidate payload - other.m_type = value_t::null; - other.m_value = {}; + // invalidate payload + other.m_type = value_t::null; + other.m_value = {}; - assert_invariant(); - } + assert_invariant(); + } - /*! + /*! @brief copy assignment Copy assignment operator. Copies a JSON value via the "copy and swap" @@ -2088,25 +2092,25 @@ class basic_json @since version 1.0.0 */ - reference& operator=(basic_json other) noexcept ( + reference& operator=(basic_json other) noexcept ( std::is_nothrow_move_constructible::value and std::is_nothrow_move_assignable::value and std::is_nothrow_move_constructible::value and std::is_nothrow_move_assignable::value - ) - { - // check that passed value is valid - other.assert_invariant(); + ) + { + // check that passed value is valid + other.assert_invariant(); - using std::swap; - swap(m_type, other.m_type); - swap(m_value, other.m_value); + using std::swap; + swap(m_type, other.m_type); + swap(m_value, other.m_value); - assert_invariant(); - return *this; - } + assert_invariant(); + return *this; + } - /*! + /*! @brief destructor Destroys the JSON value and frees all allocated memory. @@ -2121,56 +2125,56 @@ class basic_json @since version 1.0.0 */ - ~basic_json() - { - assert_invariant(); - - switch (m_type) + ~basic_json() { - case value_t::object: - { - AllocatorType alloc; - alloc.destroy(m_value.object); - alloc.deallocate(m_value.object, 1); - break; - } + assert_invariant(); - case value_t::array: + switch (m_type) { - AllocatorType alloc; - alloc.destroy(m_value.array); - alloc.deallocate(m_value.array, 1); - break; - } + case value_t::object: + { + AllocatorType alloc; + alloc.destroy(m_value.object); + alloc.deallocate(m_value.object, 1); + break; + } - case value_t::string: - { - AllocatorType alloc; - alloc.destroy(m_value.string); - alloc.deallocate(m_value.string, 1); - break; - } + case value_t::array: + { + AllocatorType alloc; + alloc.destroy(m_value.array); + alloc.deallocate(m_value.array, 1); + break; + } - default: - { - // all other types need no specific destructor - break; + case value_t::string: + { + AllocatorType alloc; + alloc.destroy(m_value.string); + alloc.deallocate(m_value.string, 1); + break; + } + + default: + { + // all other types need no specific destructor + break; + } } } - } - /// @} + /// @} - public: - /////////////////////// - // object inspection // - /////////////////////// + public: + /////////////////////// + // object inspection // + /////////////////////// - /// @name object inspection - /// Functions to inspect the type of a JSON value. - /// @{ + /// @name object inspection + /// Functions to inspect the type of a JSON value. + /// @{ - /*! + /*! @brief serialization Serialization function for JSON values. The function tries to mimic @@ -2193,32 +2197,32 @@ class basic_json @since version 1.0.0 */ - string_t dump(const int indent = -1) const - { - std::stringstream ss; - // fix locale problems - const static std::locale loc(std::locale(), new DecimalSeparator); - ss.imbue(loc); + string_t dump(const int indent = -1) const + { + std::stringstream ss; + // fix locale problems + const static std::locale loc(std::locale(), new DecimalSeparator); + ss.imbue(loc); - // 6, 15 or 16 digits of precision allows round-trip IEEE 754 - // string->float->string, string->double->string or string->long - // double->string; to be safe, we read this value from - // std::numeric_limits::digits10 - ss.precision(std::numeric_limits::digits10); + // 6, 15 or 16 digits of precision allows round-trip IEEE 754 + // string->float->string, string->double->string or string->long + // double->string; to be safe, we read this value from + // std::numeric_limits::digits10 + ss.precision(std::numeric_limits::digits10); - if (indent >= 0) - { - dump(ss, true, static_cast(indent)); - } - else - { - dump(ss, false, 0); - } + if (indent >= 0) + { + dump(ss, true, static_cast(indent)); + } + else + { + dump(ss, false, 0); + } - return ss.str(); - } + return ss.str(); + } - /*! + /*! @brief return the type of the JSON value (explicit) Return the type of the JSON value as a value from the @ref value_t @@ -2236,12 +2240,12 @@ class basic_json @since version 1.0.0 */ - constexpr value_t type() const noexcept - { - return m_type; - } + constexpr value_t type() const noexcept + { + return m_type; + } - /*! + /*! @brief return whether type is primitive This function returns true iff the JSON type is primitive (string, number, @@ -2266,12 +2270,12 @@ class basic_json @since version 1.0.0 */ - constexpr bool is_primitive() const noexcept - { - return is_null() or is_string() or is_boolean() or is_number(); - } + constexpr bool is_primitive() const noexcept + { + return is_null() or is_string() or is_boolean() or is_number(); + } - /*! + /*! @brief return whether type is structured This function returns true iff the JSON type is structured (array or @@ -2293,12 +2297,12 @@ class basic_json @since version 1.0.0 */ - constexpr bool is_structured() const noexcept - { - return is_array() or is_object(); - } + constexpr bool is_structured() const noexcept + { + return is_array() or is_object(); + } - /*! + /*! @brief return whether value is null This function returns true iff the JSON value is null. @@ -2315,12 +2319,12 @@ class basic_json @since version 1.0.0 */ - constexpr bool is_null() const noexcept - { - return m_type == value_t::null; - } + constexpr bool is_null() const noexcept + { + return m_type == value_t::null; + } - /*! + /*! @brief return whether value is a boolean This function returns true iff the JSON value is a boolean. @@ -2337,12 +2341,12 @@ class basic_json @since version 1.0.0 */ - constexpr bool is_boolean() const noexcept - { - return m_type == value_t::boolean; - } + constexpr bool is_boolean() const noexcept + { + return m_type == value_t::boolean; + } - /*! + /*! @brief return whether value is a number This function returns true iff the JSON value is a number. This includes @@ -2367,12 +2371,12 @@ class basic_json @since version 1.0.0 */ - constexpr bool is_number() const noexcept - { - return is_number_integer() or is_number_float(); - } + constexpr bool is_number() const noexcept + { + return is_number_integer() or is_number_float(); + } - /*! + /*! @brief return whether value is an integer number This function returns true iff the JSON value is an integer or unsigned @@ -2396,12 +2400,12 @@ class basic_json @since version 1.0.0 */ - constexpr bool is_number_integer() const noexcept - { - return m_type == value_t::number_integer or m_type == value_t::number_unsigned; - } + constexpr bool is_number_integer() const noexcept + { + return m_type == value_t::number_integer or m_type == value_t::number_unsigned; + } - /*! + /*! @brief return whether value is an unsigned integer number This function returns true iff the JSON value is an unsigned integer @@ -2424,12 +2428,12 @@ class basic_json @since version 2.0.0 */ - constexpr bool is_number_unsigned() const noexcept - { - return m_type == value_t::number_unsigned; - } + constexpr bool is_number_unsigned() const noexcept + { + return m_type == value_t::number_unsigned; + } - /*! + /*! @brief return whether value is a floating-point number This function returns true iff the JSON value is a floating-point number. @@ -2452,12 +2456,12 @@ class basic_json @since version 1.0.0 */ - constexpr bool is_number_float() const noexcept - { - return m_type == value_t::number_float; - } + constexpr bool is_number_float() const noexcept + { + return m_type == value_t::number_float; + } - /*! + /*! @brief return whether value is an object This function returns true iff the JSON value is an object. @@ -2474,12 +2478,12 @@ class basic_json @since version 1.0.0 */ - constexpr bool is_object() const noexcept - { - return m_type == value_t::object; - } + constexpr bool is_object() const noexcept + { + return m_type == value_t::object; + } - /*! + /*! @brief return whether value is an array This function returns true iff the JSON value is an array. @@ -2496,12 +2500,12 @@ class basic_json @since version 1.0.0 */ - constexpr bool is_array() const noexcept - { - return m_type == value_t::array; - } + constexpr bool is_array() const noexcept + { + return m_type == value_t::array; + } - /*! + /*! @brief return whether value is a string This function returns true iff the JSON value is a string. @@ -2518,12 +2522,12 @@ class basic_json @since version 1.0.0 */ - constexpr bool is_string() const noexcept - { - return m_type == value_t::string; - } + constexpr bool is_string() const noexcept + { + return m_type == value_t::string; + } - /*! + /*! @brief return whether value is discarded This function returns true iff the JSON value was discarded during parsing @@ -2545,12 +2549,12 @@ class basic_json @since version 1.0.0 */ - constexpr bool is_discarded() const noexcept - { - return m_type == value_t::discarded; - } + constexpr bool is_discarded() const noexcept + { + return m_type == value_t::discarded; + } - /*! + /*! @brief return the type of the JSON value (implicit) Implicitly return the type of the JSON value as a value from the @ref @@ -2568,261 +2572,261 @@ class basic_json @since version 1.0.0 */ - constexpr operator value_t() const noexcept - { - return m_type; - } + constexpr operator value_t() const noexcept + { + return m_type; + } - /// @} + /// @} - private: - ////////////////// - // value access // - ////////////////// + private: + ////////////////// + // value access // + ////////////////// - /// get an object (explicit) - template::value and - std::is_convertible::value, int>::type = 0> - T get_impl(T*) const - { - if (is_object()) + /// get an object (explicit) + template::value and + std::is_convertible::value, int>::type = 0> + T get_impl(T*) const { - return T(m_value.object->begin(), m_value.object->end()); + if (is_object()) + { + return T(m_value.object->begin(), m_value.object->end()); + } + else + { + throw std::domain_error("type must be object, but is " + type_name()); + } } - else + + /// get an object (explicit) + object_t get_impl(object_t*) const { - throw std::domain_error("type must be object, but is " + type_name()); + if (is_object()) + { + return *(m_value.object); + } + else + { + throw std::domain_error("type must be object, but is " + type_name()); + } } - } - /// get an object (explicit) - object_t get_impl(object_t*) const - { - if (is_object()) + /// get an array (explicit) + template::value and + not std::is_same::value and + not std::is_arithmetic::value and + not std::is_convertible::value and + not has_mapped_type::value, int>::type = 0> + T get_impl(T*) const { - return *(m_value.object); + if (is_array()) + { + T to_vector; + std::transform(m_value.array->begin(), m_value.array->end(), + std::inserter(to_vector, to_vector.end()), [](basic_json i) + { + return i.get(); + }); + return to_vector; + } + else + { + throw std::domain_error("type must be array, but is " + type_name()); + } } - else + + /// get an array (explicit) + template::value and + not std::is_same::value, int>::type = 0> + std::vector get_impl(std::vector*) const { - throw std::domain_error("type must be object, but is " + type_name()); + if (is_array()) + { + std::vector to_vector; + to_vector.reserve(m_value.array->size()); + std::transform(m_value.array->begin(), m_value.array->end(), + std::inserter(to_vector, to_vector.end()), [](basic_json i) + { + return i.get(); + }); + return to_vector; + } + else + { + throw std::domain_error("type must be array, but is " + type_name()); + } } - } - /// get an array (explicit) - template::value and - not std::is_same::value and - not std::is_arithmetic::value and - not std::is_convertible::value and - not has_mapped_type::value, int>::type = 0> - T get_impl(T*) const - { - if (is_array()) + /// get an array (explicit) + template::value and + not has_mapped_type::value, int>::type = 0> + T get_impl(T*) const { - T to_vector; - std::transform(m_value.array->begin(), m_value.array->end(), - std::inserter(to_vector, to_vector.end()), [](basic_json i) + if (is_array()) + { + return T(m_value.array->begin(), m_value.array->end()); + } + else { - return i.get(); - }); - return to_vector; + throw std::domain_error("type must be array, but is " + type_name()); + } } - else + + /// get an array (explicit) + array_t get_impl(array_t*) const { - throw std::domain_error("type must be array, but is " + type_name()); + if (is_array()) + { + return *(m_value.array); + } + else + { + throw std::domain_error("type must be array, but is " + type_name()); + } } - } - /// get an array (explicit) - template::value and - not std::is_same::value, int>::type = 0> - std::vector get_impl(std::vector*) const - { - if (is_array()) + /// get a string (explicit) + template::value, int>::type = 0> + T get_impl(T*) const { - std::vector to_vector; - to_vector.reserve(m_value.array->size()); - std::transform(m_value.array->begin(), m_value.array->end(), - std::inserter(to_vector, to_vector.end()), [](basic_json i) + if (is_string()) + { + return *m_value.string; + } + else { - return i.get(); - }); - return to_vector; + throw std::domain_error("type must be string, but is " + type_name()); + } } - else + + /// get a number (explicit) + template::value, int>::type = 0> + T get_impl(T*) const { - throw std::domain_error("type must be array, but is " + type_name()); + switch (m_type) + { + case value_t::number_integer: + { + return static_cast(m_value.number_integer); + } + + case value_t::number_unsigned: + { + return static_cast(m_value.number_unsigned); + } + + case value_t::number_float: + { + return static_cast(m_value.number_float); + } + + default: + { + throw std::domain_error("type must be number, but is " + type_name()); + } + } } - } - /// get an array (explicit) - template::value and - not has_mapped_type::value, int>::type = 0> - T get_impl(T*) const - { - if (is_array()) + /// get a boolean (explicit) + constexpr boolean_t get_impl(boolean_t*) const { - return T(m_value.array->begin(), m_value.array->end()); + return is_boolean() + ? m_value.boolean + : throw std::domain_error("type must be boolean, but is " + type_name()); } - else + + /// get a pointer to the value (object) + object_t* get_impl_ptr(object_t*) noexcept { - throw std::domain_error("type must be array, but is " + type_name()); + return is_object() ? m_value.object : nullptr; } - } - /// get an array (explicit) - array_t get_impl(array_t*) const - { - if (is_array()) + /// get a pointer to the value (object) + constexpr const object_t* get_impl_ptr(const object_t*) const noexcept { - return *(m_value.array); + return is_object() ? m_value.object : nullptr; } - else + + /// get a pointer to the value (array) + array_t* get_impl_ptr(array_t*) noexcept { - throw std::domain_error("type must be array, but is " + type_name()); + return is_array() ? m_value.array : nullptr; } - } - /// get a string (explicit) - template::value, int>::type = 0> - T get_impl(T*) const - { - if (is_string()) + /// get a pointer to the value (array) + constexpr const array_t* get_impl_ptr(const array_t*) const noexcept { - return *m_value.string; + return is_array() ? m_value.array : nullptr; } - else + + /// get a pointer to the value (string) + string_t* get_impl_ptr(string_t*) noexcept { - throw std::domain_error("type must be string, but is " + type_name()); + return is_string() ? m_value.string : nullptr; } - } - /// get a number (explicit) - template::value, int>::type = 0> - T get_impl(T*) const - { - switch (m_type) + /// get a pointer to the value (string) + constexpr const string_t* get_impl_ptr(const string_t*) const noexcept { - case value_t::number_integer: - { - return static_cast(m_value.number_integer); - } - - case value_t::number_unsigned: - { - return static_cast(m_value.number_unsigned); - } - - case value_t::number_float: - { - return static_cast(m_value.number_float); - } - - default: - { - throw std::domain_error("type must be number, but is " + type_name()); - } + return is_string() ? m_value.string : nullptr; } - } - - /// get a boolean (explicit) - constexpr boolean_t get_impl(boolean_t*) const - { - return is_boolean() - ? m_value.boolean - : throw std::domain_error("type must be boolean, but is " + type_name()); - } - - /// get a pointer to the value (object) - object_t* get_impl_ptr(object_t*) noexcept - { - return is_object() ? m_value.object : nullptr; - } - - /// get a pointer to the value (object) - constexpr const object_t* get_impl_ptr(const object_t*) const noexcept - { - return is_object() ? m_value.object : nullptr; - } - /// get a pointer to the value (array) - array_t* get_impl_ptr(array_t*) noexcept - { - return is_array() ? m_value.array : nullptr; - } - - /// get a pointer to the value (array) - constexpr const array_t* get_impl_ptr(const array_t*) const noexcept - { - return is_array() ? m_value.array : nullptr; - } - - /// get a pointer to the value (string) - string_t* get_impl_ptr(string_t*) noexcept - { - return is_string() ? m_value.string : nullptr; - } - - /// get a pointer to the value (string) - constexpr const string_t* get_impl_ptr(const string_t*) const noexcept - { - return is_string() ? m_value.string : nullptr; - } - - /// get a pointer to the value (boolean) - boolean_t* get_impl_ptr(boolean_t*) noexcept - { - return is_boolean() ? &m_value.boolean : nullptr; - } + /// get a pointer to the value (boolean) + boolean_t* get_impl_ptr(boolean_t*) noexcept + { + return is_boolean() ? &m_value.boolean : nullptr; + } - /// get a pointer to the value (boolean) - constexpr const boolean_t* get_impl_ptr(const boolean_t*) const noexcept - { - return is_boolean() ? &m_value.boolean : nullptr; - } + /// get a pointer to the value (boolean) + constexpr const boolean_t* get_impl_ptr(const boolean_t*) const noexcept + { + return is_boolean() ? &m_value.boolean : nullptr; + } - /// get a pointer to the value (integer number) - number_integer_t* get_impl_ptr(number_integer_t*) noexcept - { - return is_number_integer() ? &m_value.number_integer : nullptr; - } + /// get a pointer to the value (integer number) + number_integer_t* get_impl_ptr(number_integer_t*) noexcept + { + return is_number_integer() ? &m_value.number_integer : nullptr; + } - /// get a pointer to the value (integer number) - constexpr const number_integer_t* get_impl_ptr(const number_integer_t*) const noexcept - { - return is_number_integer() ? &m_value.number_integer : nullptr; - } + /// get a pointer to the value (integer number) + constexpr const number_integer_t* get_impl_ptr(const number_integer_t*) const noexcept + { + return is_number_integer() ? &m_value.number_integer : nullptr; + } - /// get a pointer to the value (unsigned number) - number_unsigned_t* get_impl_ptr(number_unsigned_t*) noexcept - { - return is_number_unsigned() ? &m_value.number_unsigned : nullptr; - } + /// get a pointer to the value (unsigned number) + number_unsigned_t* get_impl_ptr(number_unsigned_t*) noexcept + { + return is_number_unsigned() ? &m_value.number_unsigned : nullptr; + } - /// get a pointer to the value (unsigned number) - constexpr const number_unsigned_t* get_impl_ptr(const number_unsigned_t*) const noexcept - { - return is_number_unsigned() ? &m_value.number_unsigned : nullptr; - } + /// get a pointer to the value (unsigned number) + constexpr const number_unsigned_t* get_impl_ptr(const number_unsigned_t*) const noexcept + { + return is_number_unsigned() ? &m_value.number_unsigned : nullptr; + } - /// get a pointer to the value (floating-point number) - number_float_t* get_impl_ptr(number_float_t*) noexcept - { - return is_number_float() ? &m_value.number_float : nullptr; - } + /// get a pointer to the value (floating-point number) + number_float_t* get_impl_ptr(number_float_t*) noexcept + { + return is_number_float() ? &m_value.number_float : nullptr; + } - /// get a pointer to the value (floating-point number) - constexpr const number_float_t* get_impl_ptr(const number_float_t*) const noexcept - { - return is_number_float() ? &m_value.number_float : nullptr; - } + /// get a pointer to the value (floating-point number) + constexpr const number_float_t* get_impl_ptr(const number_float_t*) const noexcept + { + return is_number_float() ? &m_value.number_float : nullptr; + } - /*! + /*! @brief helper function to implement get_ref() This funcion helps to implement get_ref() without code duplication for @@ -2833,33 +2837,33 @@ class basic_json @throw std::domain_error if ReferenceType does not match underlying value type of the current JSON */ - template - static ReferenceType get_ref_impl(ThisType& obj) - { - // helper type - using PointerType = typename std::add_pointer::type; + template + static ReferenceType get_ref_impl(ThisType& obj) + { + // helper type + using PointerType = typename std::add_pointer::type; - // delegate the call to get_ptr<>() - auto ptr = obj.template get_ptr(); + // delegate the call to get_ptr<>() + auto ptr = obj.template get_ptr(); - if (ptr != nullptr) - { - return *ptr; - } - else - { - throw std::domain_error("incompatible ReferenceType for get_ref, actual type is " + - obj.type_name()); + if (ptr != nullptr) + { + return *ptr; + } + else + { + throw std::domain_error("incompatible ReferenceType for get_ref, actual type is " + + obj.type_name()); + } } - } - public: + public: - /// @name value access - /// Direct access to the stored value of a JSON value. - /// @{ + /// @name value access + /// Direct access to the stored value of a JSON value. + /// @{ - /*! + /*! @brief get a value (explicit) Explicit type conversion between the JSON value and a compatible value. @@ -2892,14 +2896,14 @@ class basic_json @since version 1.0.0 */ - template::value, int>::type = 0> - ValueType get() const - { - return get_impl(static_cast(nullptr)); - } + template::value, int>::type = 0> + ValueType get() const + { + return get_impl(static_cast(nullptr)); + } - /*! + /*! @brief get a pointer value (explicit) Explicit pointer access to the internally stored JSON value. No copies are @@ -2926,27 +2930,27 @@ class basic_json @since version 1.0.0 */ - template::value, int>::type = 0> - PointerType get() noexcept - { - // delegate the call to get_ptr - return get_ptr(); - } + template::value, int>::type = 0> + PointerType get() noexcept + { + // delegate the call to get_ptr + return get_ptr(); + } - /*! + /*! @brief get a pointer value (explicit) @copydoc get() */ - template::value, int>::type = 0> - constexpr const PointerType get() const noexcept - { - // delegate the call to get_ptr - return get_ptr(); - } + template::value, int>::type = 0> + constexpr const PointerType get() const noexcept + { + // delegate the call to get_ptr + return get_ptr(); + } - /*! + /*! @brief get a pointer value (implicit) Implicit pointer access to the internally stored JSON value. No copies are @@ -2972,58 +2976,58 @@ class basic_json @since version 1.0.0 */ - template::value, int>::type = 0> - PointerType get_ptr() noexcept - { - // get the type of the PointerType (remove pointer and const) - using pointee_t = typename std::remove_const::type>::type>::type; - // make sure the type matches the allowed types - static_assert( - std::is_same::value - or std::is_same::value - or std::is_same::value - or std::is_same::value - or std::is_same::value - or std::is_same::value - or std::is_same::value - , "incompatible pointer type"); - - // delegate the call to get_impl_ptr<>() - return get_impl_ptr(static_cast(nullptr)); - } + template::value, int>::type = 0> + PointerType get_ptr() noexcept + { + // get the type of the PointerType (remove pointer and const) + using pointee_t = typename std::remove_const::type>::type>::type; + // make sure the type matches the allowed types + static_assert( + std::is_same::value + or std::is_same::value + or std::is_same::value + or std::is_same::value + or std::is_same::value + or std::is_same::value + or std::is_same::value + , "incompatible pointer type"); + + // delegate the call to get_impl_ptr<>() + return get_impl_ptr(static_cast(nullptr)); + } - /*! + /*! @brief get a pointer value (implicit) @copydoc get_ptr() */ - template::value and - std::is_const::type>::value, int>::type = 0> - constexpr const PointerType get_ptr() const noexcept - { - // get the type of the PointerType (remove pointer and const) - using pointee_t = typename std::remove_const::type>::type>::type; - // make sure the type matches the allowed types - static_assert( - std::is_same::value - or std::is_same::value - or std::is_same::value - or std::is_same::value - or std::is_same::value - or std::is_same::value - or std::is_same::value - , "incompatible pointer type"); - - // delegate the call to get_impl_ptr<>() const - return get_impl_ptr(static_cast(nullptr)); - } + template::value and + std::is_const::type>::value, int>::type = 0> + constexpr const PointerType get_ptr() const noexcept + { + // get the type of the PointerType (remove pointer and const) + using pointee_t = typename std::remove_const::type>::type>::type; + // make sure the type matches the allowed types + static_assert( + std::is_same::value + or std::is_same::value + or std::is_same::value + or std::is_same::value + or std::is_same::value + or std::is_same::value + or std::is_same::value + , "incompatible pointer type"); + + // delegate the call to get_impl_ptr<>() const + return get_impl_ptr(static_cast(nullptr)); + } - /*! + /*! @brief get a reference value (implicit) Implict reference access to the internally stored JSON value. No copies @@ -3049,28 +3053,28 @@ class basic_json @since version 1.1.0 */ - template::value, int>::type = 0> - ReferenceType get_ref() - { - // delegate call to get_ref_impl - return get_ref_impl(*this); - } + template::value, int>::type = 0> + ReferenceType get_ref() + { + // delegate call to get_ref_impl + return get_ref_impl(*this); + } - /*! + /*! @brief get a reference value (implicit) @copydoc get_ref() */ - template::value and - std::is_const::type>::value, int>::type = 0> - ReferenceType get_ref() const - { - // delegate call to get_ref_impl - return get_ref_impl(*this); - } + template::value and + std::is_const::type>::value, int>::type = 0> + ReferenceType get_ref() const + { + // delegate call to get_ref_impl + return get_ref_impl(*this); + } - /*! + /*! @brief get a value (implicit) Implicit type conversion between the JSON value and a compatible value. @@ -3098,31 +3102,31 @@ class basic_json @since version 1.0.0 */ - template < typename ValueType, typename std::enable_if < - not std::is_pointer::value and - not std::is_same::value -#ifndef _MSC_VER // Fix for issue #167 operator<< abiguity under VS2015 - and not std::is_same>::value + template < typename ValueType, typename std::enable_if < + not std::is_pointer::value and + not std::is_same::value + #ifndef _MSC_VER // Fix for issue #167 operator<< abiguity under VS2015 + and not std::is_same>::value #endif - , int >::type = 0 > - operator ValueType() const - { - // delegate the call to get<>() const - return get(); - } + , int >::type = 0 > + operator ValueType() const + { + // delegate the call to get<>() const + return get(); + } - /// @} + /// @} - //////////////////// - // element access // - //////////////////// + //////////////////// + // element access // + //////////////////// - /// @name element access - /// Access to the JSON value. - /// @{ + /// @name element access + /// Access to the JSON value. + /// @{ - /*! + /*! @brief access specified array element with bounds checking Returns a reference to the element at specified location @a idx, with @@ -3144,28 +3148,28 @@ class basic_json @since version 1.0.0 */ - reference at(size_type idx) - { - // at only works for arrays - if (is_array()) + reference at(size_type idx) { - try + // at only works for arrays + if (is_array()) { - return m_value.array->at(idx); + try + { + return m_value.array->at(idx); + } + catch (std::out_of_range&) + { + // create better exception explanation + throw std::out_of_range("array index " + std::to_string(idx) + " is out of range"); + } } - catch (std::out_of_range&) + else { - // create better exception explanation - throw std::out_of_range("array index " + std::to_string(idx) + " is out of range"); + throw std::domain_error("cannot use at() with " + type_name()); } } - else - { - throw std::domain_error("cannot use at() with " + type_name()); - } - } - /*! + /*! @brief access specified array element with bounds checking Returns a const reference to the element at specified location @a idx, @@ -3187,28 +3191,28 @@ class basic_json @since version 1.0.0 */ - const_reference at(size_type idx) const - { - // at only works for arrays - if (is_array()) + const_reference at(size_type idx) const { - try + // at only works for arrays + if (is_array()) { - return m_value.array->at(idx); + try + { + return m_value.array->at(idx); + } + catch (std::out_of_range&) + { + // create better exception explanation + throw std::out_of_range("array index " + std::to_string(idx) + " is out of range"); + } } - catch (std::out_of_range&) + else { - // create better exception explanation - throw std::out_of_range("array index " + std::to_string(idx) + " is out of range"); + throw std::domain_error("cannot use at() with " + type_name()); } } - else - { - throw std::domain_error("cannot use at() with " + type_name()); - } - } - /*! + /*! @brief access specified object element with bounds checking Returns a reference to the element at with specified key @a key, with @@ -3234,28 +3238,28 @@ class basic_json @since version 1.0.0 */ - reference at(const typename object_t::key_type& key) - { - // at only works for objects - if (is_object()) + reference at(const typename object_t::key_type& key) { - try + // at only works for objects + if (is_object()) { - return m_value.object->at(key); + try + { + return m_value.object->at(key); + } + catch (std::out_of_range&) + { + // create better exception explanation + throw std::out_of_range("key '" + key + "' not found"); + } } - catch (std::out_of_range&) + else { - // create better exception explanation - throw std::out_of_range("key '" + key + "' not found"); + throw std::domain_error("cannot use at() with " + type_name()); } } - else - { - throw std::domain_error("cannot use at() with " + type_name()); - } - } - /*! + /*! @brief access specified object element with bounds checking Returns a const reference to the element at with specified key @a key, @@ -3281,28 +3285,28 @@ class basic_json @since version 1.0.0 */ - const_reference at(const typename object_t::key_type& key) const - { - // at only works for objects - if (is_object()) + const_reference at(const typename object_t::key_type& key) const { - try - { - return m_value.object->at(key); - } - catch (std::out_of_range&) + // at only works for objects + if (is_object()) { - // create better exception explanation - throw std::out_of_range("key '" + key + "' not found"); + try + { + return m_value.object->at(key); + } + catch (std::out_of_range&) + { + // create better exception explanation + throw std::out_of_range("key '" + key + "' not found"); + } + } + else + { + throw std::domain_error("cannot use at() with " + type_name()); } } - else - { - throw std::domain_error("cannot use at() with " + type_name()); - } - } - /*! + /*! @brief access specified array element Returns a reference to the element at specified location @a idx. @@ -3327,36 +3331,36 @@ class basic_json @since version 1.0.0 */ - reference operator[](size_type idx) - { - // implicitly convert null value to an empty array - if (is_null()) - { - m_type = value_t::array; - m_value.array = create(); - assert_invariant(); - } - - // operator[] only works for arrays - if (is_array()) + reference operator[](size_type idx) { - // fill up array with null values if given idx is outside range - if (idx >= m_value.array->size()) + // implicitly convert null value to an empty array + if (is_null()) { - m_value.array->insert(m_value.array->end(), - idx - m_value.array->size() + 1, - basic_json()); + m_type = value_t::array; + m_value.array = create(); + assert_invariant(); } - return m_value.array->operator[](idx); - } - else - { - throw std::domain_error("cannot use operator[] with " + type_name()); + // operator[] only works for arrays + if (is_array()) + { + // fill up array with null values if given idx is outside range + if (idx >= m_value.array->size()) + { + m_value.array->insert(m_value.array->end(), + idx - m_value.array->size() + 1, + basic_json()); + } + + return m_value.array->operator[](idx); + } + else + { + throw std::domain_error("cannot use operator[] with " + type_name()); + } } - } - /*! + /*! @brief access specified array element Returns a const reference to the element at specified location @a idx. @@ -3375,20 +3379,20 @@ class basic_json @since version 1.0.0 */ - const_reference operator[](size_type idx) const - { - // const operator[] only works for arrays - if (is_array()) - { - return m_value.array->operator[](idx); - } - else + const_reference operator[](size_type idx) const { - throw std::domain_error("cannot use operator[] with " + type_name()); + // const operator[] only works for arrays + if (is_array()) + { + return m_value.array->operator[](idx); + } + else + { + throw std::domain_error("cannot use operator[] with " + type_name()); + } } - } - /*! + /*! @brief access specified object element Returns a reference to the element at with specified key @a key. @@ -3415,28 +3419,28 @@ class basic_json @since version 1.0.0 */ - reference operator[](const typename object_t::key_type& key) - { - // implicitly convert null value to an empty object - if (is_null()) + reference operator[](const typename object_t::key_type& key) { - m_type = value_t::object; - m_value.object = create(); - assert_invariant(); - } + // implicitly convert null value to an empty object + if (is_null()) + { + m_type = value_t::object; + m_value.object = create(); + assert_invariant(); + } - // operator[] only works for objects - if (is_object()) - { - return m_value.object->operator[](key); - } - else - { - throw std::domain_error("cannot use operator[] with " + type_name()); + // operator[] only works for objects + if (is_object()) + { + 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 @@ -3466,21 +3470,21 @@ class basic_json @since version 1.0.0 */ - const_reference operator[](const typename object_t::key_type& key) const - { - // const operator[] only works for objects - if (is_object()) + const_reference operator[](const typename object_t::key_type& key) const { - assert(m_value.object->find(key) != m_value.object->end()); - return m_value.object->find(key)->second; - } - else - { - throw std::domain_error("cannot use operator[] with " + type_name()); + // const operator[] only works for objects + if (is_object()) + { + assert(m_value.object->find(key) != m_value.object->end()); + return m_value.object->find(key)->second; + } + else + { + throw std::domain_error("cannot use operator[] with " + type_name()); + } } - } - /*! + /*! @brief access specified object element Returns a reference to the element at with specified key @a key. @@ -3507,13 +3511,13 @@ class basic_json @since version 1.0.0 */ - template - reference operator[](T * (&key)[n]) - { - return operator[](static_cast(key)); - } + template + 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 @@ -3542,13 +3546,13 @@ class basic_json @since version 1.0.0 */ - template - const_reference operator[](T * (&key)[n]) const - { - return operator[](static_cast(key)); - } + 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. @@ -3575,29 +3579,29 @@ class basic_json @since version 1.1.0 */ - template - reference operator[](T* key) - { - // implicitly convert null to object - if (is_null()) + template + reference operator[](T* key) { - m_type = value_t::object; - m_value = value_t::object; - assert_invariant(); - } + // implicitly convert null to object + if (is_null()) + { + m_type = value_t::object; + m_value = value_t::object; + assert_invariant(); + } - // at only works for objects - if (is_object()) - { - return m_value.object->operator[](key); - } - else - { - throw std::domain_error("cannot use operator[] with " + type_name()); + // at only works for objects + if (is_object()) + { + 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 @@ -3627,22 +3631,22 @@ class basic_json @since version 1.1.0 */ - template - const_reference operator[](T* key) const - { - // at only works for objects - if (is_object()) + template + const_reference operator[](T* key) const { - assert(m_value.object->find(key) != m_value.object->end()); - return m_value.object->find(key)->second; - } - else - { - throw std::domain_error("cannot use operator[] with " + type_name()); + // at only works for objects + if (is_object()) + { + assert(m_value.object->find(key) != m_value.object->end()); + return m_value.object->find(key)->second; + } + else + { + throw std::domain_error("cannot use operator[] with " + type_name()); + } } - } - /*! + /*! @brief access specified object element with default value Returns either a copy of an object's element at the specified key @a key @@ -3690,40 +3694,40 @@ class basic_json @since version 1.0.0 */ - template::value, int>::type = 0> - ValueType value(const typename object_t::key_type& key, ValueType default_value) const - { - // at only works for objects - if (is_object()) + template::value, int>::type = 0> + ValueType value(const typename object_t::key_type& key, ValueType default_value) const { - // if key is found, return value and given default value otherwise - const auto it = find(key); - if (it != end()) + // at only works for objects + if (is_object()) { - return *it; + // if key is found, return value and given default value otherwise + const auto it = find(key); + if (it != end()) + { + return *it; + } + else + { + return default_value; + } } else { - return default_value; + throw std::domain_error("cannot use value() with " + type_name()); } } - else - { - throw std::domain_error("cannot use value() with " + type_name()); - } - } - /*! + /*! @brief overload for a default value of type const char* @copydoc basic_json::value(const typename object_t::key_type&, ValueType) const */ - string_t value(const typename object_t::key_type& key, const char* default_value) const - { - return value(key, string_t(default_value)); - } + string_t value(const typename object_t::key_type& key, const char* default_value) const + { + return value(key, string_t(default_value)); + } - /*! + /*! @brief access specified object element via JSON Pointer with default value Returns either a copy of an object's element at the specified key @a key @@ -3764,39 +3768,39 @@ class basic_json @since version 2.0.2 */ - template::value, int>::type = 0> - ValueType value(const json_pointer& ptr, ValueType default_value) const - { - // at only works for objects - if (is_object()) + template::value, int>::type = 0> + ValueType value(const json_pointer& ptr, ValueType default_value) const { - // if pointer resolves a value, return it or use default value - try + // at only works for objects + if (is_object()) { - return ptr.get_checked(this); + // if pointer resolves a value, return it or use default value + try + { + return ptr.get_checked(this); + } + catch (std::out_of_range&) + { + return default_value; + } } - catch (std::out_of_range&) + else { - return default_value; + throw std::domain_error("cannot use value() with " + type_name()); } } - else - { - throw std::domain_error("cannot use value() with " + type_name()); - } - } - /*! + /*! @brief overload for a default value of type const char* @copydoc basic_json::value(const json_pointer&, ValueType) const */ - string_t value(const json_pointer& ptr, const char* default_value) const - { - return value(ptr, string_t(default_value)); - } + string_t value(const json_pointer& ptr, const char* default_value) const + { + return value(ptr, string_t(default_value)); + } - /*! + /*! @brief access the first element Returns a reference to the first element in the container. For a JSON @@ -3821,20 +3825,20 @@ class basic_json @since version 1.0.0 */ - reference front() - { - return *begin(); - } + reference front() + { + return *begin(); + } - /*! + /*! @copydoc basic_json::front() */ - const_reference front() const - { - return *cbegin(); - } + const_reference front() const + { + return *cbegin(); + } - /*! + /*! @brief access the last element Returns a reference to the last element in the container. For a JSON @@ -3864,24 +3868,24 @@ class basic_json @since version 1.0.0 */ - reference back() - { - auto tmp = end(); - --tmp; - return *tmp; - } + reference back() + { + auto tmp = end(); + --tmp; + return *tmp; + } - /*! + /*! @copydoc basic_json::back() */ - const_reference back() const - { - auto tmp = cend(); - --tmp; - return *tmp; - } + const_reference back() const + { + auto tmp = cend(); + --tmp; + return *tmp; + } - /*! + /*! @brief remove element given an iterator Removes the element specified by iterator @a pos. The iterator @a pos must @@ -3926,68 +3930,68 @@ class basic_json @since version 1.0.0 */ - template::value or - std::is_same::value, int>::type - = 0> - IteratorType erase(IteratorType pos) - { - // make sure iterator fits the current value - if (this != pos.m_object) + template::value or + std::is_same::value, int>::type + = 0> + IteratorType erase(IteratorType pos) { - throw std::domain_error("iterator does not fit current value"); - } + // make sure iterator fits the current value + if (this != pos.m_object) + { + throw std::domain_error("iterator does not fit current value"); + } - IteratorType result = end(); + IteratorType result = end(); - switch (m_type) - { - case value_t::boolean: - case value_t::number_float: - case value_t::number_integer: - case value_t::number_unsigned: - case value_t::string: + switch (m_type) { - if (not pos.m_it.primitive_iterator.is_begin()) + case value_t::boolean: + case value_t::number_float: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::string: { - throw std::out_of_range("iterator out of range"); + if (not pos.m_it.primitive_iterator.is_begin()) + { + throw std::out_of_range("iterator out of range"); + } + + if (is_string()) + { + AllocatorType alloc; + alloc.destroy(m_value.string); + alloc.deallocate(m_value.string, 1); + m_value.string = nullptr; + } + + m_type = value_t::null; + assert_invariant(); + break; } - if (is_string()) + case value_t::object: { - AllocatorType alloc; - alloc.destroy(m_value.string); - alloc.deallocate(m_value.string, 1); - m_value.string = nullptr; + result.m_it.object_iterator = m_value.object->erase(pos.m_it.object_iterator); + break; } - m_type = value_t::null; - assert_invariant(); - break; - } - - case value_t::object: - { - result.m_it.object_iterator = m_value.object->erase(pos.m_it.object_iterator); - break; - } + case value_t::array: + { + result.m_it.array_iterator = m_value.array->erase(pos.m_it.array_iterator); + break; + } - case value_t::array: - { - result.m_it.array_iterator = m_value.array->erase(pos.m_it.array_iterator); - break; + default: + { + throw std::domain_error("cannot use erase() with " + type_name()); + } } - default: - { - throw std::domain_error("cannot use erase() with " + type_name()); - } + return result; } - return result; - } - - /*! + /*! @brief remove elements given an iterator range Removes the element specified by the range `[first; last)`. The iterator @@ -4033,70 +4037,70 @@ class basic_json @since version 1.0.0 */ - template::value or - std::is_same::value, int>::type - = 0> - IteratorType erase(IteratorType first, IteratorType last) - { - // make sure iterator fits the current value - if (this != first.m_object or this != last.m_object) + template::value or + std::is_same::value, int>::type + = 0> + IteratorType erase(IteratorType first, IteratorType last) { - throw std::domain_error("iterators do not fit current value"); - } + // make sure iterator fits the current value + if (this != first.m_object or this != last.m_object) + { + throw std::domain_error("iterators do not fit current value"); + } - IteratorType result = end(); + IteratorType result = end(); - switch (m_type) - { - case value_t::boolean: - case value_t::number_float: - case value_t::number_integer: - case value_t::number_unsigned: - case value_t::string: + switch (m_type) { - if (not first.m_it.primitive_iterator.is_begin() or not last.m_it.primitive_iterator.is_end()) + case value_t::boolean: + case value_t::number_float: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::string: { - throw std::out_of_range("iterators out of range"); + if (not first.m_it.primitive_iterator.is_begin() or not last.m_it.primitive_iterator.is_end()) + { + throw std::out_of_range("iterators out of range"); + } + + if (is_string()) + { + AllocatorType alloc; + alloc.destroy(m_value.string); + alloc.deallocate(m_value.string, 1); + m_value.string = nullptr; + } + + m_type = value_t::null; + assert_invariant(); + break; } - if (is_string()) + case value_t::object: { - AllocatorType alloc; - alloc.destroy(m_value.string); - alloc.deallocate(m_value.string, 1); - m_value.string = nullptr; + result.m_it.object_iterator = m_value.object->erase(first.m_it.object_iterator, + last.m_it.object_iterator); + break; } - m_type = value_t::null; - assert_invariant(); - break; - } - - case value_t::object: - { - result.m_it.object_iterator = m_value.object->erase(first.m_it.object_iterator, - last.m_it.object_iterator); - break; - } + case value_t::array: + { + result.m_it.array_iterator = m_value.array->erase(first.m_it.array_iterator, + last.m_it.array_iterator); + break; + } - case value_t::array: - { - result.m_it.array_iterator = m_value.array->erase(first.m_it.array_iterator, - last.m_it.array_iterator); - break; + default: + { + throw std::domain_error("cannot use erase() with " + type_name()); + } } - default: - { - throw std::domain_error("cannot use erase() with " + type_name()); - } + return result; } - return result; - } - - /*! + /*! @brief remove element from a JSON object given a key Removes elements from a JSON object with the key value @a key. @@ -4125,20 +4129,20 @@ class basic_json @since version 1.0.0 */ - size_type erase(const typename object_t::key_type& key) - { - // this erase only works for objects - if (is_object()) - { - return m_value.object->erase(key); - } - else + size_type erase(const typename object_t::key_type& key) { - throw std::domain_error("cannot use erase() with " + type_name()); + // this erase only works for objects + if (is_object()) + { + return m_value.object->erase(key); + } + else + { + throw std::domain_error("cannot use erase() with " + type_name()); + } } - } - /*! + /*! @brief remove element from a JSON array given an index Removes element from a JSON array at the index @a idx. @@ -4162,35 +4166,35 @@ class basic_json @since version 1.0.0 */ - void erase(const size_type idx) - { - // this erase only works for arrays - if (is_array()) + void erase(const size_type idx) { - if (idx >= size()) + // this erase only works for arrays + if (is_array()) { - throw std::out_of_range("array index " + std::to_string(idx) + " is out of range"); - } + if (idx >= size()) + { + throw std::out_of_range("array index " + std::to_string(idx) + " is out of range"); + } - m_value.array->erase(m_value.array->begin() + static_cast(idx)); - } - else - { - throw std::domain_error("cannot use erase() with " + type_name()); + m_value.array->erase(m_value.array->begin() + static_cast(idx)); + } + else + { + throw std::domain_error("cannot use erase() with " + type_name()); + } } - } - /// @} + /// @} - //////////// - // lookup // - //////////// + //////////// + // lookup // + //////////// - /// @name lookup - /// @{ + /// @name lookup + /// @{ - /*! + /*! @brief find an element in a JSON object Finds an element in a JSON object with key equivalent to @a key. If the @@ -4208,35 +4212,35 @@ class basic_json @since version 1.0.0 */ - iterator find(typename object_t::key_type key) - { - auto result = end(); - - if (is_object()) + iterator find(typename object_t::key_type key) { - result.m_it.object_iterator = m_value.object->find(key); - } + auto result = end(); - return result; - } + if (is_object()) + { + result.m_it.object_iterator = m_value.object->find(key); + } + + return result; + } - /*! + /*! @brief find an element in a JSON object @copydoc find(typename object_t::key_type) */ - const_iterator find(typename object_t::key_type key) const - { - auto result = cend(); - - if (is_object()) + const_iterator find(typename object_t::key_type key) const { - result.m_it.object_iterator = m_value.object->find(key); - } + auto result = cend(); - return result; - } + if (is_object()) + { + result.m_it.object_iterator = m_value.object->find(key); + } - /*! + return result; + } + + /*! @brief returns the number of occurrences of a key in a JSON object Returns the number of elements with key @a key. If ObjectType is the @@ -4254,23 +4258,23 @@ class basic_json @since version 1.0.0 */ - size_type count(typename object_t::key_type key) const - { - // return 0 for all nonobject types - return is_object() ? m_value.object->count(key) : 0; - } + size_type count(typename object_t::key_type key) const + { + // return 0 for all nonobject types + return is_object() ? m_value.object->count(key) : 0; + } - /// @} + /// @} - /////////////// - // iterators // - /////////////// + /////////////// + // iterators // + /////////////// - /// @name iterators - /// @{ + /// @name iterators + /// @{ - /*! + /*! @brief returns an iterator to the first element Returns an iterator to the first element. @@ -4294,22 +4298,22 @@ class basic_json @since version 1.0.0 */ - iterator begin() noexcept - { - iterator result(this); - result.set_begin(); - return result; - } + iterator begin() noexcept + { + iterator result(this); + result.set_begin(); + return result; + } - /*! + /*! @copydoc basic_json::cbegin() */ - const_iterator begin() const noexcept - { - return cbegin(); - } + const_iterator begin() const noexcept + { + return cbegin(); + } - /*! + /*! @brief returns a const iterator to the first element Returns a const iterator to the first element. @@ -4334,14 +4338,14 @@ class basic_json @since version 1.0.0 */ - const_iterator cbegin() const noexcept - { - const_iterator result(this); - result.set_begin(); - return result; - } + const_iterator cbegin() const noexcept + { + const_iterator result(this); + result.set_begin(); + return result; + } - /*! + /*! @brief returns an iterator to one past the last element Returns an iterator to one past the last element. @@ -4365,22 +4369,22 @@ class basic_json @since version 1.0.0 */ - iterator end() noexcept - { - iterator result(this); - result.set_end(); - return result; - } + iterator end() noexcept + { + iterator result(this); + result.set_end(); + return result; + } - /*! + /*! @copydoc basic_json::cend() */ - const_iterator end() const noexcept - { - return cend(); - } + const_iterator end() const noexcept + { + return cend(); + } - /*! + /*! @brief returns a const iterator to one past the last element Returns a const iterator to one past the last element. @@ -4405,14 +4409,14 @@ class basic_json @since version 1.0.0 */ - const_iterator cend() const noexcept - { - const_iterator result(this); - result.set_end(); - return result; - } + const_iterator cend() const noexcept + { + const_iterator result(this); + result.set_end(); + return result; + } - /*! + /*! @brief returns an iterator to the reverse-beginning Returns an iterator to the reverse-beginning; that is, the last element. @@ -4435,20 +4439,20 @@ class basic_json @since version 1.0.0 */ - reverse_iterator rbegin() noexcept - { - return reverse_iterator(end()); - } + reverse_iterator rbegin() noexcept + { + return reverse_iterator(end()); + } - /*! + /*! @copydoc basic_json::crbegin() */ - const_reverse_iterator rbegin() const noexcept - { - return crbegin(); - } + const_reverse_iterator rbegin() const noexcept + { + return crbegin(); + } - /*! + /*! @brief returns an iterator to the reverse-end Returns an iterator to the reverse-end; that is, one before the first @@ -4472,20 +4476,20 @@ class basic_json @since version 1.0.0 */ - reverse_iterator rend() noexcept - { - return reverse_iterator(begin()); - } + reverse_iterator rend() noexcept + { + return reverse_iterator(begin()); + } - /*! + /*! @copydoc basic_json::crend() */ - const_reverse_iterator rend() const noexcept - { - return crend(); - } + const_reverse_iterator rend() const noexcept + { + return crend(); + } - /*! + /*! @brief returns a const reverse iterator to the last element Returns a const iterator to the reverse-beginning; that is, the last @@ -4509,12 +4513,12 @@ class basic_json @since version 1.0.0 */ - const_reverse_iterator crbegin() const noexcept - { - return const_reverse_iterator(cend()); - } + const_reverse_iterator crbegin() const noexcept + { + return const_reverse_iterator(cend()); + } - /*! + /*! @brief returns a const reverse iterator to one before the first Returns a const reverse iterator to the reverse-end; that is, one before @@ -4538,17 +4542,17 @@ class basic_json @since version 1.0.0 */ - const_reverse_iterator crend() const noexcept - { - return const_reverse_iterator(cbegin()); - } + const_reverse_iterator crend() const noexcept + { + return const_reverse_iterator(cbegin()); + } - private: - // forward declaration - template class iteration_proxy; + private: + // forward declaration + template class iteration_proxy; - public: - /*! + public: + /*! @brief wrapper to access iterator member functions in range-based for This function allows to access @ref iterator::key() and @ref @@ -4559,30 +4563,30 @@ class basic_json @note The name of this function is not yet final and may change in the future. */ - static iteration_proxy iterator_wrapper(reference cont) - { - return iteration_proxy(cont); - } + static iteration_proxy iterator_wrapper(reference cont) + { + return iteration_proxy(cont); + } - /*! + /*! @copydoc iterator_wrapper(reference) */ - static iteration_proxy iterator_wrapper(const_reference cont) - { - return iteration_proxy(cont); - } + static iteration_proxy iterator_wrapper(const_reference cont) + { + return iteration_proxy(cont); + } - /// @} + /// @} - ////////////// - // capacity // - ////////////// + ////////////// + // capacity // + ////////////// - /// @name capacity - /// @{ + /// @name capacity + /// @{ - /*! + /*! @brief checks whether the container is empty Checks if a JSON value has no elements. @@ -4619,37 +4623,37 @@ class basic_json @since version 1.0.0 */ - bool empty() const noexcept - { - switch (m_type) + bool empty() const noexcept { - case value_t::null: + switch (m_type) { - // null values are empty - return true; - } + case value_t::null: + { + // null values are empty + return true; + } - case value_t::array: - { - // delegate call to array_t::empty() - return m_value.array->empty(); - } + case value_t::array: + { + // delegate call to array_t::empty() + return m_value.array->empty(); + } - case value_t::object: - { - // delegate call to object_t::empty() - return m_value.object->empty(); - } + case value_t::object: + { + // delegate call to object_t::empty() + return m_value.object->empty(); + } - default: - { - // all other types are nonempty - return false; + default: + { + // all other types are nonempty + return false; + } } } - } - /*! + /*! @brief returns the number of elements Returns the number of elements in a JSON value. @@ -4687,37 +4691,37 @@ class basic_json @since version 1.0.0 */ - size_type size() const noexcept - { - switch (m_type) + size_type size() const noexcept { - case value_t::null: + switch (m_type) { - // null values are empty - return 0; - } + case value_t::null: + { + // null values are empty + return 0; + } - case value_t::array: - { - // delegate call to array_t::size() - return m_value.array->size(); - } + case value_t::array: + { + // delegate call to array_t::size() + return m_value.array->size(); + } - case value_t::object: - { - // delegate call to object_t::size() - return m_value.object->size(); - } + case value_t::object: + { + // delegate call to object_t::size() + return m_value.object->size(); + } - default: - { - // all other types have size 1 - return 1; + default: + { + // all other types have size 1 + return 1; + } } } - } - /*! + /*! @brief returns the maximum possible number of elements Returns the maximum number of elements a JSON value is able to hold due to @@ -4753,41 +4757,41 @@ class basic_json @since version 1.0.0 */ - size_type max_size() const noexcept - { - switch (m_type) + size_type max_size() const noexcept { - case value_t::array: + switch (m_type) { - // delegate call to array_t::max_size() - return m_value.array->max_size(); - } + case value_t::array: + { + // delegate call to array_t::max_size() + return m_value.array->max_size(); + } - case value_t::object: - { - // delegate call to object_t::max_size() - return m_value.object->max_size(); - } + case value_t::object: + { + // delegate call to object_t::max_size() + return m_value.object->max_size(); + } - default: - { - // all other types have max_size() == size() - return size(); + default: + { + // all other types have max_size() == size() + return size(); + } } } - } - /// @} + /// @} - /////////////// - // modifiers // - /////////////// + /////////////// + // modifiers // + /////////////// - /// @name modifiers - /// @{ + /// @name modifiers + /// @{ - /*! + /*! @brief clears the contents Clears the content of a JSON value and resets it to the default value as @@ -4812,60 +4816,60 @@ class basic_json @since version 1.0.0 */ - void clear() noexcept - { - switch (m_type) + void clear() noexcept { - case value_t::number_integer: + switch (m_type) { - m_value.number_integer = 0; - break; - } + case value_t::number_integer: + { + m_value.number_integer = 0; + break; + } - case value_t::number_unsigned: - { - m_value.number_unsigned = 0; - break; - } + case value_t::number_unsigned: + { + m_value.number_unsigned = 0; + break; + } - case value_t::number_float: - { - m_value.number_float = 0.0; - break; - } + case value_t::number_float: + { + m_value.number_float = 0.0; + break; + } - case value_t::boolean: - { - m_value.boolean = false; - break; - } + case value_t::boolean: + { + m_value.boolean = false; + break; + } - case value_t::string: - { - m_value.string->clear(); - break; - } + case value_t::string: + { + m_value.string->clear(); + break; + } - case value_t::array: - { - m_value.array->clear(); - break; - } + case value_t::array: + { + m_value.array->clear(); + break; + } - case value_t::object: - { - m_value.object->clear(); - break; - } + case value_t::object: + { + m_value.object->clear(); + break; + } - default: - { - break; + default: + { + break; + } } } - } - /*! + /*! @brief add an object to an array Appends the given element @a val to the end of the JSON value. If the @@ -4885,73 +4889,73 @@ class basic_json @since version 1.0.0 */ - void push_back(basic_json&& val) - { - // push_back only works for null objects or arrays - if (not(is_null() or is_array())) + void push_back(basic_json&& val) { - throw std::domain_error("cannot use push_back() with " + type_name()); - } + // push_back only works for null objects or arrays + if (not(is_null() or is_array())) + { + throw std::domain_error("cannot use push_back() with " + type_name()); + } - // transform null object into an array - if (is_null()) - { - m_type = value_t::array; - m_value = value_t::array; - assert_invariant(); - } + // transform null object into an array + if (is_null()) + { + m_type = value_t::array; + m_value = value_t::array; + assert_invariant(); + } - // add element to array (move semantics) - m_value.array->push_back(std::move(val)); - // invalidate object - val.m_type = value_t::null; - } + // add element to array (move semantics) + m_value.array->push_back(std::move(val)); + // invalidate object + val.m_type = value_t::null; + } - /*! + /*! @brief add an object to an array @copydoc push_back(basic_json&&) */ - reference operator+=(basic_json&& val) - { - push_back(std::move(val)); - return *this; - } + reference operator+=(basic_json&& val) + { + push_back(std::move(val)); + return *this; + } - /*! + /*! @brief add an object to an array @copydoc push_back(basic_json&&) */ - void push_back(const basic_json& val) - { - // push_back only works for null objects or arrays - if (not(is_null() or is_array())) + void push_back(const basic_json& val) { - throw std::domain_error("cannot use push_back() with " + type_name()); - } + // push_back only works for null objects or arrays + if (not(is_null() or is_array())) + { + throw std::domain_error("cannot use push_back() with " + type_name()); + } - // transform null object into an array - if (is_null()) - { - m_type = value_t::array; - m_value = value_t::array; - assert_invariant(); - } + // transform null object into an array + if (is_null()) + { + m_type = value_t::array; + m_value = value_t::array; + assert_invariant(); + } - // add element to array - m_value.array->push_back(val); - } + // add element to array + m_value.array->push_back(val); + } - /*! + /*! @brief add an object to an array @copydoc push_back(basic_json&&) */ - reference operator+=(const basic_json& val) - { - push_back(val); - return *this; - } + reference operator+=(const basic_json& val) + { + push_back(val); + return *this; + } - /*! + /*! @brief add an object to an object Inserts the given element @a val to the JSON object. If the function is @@ -4971,37 +4975,37 @@ class basic_json @since version 1.0.0 */ - void push_back(const typename object_t::value_type& val) - { - // push_back only works for null objects or objects - if (not(is_null() or is_object())) + void push_back(const typename object_t::value_type& val) { - throw std::domain_error("cannot use push_back() with " + type_name()); - } + // push_back only works for null objects or objects + if (not(is_null() or is_object())) + { + throw std::domain_error("cannot use push_back() with " + type_name()); + } - // transform null object into an object - if (is_null()) - { - m_type = value_t::object; - m_value = value_t::object; - assert_invariant(); - } + // transform null object into an object + if (is_null()) + { + m_type = value_t::object; + m_value = value_t::object; + assert_invariant(); + } - // add element to array - m_value.object->insert(val); - } + // add element to array + m_value.object->insert(val); + } - /*! + /*! @brief add an object to an object @copydoc push_back(const typename object_t::value_type&) */ - reference operator+=(const typename object_t::value_type& val) - { - push_back(val); - return *this; - } + reference operator+=(const typename object_t::value_type& val) + { + push_back(val); + return *this; + } - /*! + /*! @brief add an object to an object This function allows to use `push_back` with an initializer list. In case @@ -5026,30 +5030,30 @@ class basic_json @liveexample{The example shows how initializer lists are treated as objects when possible.,push_back__initializer_list} */ - void push_back(std::initializer_list init) - { - if (is_object() and init.size() == 2 and init.begin()->is_string()) - { - const string_t key = *init.begin(); - push_back(typename object_t::value_type(key, *(init.begin() + 1))); - } - else + void push_back(std::initializer_list init) { - push_back(basic_json(init)); + if (is_object() and init.size() == 2 and init.begin()->is_string()) + { + const string_t key = *init.begin(); + push_back(typename object_t::value_type(key, *(init.begin() + 1))); + } + else + { + push_back(basic_json(init)); + } } - } - /*! + /*! @brief add an object to an object @copydoc push_back(std::initializer_list) */ - reference operator+=(std::initializer_list init) - { - push_back(init); - return *this; - } + reference operator+=(std::initializer_list init) + { + push_back(init); + return *this; + } - /*! + /*! @brief inserts element Inserts element @a val before iterator @a pos. @@ -5071,38 +5075,38 @@ class basic_json @since version 1.0.0 */ - iterator insert(const_iterator pos, const basic_json& val) - { - // insert only works for arrays - if (is_array()) + iterator insert(const_iterator pos, const basic_json& val) { - // check if iterator pos fits to this JSON value - if (pos.m_object != this) + // insert only works for arrays + if (is_array()) { - throw std::domain_error("iterator does not fit current value"); - } + // check if iterator pos fits to this JSON value + if (pos.m_object != this) + { + throw std::domain_error("iterator does not fit current value"); + } - // insert to array and return iterator - iterator result(this); - result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, val); - return result; - } - else - { - throw std::domain_error("cannot use insert() with " + type_name()); + // insert to array and return iterator + iterator result(this); + result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, val); + return result; + } + else + { + throw std::domain_error("cannot use insert() with " + type_name()); + } } - } - /*! + /*! @brief inserts element @copydoc insert(const_iterator, const basic_json&) */ - iterator insert(const_iterator pos, basic_json&& val) - { - return insert(pos, val); - } + iterator insert(const_iterator pos, basic_json&& val) + { + return insert(pos, val); + } - /*! + /*! @brief inserts elements Inserts @a cnt copies of @a val before iterator @a pos. @@ -5126,29 +5130,29 @@ class basic_json @since version 1.0.0 */ - iterator insert(const_iterator pos, size_type cnt, const basic_json& val) - { - // insert only works for arrays - if (is_array()) + iterator insert(const_iterator pos, size_type cnt, const basic_json& val) { - // check if iterator pos fits to this JSON value - if (pos.m_object != this) + // insert only works for arrays + if (is_array()) { - throw std::domain_error("iterator does not fit current value"); - } + // check if iterator pos fits to this JSON value + if (pos.m_object != this) + { + throw std::domain_error("iterator does not fit current value"); + } - // insert to array and return iterator - iterator result(this); - result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, cnt, val); - return result; - } - else - { - throw std::domain_error("cannot use insert() with " + type_name()); + // insert to array and return iterator + iterator result(this); + result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, cnt, val); + return result; + } + else + { + throw std::domain_error("cannot use insert() with " + type_name()); + } } - } - /*! + /*! @brief inserts elements Inserts elements from range `[first, last)` before iterator @a pos. @@ -5178,41 +5182,41 @@ class basic_json @since version 1.0.0 */ - iterator insert(const_iterator pos, const_iterator first, const_iterator last) - { - // insert only works for arrays - if (not is_array()) + iterator insert(const_iterator pos, const_iterator first, const_iterator last) { - throw std::domain_error("cannot use insert() with " + type_name()); - } + // insert only works for arrays + if (not is_array()) + { + throw std::domain_error("cannot use insert() with " + type_name()); + } - // check if iterator pos fits to this JSON value - if (pos.m_object != this) - { - throw std::domain_error("iterator does not fit current value"); - } + // check if iterator pos fits to this JSON value + if (pos.m_object != this) + { + throw std::domain_error("iterator does not fit current value"); + } - // check if range iterators belong to the same JSON object - if (first.m_object != last.m_object) - { - throw std::domain_error("iterators do not fit"); - } + // check if range iterators belong to the same JSON object + if (first.m_object != last.m_object) + { + throw std::domain_error("iterators do not fit"); + } - if (first.m_object == this or last.m_object == this) - { - throw std::domain_error("passed iterators may not belong to container"); - } + if (first.m_object == this or last.m_object == this) + { + throw std::domain_error("passed iterators may not belong to container"); + } - // insert to array and return iterator - iterator result(this); - result.m_it.array_iterator = m_value.array->insert( - pos.m_it.array_iterator, - first.m_it.array_iterator, - last.m_it.array_iterator); - return result; - } + // insert to array and return iterator + iterator result(this); + result.m_it.array_iterator = m_value.array->insert( + pos.m_it.array_iterator, + first.m_it.array_iterator, + last.m_it.array_iterator); + return result; + } - /*! + /*! @brief inserts elements Inserts elements from initializer list @a ilist before iterator @a pos. @@ -5236,27 +5240,27 @@ class basic_json @since version 1.0.0 */ - iterator insert(const_iterator pos, std::initializer_list ilist) - { - // insert only works for arrays - if (not is_array()) + iterator insert(const_iterator pos, std::initializer_list ilist) { - throw std::domain_error("cannot use insert() with " + type_name()); - } + // insert only works for arrays + if (not is_array()) + { + throw std::domain_error("cannot use insert() with " + type_name()); + } - // check if iterator pos fits to this JSON value - if (pos.m_object != this) - { - throw std::domain_error("iterator does not fit current value"); - } + // check if iterator pos fits to this JSON value + if (pos.m_object != this) + { + throw std::domain_error("iterator does not fit current value"); + } - // insert to array and return iterator - iterator result(this); - result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, ilist); - return result; - } + // insert to array and return iterator + iterator result(this); + result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, ilist); + return result; + } - /*! + /*! @brief exchanges the values Exchanges the contents of the JSON value with those of @a other. Does not @@ -5273,19 +5277,19 @@ class basic_json @since version 1.0.0 */ - void swap(reference other) noexcept ( + void swap(reference other) noexcept ( std::is_nothrow_move_constructible::value and std::is_nothrow_move_assignable::value and std::is_nothrow_move_constructible::value and std::is_nothrow_move_assignable::value - ) - { - std::swap(m_type, other.m_type); - std::swap(m_value, other.m_value); - assert_invariant(); - } + ) + { + std::swap(m_type, other.m_type); + std::swap(m_value, other.m_value); + assert_invariant(); + } - /*! + /*! @brief exchanges the values Exchanges the contents of a JSON array with those of @a other. Does not @@ -5305,20 +5309,20 @@ class basic_json @since version 1.0.0 */ - void swap(array_t& other) - { - // swap only works for arrays - if (is_array()) - { - std::swap(*(m_value.array), other); - } - else + void swap(array_t& other) { - throw std::domain_error("cannot use swap() with " + type_name()); + // swap only works for arrays + if (is_array()) + { + std::swap(*(m_value.array), other); + } + else + { + throw std::domain_error("cannot use swap() with " + type_name()); + } } - } - /*! + /*! @brief exchanges the values Exchanges the contents of a JSON object with those of @a other. Does not @@ -5338,20 +5342,20 @@ class basic_json @since version 1.0.0 */ - void swap(object_t& other) - { - // swap only works for objects - if (is_object()) + void swap(object_t& other) { - std::swap(*(m_value.object), other); - } - else - { - throw std::domain_error("cannot use swap() with " + type_name()); + // swap only works for objects + if (is_object()) + { + std::swap(*(m_value.object), other); + } + else + { + throw std::domain_error("cannot use swap() with " + type_name()); + } } - } - /*! + /*! @brief exchanges the values Exchanges the contents of a JSON string with those of @a other. Does not @@ -5371,31 +5375,31 @@ class basic_json @since version 1.0.0 */ - void swap(string_t& other) - { - // swap only works for strings - if (is_string()) - { - std::swap(*(m_value.string), other); - } - else + void swap(string_t& other) { - throw std::domain_error("cannot use swap() with " + type_name()); + // swap only works for strings + if (is_string()) + { + std::swap(*(m_value.string), other); + } + else + { + throw std::domain_error("cannot use swap() with " + type_name()); + } } - } - /// @} + /// @} - ////////////////////////////////////////// - // lexicographical comparison operators // - ////////////////////////////////////////// + ////////////////////////////////////////// + // lexicographical comparison operators // + ////////////////////////////////////////// - /// @name lexicographical comparison operators - /// @{ + /// @name lexicographical comparison operators + /// @{ - private: - /*! + private: + /*! @brief comparison operator for JSON types Returns an ordering that is similar to Python: @@ -5404,31 +5408,31 @@ class basic_json @since version 1.0.0 */ - friend 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 + friend 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; } - }; - // 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)]; } - return order[static_cast(lhs)] < order[static_cast(rhs)]; - } - - public: - /*! + public: + /*! @brief comparison: equal Compares two JSON values for equality according to the following rules: @@ -5451,82 +5455,82 @@ class basic_json @since version 1.0.0 */ - friend bool operator==(const_reference lhs, const_reference rhs) noexcept - { - const auto lhs_type = lhs.type(); - const auto rhs_type = rhs.type(); - - if (lhs_type == rhs_type) + friend bool operator==(const_reference lhs, const_reference rhs) noexcept { - switch (lhs_type) + const auto lhs_type = lhs.type(); + const auto rhs_type = rhs.type(); + + if (lhs_type == rhs_type) { - case value_t::array: - { - return *lhs.m_value.array == *rhs.m_value.array; - } - case value_t::object: - { - return *lhs.m_value.object == *rhs.m_value.object; - } - case value_t::null: - { - return true; - } - case value_t::string: - { - return *lhs.m_value.string == *rhs.m_value.string; - } - case value_t::boolean: - { - return lhs.m_value.boolean == rhs.m_value.boolean; - } - case value_t::number_integer: - { - return lhs.m_value.number_integer == rhs.m_value.number_integer; - } - case value_t::number_unsigned: - { - return lhs.m_value.number_unsigned == rhs.m_value.number_unsigned; - } - case value_t::number_float: + switch (lhs_type) { - return lhs.m_value.number_float == rhs.m_value.number_float; - } - default: - { - return false; + case value_t::array: + { + return *lhs.m_value.array == *rhs.m_value.array; + } + case value_t::object: + { + return *lhs.m_value.object == *rhs.m_value.object; + } + case value_t::null: + { + return true; + } + case value_t::string: + { + return *lhs.m_value.string == *rhs.m_value.string; + } + case value_t::boolean: + { + return lhs.m_value.boolean == rhs.m_value.boolean; + } + case value_t::number_integer: + { + return lhs.m_value.number_integer == rhs.m_value.number_integer; + } + case value_t::number_unsigned: + { + return lhs.m_value.number_unsigned == rhs.m_value.number_unsigned; + } + case value_t::number_float: + { + return lhs.m_value.number_float == rhs.m_value.number_float; + } + default: + { + return false; + } } } - } - else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_float) - { - return static_cast(lhs.m_value.number_integer) == rhs.m_value.number_float; - } - else if (lhs_type == value_t::number_float and rhs_type == value_t::number_integer) - { - return lhs.m_value.number_float == static_cast(rhs.m_value.number_integer); - } - else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_float) - { - return static_cast(lhs.m_value.number_unsigned) == rhs.m_value.number_float; - } - else if (lhs_type == value_t::number_float and rhs_type == value_t::number_unsigned) - { - return lhs.m_value.number_float == static_cast(rhs.m_value.number_unsigned); - } - else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_integer) - { - return static_cast(lhs.m_value.number_unsigned) == rhs.m_value.number_integer; - } - else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_unsigned) - { - return lhs.m_value.number_integer == static_cast(rhs.m_value.number_unsigned); - } + else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_float) + { + return static_cast(lhs.m_value.number_integer) == rhs.m_value.number_float; + } + else if (lhs_type == value_t::number_float and rhs_type == value_t::number_integer) + { + return lhs.m_value.number_float == static_cast(rhs.m_value.number_integer); + } + else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_float) + { + return static_cast(lhs.m_value.number_unsigned) == rhs.m_value.number_float; + } + else if (lhs_type == value_t::number_float and rhs_type == value_t::number_unsigned) + { + return lhs.m_value.number_float == static_cast(rhs.m_value.number_unsigned); + } + else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_integer) + { + return static_cast(lhs.m_value.number_unsigned) == rhs.m_value.number_integer; + } + else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_unsigned) + { + return lhs.m_value.number_integer == static_cast(rhs.m_value.number_unsigned); + } - return false; - } + return false; + } - /*! + /*! @brief comparison: equal The functions compares the given JSON value against a null pointer. As the @@ -5544,21 +5548,21 @@ class basic_json @since version 1.0.0 */ - friend bool operator==(const_reference v, std::nullptr_t) noexcept - { - return v.is_null(); - } + friend bool operator==(const_reference v, std::nullptr_t) noexcept + { + return v.is_null(); + } - /*! + /*! @brief comparison: equal @copydoc operator==(const_reference, std::nullptr_t) */ - friend bool operator==(std::nullptr_t, const_reference v) noexcept - { - return v.is_null(); - } + friend bool operator==(std::nullptr_t, const_reference v) noexcept + { + return v.is_null(); + } - /*! + /*! @brief comparison: not equal Compares two JSON values for inequality by calculating `not (lhs == rhs)`. @@ -5574,12 +5578,12 @@ class basic_json @since version 1.0.0 */ - friend bool operator!=(const_reference lhs, const_reference rhs) noexcept - { - return not (lhs == rhs); - } + friend bool operator!=(const_reference lhs, const_reference rhs) noexcept + { + return not (lhs == rhs); + } - /*! + /*! @brief comparison: not equal The functions compares the given JSON value against a null pointer. As the @@ -5597,21 +5601,21 @@ class basic_json @since version 1.0.0 */ - friend bool operator!=(const_reference v, std::nullptr_t) noexcept - { - return not v.is_null(); - } + friend bool operator!=(const_reference v, std::nullptr_t) noexcept + { + return not v.is_null(); + } - /*! + /*! @brief comparison: not equal @copydoc operator!=(const_reference, std::nullptr_t) */ - friend bool operator!=(std::nullptr_t, const_reference v) noexcept - { - return not v.is_null(); - } + friend bool operator!=(std::nullptr_t, const_reference v) noexcept + { + return not v.is_null(); + } - /*! + /*! @brief comparison: less than Compares whether one JSON value @a lhs is less than another JSON value @a @@ -5635,85 +5639,85 @@ class basic_json @since version 1.0.0 */ - friend bool operator<(const_reference lhs, const_reference rhs) noexcept - { - const auto lhs_type = lhs.type(); - const auto rhs_type = rhs.type(); - - if (lhs_type == rhs_type) + friend bool operator<(const_reference lhs, const_reference rhs) noexcept { - switch (lhs_type) + const auto lhs_type = lhs.type(); + const auto rhs_type = rhs.type(); + + if (lhs_type == rhs_type) { - case value_t::array: - { - return *lhs.m_value.array < *rhs.m_value.array; - } - case value_t::object: - { - return *lhs.m_value.object < *rhs.m_value.object; - } - case value_t::null: - { - return false; - } - case value_t::string: - { - return *lhs.m_value.string < *rhs.m_value.string; - } - case value_t::boolean: - { - return lhs.m_value.boolean < rhs.m_value.boolean; - } - case value_t::number_integer: - { - return lhs.m_value.number_integer < rhs.m_value.number_integer; - } - case value_t::number_unsigned: - { - return lhs.m_value.number_unsigned < rhs.m_value.number_unsigned; - } - case value_t::number_float: - { - return lhs.m_value.number_float < rhs.m_value.number_float; - } - default: + switch (lhs_type) { - return false; + case value_t::array: + { + return *lhs.m_value.array < *rhs.m_value.array; + } + case value_t::object: + { + return *lhs.m_value.object < *rhs.m_value.object; + } + case value_t::null: + { + return false; + } + case value_t::string: + { + return *lhs.m_value.string < *rhs.m_value.string; + } + case value_t::boolean: + { + return lhs.m_value.boolean < rhs.m_value.boolean; + } + case value_t::number_integer: + { + return lhs.m_value.number_integer < rhs.m_value.number_integer; + } + case value_t::number_unsigned: + { + return lhs.m_value.number_unsigned < rhs.m_value.number_unsigned; + } + case value_t::number_float: + { + return lhs.m_value.number_float < rhs.m_value.number_float; + } + default: + { + return false; + } } } - } - else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_float) - { - return static_cast(lhs.m_value.number_integer) < rhs.m_value.number_float; - } - else if (lhs_type == value_t::number_float and rhs_type == value_t::number_integer) - { - return lhs.m_value.number_float < static_cast(rhs.m_value.number_integer); - } - else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_float) - { - return static_cast(lhs.m_value.number_unsigned) < rhs.m_value.number_float; - } - else if (lhs_type == value_t::number_float and rhs_type == value_t::number_unsigned) - { - return lhs.m_value.number_float < static_cast(rhs.m_value.number_unsigned); - } - else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_unsigned) - { - return lhs.m_value.number_integer < static_cast(rhs.m_value.number_unsigned); - } - else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_integer) - { - return static_cast(lhs.m_value.number_unsigned) < rhs.m_value.number_integer; - } + else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_float) + { + return static_cast(lhs.m_value.number_integer) < rhs.m_value.number_float; + } + else if (lhs_type == value_t::number_float and rhs_type == value_t::number_integer) + { + return lhs.m_value.number_float < static_cast(rhs.m_value.number_integer); + } + else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_float) + { + return static_cast(lhs.m_value.number_unsigned) < rhs.m_value.number_float; + } + else if (lhs_type == value_t::number_float and rhs_type == value_t::number_unsigned) + { + return lhs.m_value.number_float < static_cast(rhs.m_value.number_unsigned); + } + else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_unsigned) + { + return lhs.m_value.number_integer < static_cast(rhs.m_value.number_unsigned); + } + else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_integer) + { + return static_cast(lhs.m_value.number_unsigned) < rhs.m_value.number_integer; + } - // We only reach this line if we cannot compare values. In that case, - // we compare types. Note we have to call the operator explicitly, - // because MSVC has problems otherwise. - return operator<(lhs_type, rhs_type); - } + // We only reach this line if we cannot compare values. In that case, + // we compare types. Note we have to call the operator explicitly, + // because MSVC has problems otherwise. + return operator<(lhs_type, rhs_type); + } - /*! + /*! @brief comparison: less than or equal Compares whether one JSON value @a lhs is less than or equal to another @@ -5730,12 +5734,12 @@ class basic_json @since version 1.0.0 */ - friend bool operator<=(const_reference lhs, const_reference rhs) noexcept - { - return not (rhs < lhs); - } + friend bool operator<=(const_reference lhs, const_reference rhs) noexcept + { + return not (rhs < lhs); + } - /*! + /*! @brief comparison: greater than Compares whether one JSON value @a lhs is greater than another @@ -5752,12 +5756,12 @@ class basic_json @since version 1.0.0 */ - friend bool operator>(const_reference lhs, const_reference rhs) noexcept - { - return not (lhs <= rhs); - } + friend bool operator>(const_reference lhs, const_reference rhs) noexcept + { + return not (lhs <= rhs); + } - /*! + /*! @brief comparison: greater than or equal Compares whether one JSON value @a lhs is greater than or equal to another @@ -5774,22 +5778,22 @@ class basic_json @since version 1.0.0 */ - friend bool operator>=(const_reference lhs, const_reference rhs) noexcept - { - return not (lhs < rhs); - } + friend bool operator>=(const_reference lhs, const_reference rhs) noexcept + { + return not (lhs < rhs); + } - /// @} + /// @} - /////////////////// - // serialization // - /////////////////// + /////////////////// + // serialization // + /////////////////// - /// @name serialization - /// @{ + /// @name serialization + /// @{ - /*! + /*! @brief serialize to stream Serialize the given JSON value @a j to the output stream @a o. The JSON @@ -5815,54 +5819,54 @@ class basic_json @since version 1.0.0 */ - friend std::ostream& operator<<(std::ostream& o, const basic_json& j) - { - // read width member and use it as indentation parameter if nonzero - const bool pretty_print = (o.width() > 0); - const auto indentation = (pretty_print ? o.width() : 0); - - // reset width to 0 for subsequent calls to this stream - o.width(0); - - // fix locale problems - const auto old_locale = o.imbue(std::locale(std::locale(), new DecimalSeparator)); - // set precision - - // 6, 15 or 16 digits of precision allows round-trip IEEE 754 - // string->float->string, string->double->string or string->long - // double->string; to be safe, we read this value from - // std::numeric_limits::digits10 - const auto old_precision = o.precision(std::numeric_limits::digits10); - - // do the actual serialization - j.dump(o, pretty_print, static_cast(indentation)); - - // reset locale and precision - o.imbue(old_locale); - o.precision(old_precision); - return o; - } + friend std::ostream& operator<<(std::ostream& o, const basic_json& j) + { + // read width member and use it as indentation parameter if nonzero + const bool pretty_print = (o.width() > 0); + const auto indentation = (pretty_print ? o.width() : 0); + + // reset width to 0 for subsequent calls to this stream + o.width(0); + + // fix locale problems + const auto old_locale = o.imbue(std::locale(std::locale(), new DecimalSeparator)); + // set precision - /*! + // 6, 15 or 16 digits of precision allows round-trip IEEE 754 + // string->float->string, string->double->string or string->long + // double->string; to be safe, we read this value from + // std::numeric_limits::digits10 + const auto old_precision = o.precision(std::numeric_limits::digits10); + + // do the actual serialization + j.dump(o, pretty_print, static_cast(indentation)); + + // reset locale and precision + o.imbue(old_locale); + o.precision(old_precision); + return o; + } + + /*! @brief serialize to stream @copydoc operator<<(std::ostream&, const basic_json&) */ - friend std::ostream& operator>>(const basic_json& j, std::ostream& o) - { - return o << j; - } + friend std::ostream& operator>>(const basic_json& j, std::ostream& o) + { + return o << j; + } - /// @} + /// @} - ///////////////////// - // deserialization // - ///////////////////// + ///////////////////// + // deserialization // + ///////////////////// - /// @name deserialization - /// @{ + /// @name deserialization + /// @{ - /*! + /*! @brief deserialize from an array This function reads from an array of 1-byte values. @@ -5889,15 +5893,15 @@ class basic_json @since version 2.0.3 */ - template - static basic_json parse(T (&array)[N], - const parser_callback_t cb = nullptr) - { - // delegate the call to the iterator-range parse overload - return parse(std::begin(array), std::end(array), cb); - } + template + static basic_json parse(T (&array)[N], + const parser_callback_t cb = nullptr) + { + // delegate the call to the iterator-range parse overload + return parse(std::begin(array), std::end(array), cb); + } - /*! + /*! @brief deserialize from string literal @tparam CharT character/literal type with size of 1 byte @@ -5924,17 +5928,17 @@ class basic_json @since version 1.0.0 (originally for @ref string_t) */ - template::value and - std::is_integral::type>::value and - sizeof(typename std::remove_pointer::type) == 1, int>::type = 0> - static basic_json parse(const CharPT s, - const parser_callback_t cb = nullptr) - { - return parser(reinterpret_cast(s), cb).parse(); - } + template::value and + std::is_integral::type>::value and + sizeof(typename std::remove_pointer::type) == 1, int>::type = 0> + static basic_json parse(const CharPT s, + const parser_callback_t cb = nullptr) + { + return parser(reinterpret_cast(s), cb).parse(); + } - /*! + /*! @brief deserialize from stream @param[in,out] i stream to read a serialized JSON value from @@ -5958,22 +5962,22 @@ class basic_json @since version 1.0.0 */ - static basic_json parse(std::istream& i, - const parser_callback_t cb = nullptr) - { - return parser(i, cb).parse(); - } + static basic_json parse(std::istream& i, + const parser_callback_t cb = nullptr) + { + return parser(i, cb).parse(); + } - /*! + /*! @copydoc parse(std::istream&, const parser_callback_t) */ - static basic_json parse(std::istream&& i, - const parser_callback_t cb = nullptr) - { - return parser(i, cb).parse(); - } + static basic_json parse(std::istream&& i, + const parser_callback_t cb = nullptr) + { + return parser(i, cb).parse(); + } - /*! + /*! @brief deserialize from an iterator range with contiguous storage This function reads from an iterator range of a container with contiguous @@ -6014,37 +6018,37 @@ class basic_json @since version 2.0.3 */ - template::iterator_category>::value, int>::type = 0> - static basic_json parse(IteratorType first, IteratorType last, - const parser_callback_t cb = nullptr) - { - // assertion to check that the iterator range is indeed contiguous, - // see http://stackoverflow.com/a/35008842/266378 for more discussion - assert(std::accumulate(first, last, std::make_pair(true, 0), - [&first](std::pair res, decltype(*first) val) + template::iterator_category>::value, int>::type = 0> + static basic_json parse(IteratorType first, IteratorType last, + const parser_callback_t cb = nullptr) { - res.first &= (val == *(std::next(std::addressof(*first), res.second++))); - return res; - }).first); + // assertion to check that the iterator range is indeed contiguous, + // see http://stackoverflow.com/a/35008842/266378 for more discussion + assert(std::accumulate(first, last, std::make_pair(true, 0), + [&first](std::pair res, decltype(*first) val) + { + res.first &= (val == *(std::next(std::addressof(*first), res.second++))); + return res; + }).first); - // assertion to check that each element is 1 byte long - static_assert(sizeof(typename std::iterator_traits::value_type) == 1, - "each element in the iterator range must have the size of 1 byte"); + // assertion to check that each element is 1 byte long + static_assert(sizeof(typename std::iterator_traits::value_type) == 1, + "each element in the iterator range must have the size of 1 byte"); - // if iterator range is empty, create a parser with an empty string - // to generate "unexpected EOF" error message - if (std::distance(first, last) <= 0) - { - return parser("").parse(); - } + // if iterator range is empty, create a parser with an empty string + // to generate "unexpected EOF" error message + if (std::distance(first, last) <= 0) + { + return parser("").parse(); + } - return parser(first, last, cb).parse(); - } + return parser(first, last, cb).parse(); + } - /*! + /*! @brief deserialize from a container with contiguous storage This function reads from a container with contiguous storage of 1-byte @@ -6084,20 +6088,20 @@ class basic_json @since version 2.0.3 */ - template::value and - std::is_base_of< - std::random_access_iterator_tag, - typename std::iterator_traits()))>::iterator_category>::value - , int>::type = 0> - static basic_json parse(const ContiguousContainer& c, - const parser_callback_t cb = nullptr) - { - // delegate the call to the iterator-range parse overload - return parse(std::begin(c), std::end(c), cb); - } + template::value and + std::is_base_of< + std::random_access_iterator_tag, + typename std::iterator_traits()))>::iterator_category>::value + , int>::type = 0> + static basic_json parse(const ContiguousContainer& c, + const parser_callback_t cb = nullptr) + { + // delegate the call to the iterator-range parse overload + return parse(std::begin(c), std::end(c), cb); + } - /*! + /*! @brief deserialize from stream Deserializes an input stream to a JSON value. @@ -6120,31 +6124,31 @@ class basic_json @since version 1.0.0 */ - friend std::istream& operator<<(basic_json& j, std::istream& i) - { - j = parser(i).parse(); - return i; - } + friend std::istream& operator<<(basic_json& j, std::istream& i) + { + j = parser(i).parse(); + return i; + } - /*! + /*! @brief deserialize from stream @copydoc operator<<(basic_json&, std::istream&) */ - friend std::istream& operator>>(std::istream& i, basic_json& j) - { - j = parser(i).parse(); - return i; - } + friend std::istream& operator>>(std::istream& i, basic_json& j) + { + j = parser(i).parse(); + return i; + } - /// @} + /// @} - private: - /////////////////////////// - // convenience functions // - /////////////////////////// + private: + /////////////////////////// + // convenience functions // + /////////////////////////// - /*! + /*! @brief return the type as string Returns the type name as string to be used in error messages - usually to @@ -6156,28 +6160,28 @@ class basic_json @since version 1.0.0 */ - std::string type_name() const - { - switch (m_type) - { - case value_t::null: - return "null"; - case value_t::object: - return "object"; - case value_t::array: - return "array"; - case value_t::string: - return "string"; - case value_t::boolean: - return "boolean"; - case value_t::discarded: - return "discarded"; - default: - return "number"; + std::string type_name() const + { + switch (m_type) + { + case value_t::null: + return "null"; + case value_t::object: + return "object"; + case value_t::array: + return "array"; + case value_t::string: + return "string"; + case value_t::boolean: + return "boolean"; + case value_t::discarded: + return "discarded"; + default: + return "number"; + } } - } - /*! + /*! @brief calculates the extra space to escape a JSON string @param[in] s the string to escape @@ -6185,42 +6189,42 @@ class basic_json @complexity Linear in the length of string @a s. */ - static std::size_t extra_space(const string_t& s) noexcept - { - return std::accumulate(s.begin(), s.end(), size_t{}, - [](size_t res, typename string_t::value_type c) - { - switch (c) - { - case '"': - case '\\': - case '\b': - case '\f': - case '\n': - case '\r': - case '\t': - { - // from c (1 byte) to \x (2 bytes) - return res + 1; - } - - default: - { - if (c >= 0x00 and c <= 0x1f) - { - // from c (1 byte) to \uxxxx (6 bytes) - return res + 5; - } - else - { - return res; - } - } - } - }); - } + static std::size_t extra_space(const string_t& s) noexcept + { + return std::accumulate(s.begin(), s.end(), size_t{}, + [](size_t res, typename string_t::value_type c) + { + switch (c) + { + case '"': + case '\\': + case '\b': + case '\f': + case '\n': + case '\r': + case '\t': + { + // from c (1 byte) to \x (2 bytes) + return res + 1; + } + + default: + { + if (c >= 0x00 and c <= 0x1f) + { + // from c (1 byte) to \uxxxx (6 bytes) + return res + 5; + } + else + { + return res; + } + } + } + }); + } - /*! + /*! @brief escape a string Escape a string by replacing certain special characters by a sequence of @@ -6233,114 +6237,114 @@ class basic_json @complexity Linear in the length of string @a s. */ - static string_t escape_string(const string_t& s) - { - const auto space = extra_space(s); - if (space == 0) + static string_t escape_string(const string_t& s) { - return s; - } + const auto space = extra_space(s); + if (space == 0) + { + return s; + } - // create a result string of necessary size - string_t result(s.size() + space, '\\'); - std::size_t pos = 0; + // create a result string of necessary size + string_t result(s.size() + space, '\\'); + std::size_t pos = 0; - for (const auto& c : s) - { - switch (c) + for (const auto& c : s) { - // quotation mark (0x22) - case '"': + switch (c) { - result[pos + 1] = '"'; - pos += 2; - break; - } + // quotation mark (0x22) + case '"': + { + result[pos + 1] = '"'; + pos += 2; + break; + } - // reverse solidus (0x5c) - case '\\': - { - // nothing to change - pos += 2; - break; - } + // reverse solidus (0x5c) + case '\\': + { + // nothing to change + pos += 2; + break; + } - // backspace (0x08) - case '\b': - { - result[pos + 1] = 'b'; - pos += 2; - break; - } + // backspace (0x08) + case '\b': + { + result[pos + 1] = 'b'; + pos += 2; + break; + } - // formfeed (0x0c) - case '\f': - { - result[pos + 1] = 'f'; - pos += 2; - break; - } + // formfeed (0x0c) + case '\f': + { + result[pos + 1] = 'f'; + pos += 2; + break; + } - // newline (0x0a) - case '\n': - { - result[pos + 1] = 'n'; - pos += 2; - break; - } + // newline (0x0a) + case '\n': + { + result[pos + 1] = 'n'; + pos += 2; + break; + } - // carriage return (0x0d) - case '\r': - { - result[pos + 1] = 'r'; - pos += 2; - break; - } + // carriage return (0x0d) + case '\r': + { + result[pos + 1] = 'r'; + pos += 2; + break; + } - // horizontal tab (0x09) - case '\t': - { - result[pos + 1] = 't'; - pos += 2; - break; - } + // horizontal tab (0x09) + case '\t': + { + result[pos + 1] = 't'; + pos += 2; + break; + } - default: - { - if (c >= 0x00 and c <= 0x1f) + default: { - // convert a number 0..15 to its hex representation - // (0..f) - static const char hexify[16] = + if (c >= 0x00 and c <= 0x1f) { - '0', '1', '2', '3', '4', '5', '6', '7', - '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' - }; + // convert a number 0..15 to its hex representation + // (0..f) + static const char hexify[16] = + { + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' + }; + + // print character c as \uxxxx + for (const char m : + { 'u', '0', '0', hexify[c >> 4], hexify[c & 0x0f] + }) + { + result[++pos] = m; + } - // print character c as \uxxxx - for (const char m : - { 'u', '0', '0', hexify[c >> 4], hexify[c & 0x0f] - }) - { - result[++pos] = m; + ++pos; } - - ++pos; - } - else - { - // all other characters are added as-is - result[pos++] = c; + else + { + // all other characters are added as-is + result[pos++] = c; + } + break; } - break; } } - } - return result; - } + return result; + } - /*! + /*! @brief internal implementation of the serialization function This function is called by the public member function dump and organizes @@ -6357,164 +6361,164 @@ class basic_json @param[in] indent_step the indent level @param[in] current_indent the current indent level (only used internally) */ - void dump(std::ostream& o, - const bool pretty_print, - const unsigned int indent_step, - const unsigned int current_indent = 0) const - { - // variable to hold indentation for recursive calls - unsigned int new_indent = current_indent; - - switch (m_type) + void dump(std::ostream& o, + const bool pretty_print, + const unsigned int indent_step, + const unsigned int current_indent = 0) const { - case value_t::object: + // variable to hold indentation for recursive calls + unsigned int new_indent = current_indent; + + switch (m_type) { - if (m_value.object->empty()) + case value_t::object: { - o << "{}"; - return; - } + if (m_value.object->empty()) + { + o << "{}"; + return; + } - o << "{"; + o << "{"; - // increase indentation - if (pretty_print) - { - new_indent += indent_step; - o << "\n"; + // increase indentation + if (pretty_print) + { + new_indent += indent_step; + o << "\n"; + } + + for (auto i = m_value.object->cbegin(); i != m_value.object->cend(); ++i) + { + if (i != m_value.object->cbegin()) + { + o << (pretty_print ? ",\n" : ","); + } + o << string_t(new_indent, ' ') << "\"" + << escape_string(i->first) << "\":" + << (pretty_print ? " " : ""); + i->second.dump(o, pretty_print, indent_step, new_indent); + } + + // decrease indentation + if (pretty_print) + { + new_indent -= indent_step; + o << "\n"; + } + + o << string_t(new_indent, ' ') + "}"; + return; } - for (auto i = m_value.object->cbegin(); i != m_value.object->cend(); ++i) + case value_t::array: { - if (i != m_value.object->cbegin()) + if (m_value.array->empty()) + { + o << "[]"; + return; + } + + o << "["; + + // increase indentation + if (pretty_print) + { + new_indent += indent_step; + o << "\n"; + } + + for (auto i = m_value.array->cbegin(); i != m_value.array->cend(); ++i) + { + if (i != m_value.array->cbegin()) + { + o << (pretty_print ? ",\n" : ","); + } + o << string_t(new_indent, ' '); + i->dump(o, pretty_print, indent_step, new_indent); + } + + // decrease indentation + if (pretty_print) { - o << (pretty_print ? ",\n" : ","); + new_indent -= indent_step; + o << "\n"; } - o << string_t(new_indent, ' ') << "\"" - << escape_string(i->first) << "\":" - << (pretty_print ? " " : ""); - i->second.dump(o, pretty_print, indent_step, new_indent); + + o << string_t(new_indent, ' ') << "]"; + return; } - // decrease indentation - if (pretty_print) + case value_t::string: { - new_indent -= indent_step; - o << "\n"; + o << string_t("\"") << escape_string(*m_value.string) << "\""; + return; } - o << string_t(new_indent, ' ') + "}"; - return; - } - - case value_t::array: - { - if (m_value.array->empty()) + case value_t::boolean: { - o << "[]"; + o << (m_value.boolean ? "true" : "false"); return; } - o << "["; + case value_t::number_integer: + { + o << m_value.number_integer; + return; + } - // increase indentation - if (pretty_print) + case value_t::number_unsigned: { - new_indent += indent_step; - o << "\n"; + o << m_value.number_unsigned; + return; } - for (auto i = m_value.array->cbegin(); i != m_value.array->cend(); ++i) + case value_t::number_float: { - if (i != m_value.array->cbegin()) + if (m_value.number_float == 0) + { + // special case for zero to get "0.0"/"-0.0" + o << (std::signbit(m_value.number_float) ? "-0.0" : "0.0"); + } + else { - o << (pretty_print ? ",\n" : ","); + o << m_value.number_float; } - o << string_t(new_indent, ' '); - i->dump(o, pretty_print, indent_step, new_indent); + return; } - // decrease indentation - if (pretty_print) + case value_t::discarded: { - new_indent -= indent_step; - o << "\n"; + o << ""; + return; } - o << string_t(new_indent, ' ') << "]"; - return; - } - - case value_t::string: - { - o << string_t("\"") << escape_string(*m_value.string) << "\""; - return; - } - - case value_t::boolean: - { - o << (m_value.boolean ? "true" : "false"); - return; - } - - case value_t::number_integer: - { - o << m_value.number_integer; - return; - } - - case value_t::number_unsigned: - { - o << m_value.number_unsigned; - return; - } - - case value_t::number_float: - { - if (m_value.number_float == 0) - { - // special case for zero to get "0.0"/"-0.0" - o << (std::signbit(m_value.number_float) ? "-0.0" : "0.0"); - } - else + case value_t::null: { - o << m_value.number_float; + o << "null"; + return; } - return; - } - - case value_t::discarded: - { - o << ""; - return; - } - - case value_t::null: - { - o << "null"; - return; } } - } - private: - ////////////////////// - // member variables // - ////////////////////// + private: + ////////////////////// + // member variables // + ////////////////////// - /// the type of the current element - value_t m_type = value_t::null; + /// the type of the current element + value_t m_type = value_t::null; - /// the value of the current element - json_value m_value = {}; + /// the value of the current element + json_value m_value = {}; - private: - /////////////// - // iterators // - /////////////// + private: + /////////////// + // iterators // + /////////////// - /*! + /*! @brief an iterator for primitive JSON types This class models an iterator for primitive JSON types (boolean, number, @@ -6523,173 +6527,173 @@ class basic_json a `difference_type` variable. Value begin_value (`0`) models the begin, end_value (`1`) models past the end. */ - class primitive_iterator_t - { - public: - /// set iterator to a defined beginning - void set_begin() noexcept + class primitive_iterator_t { - m_it = begin_value; - } + public: + /// set iterator to a defined beginning + void set_begin() noexcept + { + m_it = begin_value; + } - /// set iterator to a defined past the end - void set_end() noexcept - { - m_it = end_value; - } + /// set iterator to a defined past the end + void set_end() noexcept + { + m_it = end_value; + } - /// return whether the iterator can be dereferenced - constexpr bool is_begin() const noexcept - { - return (m_it == begin_value); - } + /// return whether the iterator can be dereferenced + constexpr bool is_begin() const noexcept + { + return (m_it == begin_value); + } - /// return whether the iterator is at end - constexpr bool is_end() const noexcept - { - return (m_it == end_value); - } + /// return whether the iterator is at end + constexpr bool is_end() const noexcept + { + return (m_it == end_value); + } - /// return reference to the value to change and compare - operator difference_type& () noexcept - { - return m_it; - } + /// return reference to the value to change and compare + operator difference_type& () noexcept + { + return m_it; + } - /// return value to compare - constexpr operator difference_type () const noexcept - { - return m_it; - } + /// return value to compare + constexpr operator difference_type () const noexcept + { + return m_it; + } - private: - static constexpr difference_type begin_value = 0; - static constexpr difference_type end_value = begin_value + 1; + private: + static constexpr difference_type begin_value = 0; + static constexpr difference_type end_value = begin_value + 1; - /// iterator as signed integer type - difference_type m_it = std::numeric_limits::denorm_min(); - }; + /// iterator as signed integer type + difference_type m_it = std::numeric_limits::denorm_min(); + }; - /*! + /*! @brief an iterator value @note This structure could easily be a union, but MSVC currently does not allow unions members with complex constructors, see https://github.com/nlohmann/json/pull/105. */ - struct internal_iterator - { - /// iterator for JSON objects - typename object_t::iterator object_iterator; - /// iterator for JSON arrays - typename array_t::iterator array_iterator; - /// generic iterator for all other types - primitive_iterator_t primitive_iterator; - - /// create an uninitialized internal_iterator - internal_iterator() noexcept - : object_iterator(), array_iterator(), primitive_iterator() - {} - }; + struct internal_iterator + { + /// iterator for JSON objects + typename object_t::iterator object_iterator; + /// iterator for JSON arrays + typename array_t::iterator array_iterator; + /// generic iterator for all other types + primitive_iterator_t primitive_iterator; - /// proxy class for the iterator_wrapper functions - template - class iteration_proxy - { - private: - /// helper class for iteration - class iteration_proxy_internal - { - private: - /// the iterator - IteratorType anchor; - /// an index for arrays (used to create key names) - size_t array_index = 0; - - public: - explicit iteration_proxy_internal(IteratorType it) noexcept - : anchor(it) + /// create an uninitialized internal_iterator + internal_iterator() noexcept + : object_iterator(), array_iterator(), primitive_iterator() {} + }; - /// dereference operator (needed for range-based for) - iteration_proxy_internal& operator*() + /// proxy class for the iterator_wrapper functions + template + class iteration_proxy + { + private: + /// helper class for iteration + class iteration_proxy_internal { - return *this; - } + private: + /// the iterator + IteratorType anchor; + /// an index for arrays (used to create key names) + size_t array_index = 0; - /// increment operator (needed for range-based for) - iteration_proxy_internal& operator++() - { - ++anchor; - ++array_index; + public: + explicit iteration_proxy_internal(IteratorType it) noexcept + : anchor(it) + {} - return *this; - } + /// dereference operator (needed for range-based for) + iteration_proxy_internal& operator*() + { + return *this; + } - /// inequality operator (needed for range-based for) - bool operator!= (const iteration_proxy_internal& o) const - { - return anchor != o.anchor; - } + /// increment operator (needed for range-based for) + iteration_proxy_internal& operator++() + { + ++anchor; + ++array_index; - /// return key of the iterator - typename basic_json::string_t key() const - { - assert(anchor.m_object != nullptr); + return *this; + } - switch (anchor.m_object->type()) + /// inequality operator (needed for range-based for) + bool operator!= (const iteration_proxy_internal& o) const { - // use integer array index as key - case value_t::array: - { - return std::to_string(array_index); - } + return anchor != o.anchor; + } - // use key from the object - case value_t::object: - { - return anchor.key(); - } + /// return key of the iterator + typename basic_json::string_t key() const + { + assert(anchor.m_object != nullptr); - // use an empty key for all primitive types - default: + switch (anchor.m_object->type()) { - return ""; + // use integer array index as key + case value_t::array: + { + return std::to_string(array_index); + } + + // use key from the object + case value_t::object: + { + return anchor.key(); + } + + // use an empty key for all primitive types + default: + { + return ""; + } } } - } - /// return value of the iterator - typename IteratorType::reference value() const - { - return anchor.value(); - } - }; + /// return value of the iterator + typename IteratorType::reference value() const + { + return anchor.value(); + } + }; - /// the container to iterate - typename IteratorType::reference container; + /// the container to iterate + typename IteratorType::reference container; - public: - /// construct iteration proxy from a container - explicit iteration_proxy(typename IteratorType::reference cont) - : container(cont) - {} + public: + /// construct iteration proxy from a container + explicit iteration_proxy(typename IteratorType::reference cont) + : container(cont) + {} - /// return iterator begin (needed for range-based for) - iteration_proxy_internal begin() noexcept - { - return iteration_proxy_internal(container.begin()); - } + /// return iterator begin (needed for range-based for) + iteration_proxy_internal begin() noexcept + { + return iteration_proxy_internal(container.begin()); + } - /// return iterator end (needed for range-based for) - iteration_proxy_internal end() noexcept - { - return iteration_proxy_internal(container.end()); - } - }; + /// return iterator end (needed for range-based for) + iteration_proxy_internal end() noexcept + { + return iteration_proxy_internal(container.end()); + } + }; - public: - /*! + public: + /*! @brief a const random access iterator for the @ref basic_json class This class implements a const iterator for the @ref basic_json class. From @@ -6708,615 +6712,615 @@ class basic_json @since version 1.0.0 */ - class const_iterator : public std::iterator - { - /// allow basic_json to access private members - friend class basic_json; + class const_iterator : public std::iterator + { + /// allow basic_json to access private members + friend class basic_json; - public: - /// the type of the values when the iterator is dereferenced - using value_type = typename basic_json::value_type; - /// a type to represent differences between iterators - using difference_type = typename basic_json::difference_type; - /// defines a pointer to the type iterated over (value_type) - using pointer = typename basic_json::const_pointer; - /// defines a reference to the type iterated over (value_type) - using reference = typename basic_json::const_reference; - /// the category of the iterator - using iterator_category = std::bidirectional_iterator_tag; + public: + /// the type of the values when the iterator is dereferenced + using value_type = typename basic_json::value_type; + /// a type to represent differences between iterators + using difference_type = typename basic_json::difference_type; + /// defines a pointer to the type iterated over (value_type) + using pointer = typename basic_json::const_pointer; + /// defines a reference to the type iterated over (value_type) + using reference = typename basic_json::const_reference; + /// the category of the iterator + using iterator_category = std::bidirectional_iterator_tag; - /// default constructor - const_iterator() = default; + /// default constructor + const_iterator() = default; - /*! + /*! @brief constructor for a given JSON instance @param[in] object pointer to a JSON object for this iterator @pre object != nullptr @post The iterator is initialized; i.e. `m_object != nullptr`. */ - explicit const_iterator(pointer object) noexcept - : m_object(object) - { - assert(m_object != nullptr); - - switch (m_object->m_type) + explicit const_iterator(pointer object) noexcept + : m_object(object) { - case basic_json::value_t::object: - { - m_it.object_iterator = typename object_t::iterator(); - break; - } - - case basic_json::value_t::array: - { - m_it.array_iterator = typename array_t::iterator(); - break; - } - - default: - { - m_it.primitive_iterator = primitive_iterator_t(); - break; - } - } - } + assert(m_object != nullptr); - /*! - @brief copy constructor given a non-const iterator - @param[in] other iterator to copy from - @note It is not checked whether @a other is initialized. - */ - explicit const_iterator(const iterator& other) noexcept - : m_object(other.m_object) - { - if (m_object != nullptr) - { switch (m_object->m_type) { case basic_json::value_t::object: { - m_it.object_iterator = other.m_it.object_iterator; + m_it.object_iterator = typename object_t::iterator(); break; } case basic_json::value_t::array: { - m_it.array_iterator = other.m_it.array_iterator; + m_it.array_iterator = typename array_t::iterator(); break; } default: { - m_it.primitive_iterator = other.m_it.primitive_iterator; + m_it.primitive_iterator = primitive_iterator_t(); break; } } } - } - /*! + /*! + @brief copy constructor given a non-const iterator + @param[in] other iterator to copy from + @note It is not checked whether @a other is initialized. + */ + explicit const_iterator(const iterator& other) noexcept + : m_object(other.m_object) + { + if (m_object != nullptr) + { + switch (m_object->m_type) + { + case basic_json::value_t::object: + { + m_it.object_iterator = other.m_it.object_iterator; + break; + } + + case basic_json::value_t::array: + { + m_it.array_iterator = other.m_it.array_iterator; + break; + } + + default: + { + m_it.primitive_iterator = other.m_it.primitive_iterator; + break; + } + } + } + } + + /*! @brief copy constructor @param[in] other iterator to copy from @note It is not checked whether @a other is initialized. */ - const_iterator(const const_iterator& other) noexcept - : m_object(other.m_object), m_it(other.m_it) - {} + const_iterator(const const_iterator& other) noexcept + : m_object(other.m_object), m_it(other.m_it) + {} - /*! + /*! @brief copy assignment @param[in,out] other iterator to copy from @note It is not checked whether @a other is initialized. */ - const_iterator& operator=(const_iterator other) noexcept( + const_iterator& operator=(const_iterator other) noexcept( std::is_nothrow_move_constructible::value and std::is_nothrow_move_assignable::value and std::is_nothrow_move_constructible::value and std::is_nothrow_move_assignable::value - ) - { - std::swap(m_object, other.m_object); - std::swap(m_it, other.m_it); - return *this; - } + ) + { + std::swap(m_object, other.m_object); + std::swap(m_it, other.m_it); + return *this; + } - private: - /*! + private: + /*! @brief set the iterator to the first value @pre The iterator is initialized; i.e. `m_object != nullptr`. */ - void set_begin() noexcept - { - assert(m_object != nullptr); - - switch (m_object->m_type) + void set_begin() noexcept { - case basic_json::value_t::object: - { - m_it.object_iterator = m_object->m_value.object->begin(); - break; - } - - case basic_json::value_t::array: - { - m_it.array_iterator = m_object->m_value.array->begin(); - break; - } + assert(m_object != nullptr); - case basic_json::value_t::null: + switch (m_object->m_type) { - // set to end so begin()==end() is true: null is empty - m_it.primitive_iterator.set_end(); - break; - } + case basic_json::value_t::object: + { + m_it.object_iterator = m_object->m_value.object->begin(); + break; + } - default: - { - m_it.primitive_iterator.set_begin(); - break; + case basic_json::value_t::array: + { + m_it.array_iterator = m_object->m_value.array->begin(); + break; + } + + case basic_json::value_t::null: + { + // set to end so begin()==end() is true: null is empty + m_it.primitive_iterator.set_end(); + break; + } + + default: + { + m_it.primitive_iterator.set_begin(); + break; + } } } - } - /*! + /*! @brief set the iterator past the last value @pre The iterator is initialized; i.e. `m_object != nullptr`. */ - void set_end() noexcept - { - assert(m_object != nullptr); - - switch (m_object->m_type) + void set_end() noexcept { - case basic_json::value_t::object: - { - m_it.object_iterator = m_object->m_value.object->end(); - break; - } + assert(m_object != nullptr); - case basic_json::value_t::array: + switch (m_object->m_type) { - m_it.array_iterator = m_object->m_value.array->end(); - break; - } + case basic_json::value_t::object: + { + m_it.object_iterator = m_object->m_value.object->end(); + break; + } - default: - { - m_it.primitive_iterator.set_end(); - break; + case basic_json::value_t::array: + { + m_it.array_iterator = m_object->m_value.array->end(); + break; + } + + default: + { + m_it.primitive_iterator.set_end(); + break; + } } } - } - public: - /*! + public: + /*! @brief return a reference to the value pointed to by the iterator @pre The iterator is initialized; i.e. `m_object != nullptr`. */ - reference operator*() const - { - assert(m_object != nullptr); - - switch (m_object->m_type) + reference operator*() const { - case basic_json::value_t::object: - { - assert(m_it.object_iterator != m_object->m_value.object->end()); - return m_it.object_iterator->second; - } - - case basic_json::value_t::array: - { - assert(m_it.array_iterator != m_object->m_value.array->end()); - return *m_it.array_iterator; - } + assert(m_object != nullptr); - case basic_json::value_t::null: + switch (m_object->m_type) { - throw std::out_of_range("cannot get value"); - } + case basic_json::value_t::object: + { + assert(m_it.object_iterator != m_object->m_value.object->end()); + return m_it.object_iterator->second; + } - default: - { - if (m_it.primitive_iterator.is_begin()) + case basic_json::value_t::array: { - return *m_object; + assert(m_it.array_iterator != m_object->m_value.array->end()); + return *m_it.array_iterator; } - else + + case basic_json::value_t::null: { throw std::out_of_range("cannot get value"); } + + default: + { + if (m_it.primitive_iterator.is_begin()) + { + return *m_object; + } + else + { + throw std::out_of_range("cannot get value"); + } + } } } - } - /*! + /*! @brief dereference the iterator @pre The iterator is initialized; i.e. `m_object != nullptr`. */ - pointer operator->() const - { - assert(m_object != nullptr); - - switch (m_object->m_type) + pointer operator->() const { - case basic_json::value_t::object: - { - assert(m_it.object_iterator != m_object->m_value.object->end()); - return &(m_it.object_iterator->second); - } + assert(m_object != nullptr); - case basic_json::value_t::array: + switch (m_object->m_type) { - assert(m_it.array_iterator != m_object->m_value.array->end()); - return &*m_it.array_iterator; - } + case basic_json::value_t::object: + { + assert(m_it.object_iterator != m_object->m_value.object->end()); + return &(m_it.object_iterator->second); + } - default: - { - if (m_it.primitive_iterator.is_begin()) + case basic_json::value_t::array: { - return m_object; + assert(m_it.array_iterator != m_object->m_value.array->end()); + return &*m_it.array_iterator; } - else + + default: { - throw std::out_of_range("cannot get value"); + if (m_it.primitive_iterator.is_begin()) + { + return m_object; + } + else + { + throw std::out_of_range("cannot get value"); + } } } } - } - /*! + /*! @brief post-increment (it++) @pre The iterator is initialized; i.e. `m_object != nullptr`. */ - const_iterator operator++(int) - { - auto result = *this; - ++(*this); - return result; - } + const_iterator operator++(int) + { + auto result = *this; + ++(*this); + return result; + } - /*! + /*! @brief pre-increment (++it) @pre The iterator is initialized; i.e. `m_object != nullptr`. */ - const_iterator& operator++() - { - assert(m_object != nullptr); - - switch (m_object->m_type) + const_iterator& operator++() { - case basic_json::value_t::object: - { - std::advance(m_it.object_iterator, 1); - break; - } + assert(m_object != nullptr); - case basic_json::value_t::array: + switch (m_object->m_type) { - std::advance(m_it.array_iterator, 1); - break; - } + case basic_json::value_t::object: + { + std::advance(m_it.object_iterator, 1); + break; + } - default: - { - ++m_it.primitive_iterator; - break; + case basic_json::value_t::array: + { + std::advance(m_it.array_iterator, 1); + break; + } + + default: + { + ++m_it.primitive_iterator; + break; + } } - } - return *this; - } + return *this; + } - /*! + /*! @brief post-decrement (it--) @pre The iterator is initialized; i.e. `m_object != nullptr`. */ - const_iterator operator--(int) - { - auto result = *this; - --(*this); - return result; - } + const_iterator operator--(int) + { + auto result = *this; + --(*this); + return result; + } - /*! + /*! @brief pre-decrement (--it) @pre The iterator is initialized; i.e. `m_object != nullptr`. */ - const_iterator& operator--() - { - assert(m_object != nullptr); - - switch (m_object->m_type) + const_iterator& operator--() { - case basic_json::value_t::object: - { - std::advance(m_it.object_iterator, -1); - break; - } + assert(m_object != nullptr); - case basic_json::value_t::array: + switch (m_object->m_type) { - std::advance(m_it.array_iterator, -1); - break; - } + case basic_json::value_t::object: + { + std::advance(m_it.object_iterator, -1); + break; + } - default: - { - --m_it.primitive_iterator; - break; + case basic_json::value_t::array: + { + std::advance(m_it.array_iterator, -1); + break; + } + + default: + { + --m_it.primitive_iterator; + break; + } } - } - return *this; - } + return *this; + } - /*! + /*! @brief comparison: equal @pre The iterator is initialized; i.e. `m_object != nullptr`. */ - bool operator==(const const_iterator& other) const - { - // if objects are not the same, the comparison is undefined - if (m_object != other.m_object) + bool operator==(const const_iterator& other) const { - throw std::domain_error("cannot compare iterators of different containers"); - } - - assert(m_object != nullptr); - - switch (m_object->m_type) - { - case basic_json::value_t::object: + // if objects are not the same, the comparison is undefined + if (m_object != other.m_object) { - return (m_it.object_iterator == other.m_it.object_iterator); + throw std::domain_error("cannot compare iterators of different containers"); } - case basic_json::value_t::array: - { - return (m_it.array_iterator == other.m_it.array_iterator); - } + assert(m_object != nullptr); - default: + switch (m_object->m_type) { - return (m_it.primitive_iterator == other.m_it.primitive_iterator); + case basic_json::value_t::object: + { + return (m_it.object_iterator == other.m_it.object_iterator); + } + + case basic_json::value_t::array: + { + return (m_it.array_iterator == other.m_it.array_iterator); + } + + default: + { + return (m_it.primitive_iterator == other.m_it.primitive_iterator); + } } } - } - /*! + /*! @brief comparison: not equal @pre The iterator is initialized; i.e. `m_object != nullptr`. */ - bool operator!=(const const_iterator& other) const - { - return not operator==(other); - } + bool operator!=(const const_iterator& other) const + { + return not operator==(other); + } - /*! + /*! @brief comparison: smaller @pre The iterator is initialized; i.e. `m_object != nullptr`. */ - bool operator<(const const_iterator& other) const - { - // if objects are not the same, the comparison is undefined - if (m_object != other.m_object) - { - throw std::domain_error("cannot compare iterators of different containers"); - } - - assert(m_object != nullptr); - - switch (m_object->m_type) + bool operator<(const const_iterator& other) const { - case basic_json::value_t::object: + // if objects are not the same, the comparison is undefined + if (m_object != other.m_object) { - throw std::domain_error("cannot compare order of object iterators"); + throw std::domain_error("cannot compare iterators of different containers"); } - case basic_json::value_t::array: - { - return (m_it.array_iterator < other.m_it.array_iterator); - } + assert(m_object != nullptr); - default: + switch (m_object->m_type) { - return (m_it.primitive_iterator < other.m_it.primitive_iterator); + case basic_json::value_t::object: + { + throw std::domain_error("cannot compare order of object iterators"); + } + + case basic_json::value_t::array: + { + return (m_it.array_iterator < other.m_it.array_iterator); + } + + default: + { + return (m_it.primitive_iterator < other.m_it.primitive_iterator); + } } } - } - /*! + /*! @brief comparison: less than or equal @pre The iterator is initialized; i.e. `m_object != nullptr`. */ - bool operator<=(const const_iterator& other) const - { - return not other.operator < (*this); - } + bool operator<=(const const_iterator& other) const + { + return not other.operator < (*this); + } - /*! + /*! @brief comparison: greater than @pre The iterator is initialized; i.e. `m_object != nullptr`. */ - bool operator>(const const_iterator& other) const - { - return not operator<=(other); - } + bool operator>(const const_iterator& other) const + { + return not operator<=(other); + } - /*! + /*! @brief comparison: greater than or equal @pre The iterator is initialized; i.e. `m_object != nullptr`. */ - bool operator>=(const const_iterator& other) const - { - return not operator<(other); - } + bool operator>=(const const_iterator& other) const + { + return not operator<(other); + } - /*! + /*! @brief add to iterator @pre The iterator is initialized; i.e. `m_object != nullptr`. */ - const_iterator& operator+=(difference_type i) - { - assert(m_object != nullptr); - - switch (m_object->m_type) + const_iterator& operator+=(difference_type i) { - case basic_json::value_t::object: - { - throw std::domain_error("cannot use offsets with object iterators"); - } + assert(m_object != nullptr); - case basic_json::value_t::array: + switch (m_object->m_type) { - std::advance(m_it.array_iterator, i); - break; - } + case basic_json::value_t::object: + { + throw std::domain_error("cannot use offsets with object iterators"); + } - default: - { - m_it.primitive_iterator += i; - break; + case basic_json::value_t::array: + { + std::advance(m_it.array_iterator, i); + break; + } + + default: + { + m_it.primitive_iterator += i; + break; + } } + + return *this; } - return *this; - } - - /*! + /*! @brief subtract from iterator @pre The iterator is initialized; i.e. `m_object != nullptr`. */ - const_iterator& operator-=(difference_type i) - { - return operator+=(-i); - } + const_iterator& operator-=(difference_type i) + { + return operator+=(-i); + } - /*! + /*! @brief add to iterator @pre The iterator is initialized; i.e. `m_object != nullptr`. */ - const_iterator operator+(difference_type i) - { - auto result = *this; - result += i; - return result; - } + const_iterator operator+(difference_type i) + { + auto result = *this; + result += i; + return result; + } - /*! + /*! @brief subtract from iterator @pre The iterator is initialized; i.e. `m_object != nullptr`. */ - const_iterator operator-(difference_type i) - { - auto result = *this; - result -= i; - return result; - } + const_iterator operator-(difference_type i) + { + auto result = *this; + result -= i; + return result; + } - /*! + /*! @brief return difference @pre The iterator is initialized; i.e. `m_object != nullptr`. */ - difference_type operator-(const const_iterator& other) const - { - assert(m_object != nullptr); - - switch (m_object->m_type) + difference_type operator-(const const_iterator& other) const { - case basic_json::value_t::object: - { - throw std::domain_error("cannot use offsets with object iterators"); - } + assert(m_object != nullptr); - case basic_json::value_t::array: + switch (m_object->m_type) { - return m_it.array_iterator - other.m_it.array_iterator; - } + case basic_json::value_t::object: + { + throw std::domain_error("cannot use offsets with object iterators"); + } - default: - { - return m_it.primitive_iterator - other.m_it.primitive_iterator; + case basic_json::value_t::array: + { + return m_it.array_iterator - other.m_it.array_iterator; + } + + default: + { + return m_it.primitive_iterator - other.m_it.primitive_iterator; + } } } - } - /*! + /*! @brief access to successor @pre The iterator is initialized; i.e. `m_object != nullptr`. */ - reference operator[](difference_type n) const - { - assert(m_object != nullptr); - - switch (m_object->m_type) + reference operator[](difference_type n) const { - case basic_json::value_t::object: - { - throw std::domain_error("cannot use operator[] for object iterators"); - } - - case basic_json::value_t::array: - { - return *std::next(m_it.array_iterator, n); - } + assert(m_object != nullptr); - case basic_json::value_t::null: + switch (m_object->m_type) { - throw std::out_of_range("cannot get value"); - } + case basic_json::value_t::object: + { + throw std::domain_error("cannot use operator[] for object iterators"); + } - default: - { - if (m_it.primitive_iterator == -n) + case basic_json::value_t::array: { - return *m_object; + return *std::next(m_it.array_iterator, n); } - else + + case basic_json::value_t::null: { throw std::out_of_range("cannot get value"); } + + default: + { + if (m_it.primitive_iterator == -n) + { + return *m_object; + } + else + { + throw std::out_of_range("cannot get value"); + } + } } } - } - /*! + /*! @brief return the key of an object iterator @pre The iterator is initialized; i.e. `m_object != nullptr`. */ - typename object_t::key_type key() const - { - assert(m_object != nullptr); - - if (m_object->is_object()) + typename object_t::key_type key() const { - return m_it.object_iterator->first; - } - else - { - throw std::domain_error("cannot use key() for non-object iterators"); + assert(m_object != nullptr); + + if (m_object->is_object()) + { + return m_it.object_iterator->first; + } + else + { + throw std::domain_error("cannot use key() for non-object iterators"); + } } - } - /*! + /*! @brief return the value of an iterator @pre The iterator is initialized; i.e. `m_object != nullptr`. */ - reference value() const - { - return operator*(); - } + reference value() const + { + return operator*(); + } - private: - /// associated JSON instance - pointer m_object = nullptr; - /// the actual iterator of the associated instance - internal_iterator m_it = internal_iterator(); - }; + private: + /// associated JSON instance + pointer m_object = nullptr; + /// the actual iterator of the associated instance + internal_iterator m_it = internal_iterator(); + }; - /*! + /*! @brief a mutable random access iterator for the @ref basic_json class @requirement The class satisfies the following concept requirements: @@ -7328,130 +7332,130 @@ class basic_json @since version 1.0.0 */ - class iterator : public const_iterator - { - public: - using base_iterator = const_iterator; - using pointer = typename basic_json::pointer; - using reference = typename basic_json::reference; - - /// default constructor - iterator() = default; - - /// constructor for a given JSON instance - explicit iterator(pointer object) noexcept - : base_iterator(object) - {} - - /// copy constructor - iterator(const iterator& other) noexcept - : base_iterator(other) - {} - - /// copy assignment - iterator& operator=(iterator other) noexcept( + class iterator : public const_iterator + { + public: + using base_iterator = const_iterator; + using pointer = typename basic_json::pointer; + using reference = typename basic_json::reference; + + /// default constructor + iterator() = default; + + /// constructor for a given JSON instance + explicit iterator(pointer object) noexcept + : base_iterator(object) + {} + + /// copy constructor + iterator(const iterator& other) noexcept + : base_iterator(other) + {} + + /// copy assignment + iterator& operator=(iterator other) noexcept( std::is_nothrow_move_constructible::value and std::is_nothrow_move_assignable::value and std::is_nothrow_move_constructible::value and std::is_nothrow_move_assignable::value - ) - { - base_iterator::operator=(other); - return *this; - } + ) + { + base_iterator::operator=(other); + return *this; + } - /// return a reference to the value pointed to by the iterator - reference operator*() const - { - return const_cast(base_iterator::operator*()); - } + /// return a reference to the value pointed to by the iterator + reference operator*() const + { + return const_cast(base_iterator::operator*()); + } - /// dereference the iterator - pointer operator->() const - { - return const_cast(base_iterator::operator->()); - } + /// dereference the iterator + pointer operator->() const + { + return const_cast(base_iterator::operator->()); + } - /// post-increment (it++) - iterator operator++(int) - { - iterator result = *this; - base_iterator::operator++(); - return result; - } + /// post-increment (it++) + iterator operator++(int) + { + iterator result = *this; + base_iterator::operator++(); + return result; + } - /// pre-increment (++it) - iterator& operator++() - { - base_iterator::operator++(); - return *this; - } + /// pre-increment (++it) + iterator& operator++() + { + base_iterator::operator++(); + return *this; + } - /// post-decrement (it--) - iterator operator--(int) - { - iterator result = *this; - base_iterator::operator--(); - return result; - } + /// post-decrement (it--) + iterator operator--(int) + { + iterator result = *this; + base_iterator::operator--(); + return result; + } - /// pre-decrement (--it) - iterator& operator--() - { - base_iterator::operator--(); - return *this; - } + /// pre-decrement (--it) + iterator& operator--() + { + base_iterator::operator--(); + return *this; + } - /// add to iterator - iterator& operator+=(difference_type i) - { - base_iterator::operator+=(i); - return *this; - } + /// add to iterator + iterator& operator+=(difference_type i) + { + base_iterator::operator+=(i); + return *this; + } - /// subtract from iterator - iterator& operator-=(difference_type i) - { - base_iterator::operator-=(i); - return *this; - } + /// subtract from iterator + iterator& operator-=(difference_type i) + { + base_iterator::operator-=(i); + return *this; + } - /// add to iterator - iterator operator+(difference_type i) - { - auto result = *this; - result += i; - return result; - } + /// add to iterator + iterator operator+(difference_type i) + { + auto result = *this; + result += i; + return result; + } - /// subtract from iterator - iterator operator-(difference_type i) - { - auto result = *this; - result -= i; - return result; - } + /// subtract from iterator + iterator operator-(difference_type i) + { + auto result = *this; + result -= i; + return result; + } - /// return difference - difference_type operator-(const iterator& other) const - { - return base_iterator::operator-(other); - } + /// return difference + difference_type operator-(const iterator& other) const + { + return base_iterator::operator-(other); + } - /// access to successor - reference operator[](difference_type n) const - { - return const_cast(base_iterator::operator[](n)); - } + /// access to successor + reference operator[](difference_type n) const + { + return const_cast(base_iterator::operator[](n)); + } - /// return the value of an iterator - reference value() const - { - return const_cast(base_iterator::value()); - } - }; + /// return the value of an iterator + reference value() const + { + return const_cast(base_iterator::value()); + } + }; - /*! + /*! @brief a template for a reverse iterator class @tparam Base the base iterator type to reverse. Valid types are @ref @@ -7468,162 +7472,170 @@ class basic_json @since version 1.0.0 */ - template - class json_reverse_iterator : public std::reverse_iterator - { - public: - /// shortcut to the reverse iterator adaptor - using base_iterator = std::reverse_iterator; - /// the reference type for the pointed-to element - using reference = typename Base::reference; + template + class json_reverse_iterator : public std::reverse_iterator + { + public: + /// shortcut to the reverse iterator adaptor + using base_iterator = std::reverse_iterator; + /// the reference type for the pointed-to element + using reference = typename Base::reference; - /// create reverse iterator from iterator - json_reverse_iterator(const typename base_iterator::iterator_type& it) noexcept - : base_iterator(it) - {} + /// create reverse iterator from iterator + json_reverse_iterator(const typename base_iterator::iterator_type& it) noexcept + : base_iterator(it) + {} - /// create reverse iterator from base class - json_reverse_iterator(const base_iterator& it) noexcept - : base_iterator(it) - {} + /// create reverse iterator from base class + json_reverse_iterator(const base_iterator& it) noexcept + : base_iterator(it) + {} - /// post-increment (it++) - json_reverse_iterator operator++(int) - { - return base_iterator::operator++(1); - } + /// post-increment (it++) + json_reverse_iterator operator++(int) + { + return base_iterator::operator++(1); + } - /// pre-increment (++it) - json_reverse_iterator& operator++() - { - base_iterator::operator++(); - return *this; - } + /// pre-increment (++it) + json_reverse_iterator& operator++() + { + base_iterator::operator++(); + return *this; + } - /// post-decrement (it--) - json_reverse_iterator operator--(int) - { - return base_iterator::operator--(1); - } + /// post-decrement (it--) + json_reverse_iterator operator--(int) + { + return base_iterator::operator--(1); + } - /// pre-decrement (--it) - json_reverse_iterator& operator--() - { - base_iterator::operator--(); - return *this; - } + /// pre-decrement (--it) + json_reverse_iterator& operator--() + { + base_iterator::operator--(); + return *this; + } - /// add to iterator - json_reverse_iterator& operator+=(difference_type i) - { - base_iterator::operator+=(i); - return *this; - } + /// add to iterator + json_reverse_iterator& operator+=(difference_type i) + { + base_iterator::operator+=(i); + return *this; + } - /// add to iterator - json_reverse_iterator operator+(difference_type i) const - { - auto result = *this; - result += i; - return result; - } + /// add to iterator + json_reverse_iterator operator+(difference_type i) const + { + auto result = *this; + result += i; + return result; + } - /// subtract from iterator - json_reverse_iterator operator-(difference_type i) const - { - auto result = *this; - result -= i; - return result; - } + /// subtract from iterator + json_reverse_iterator operator-(difference_type i) const + { + auto result = *this; + result -= i; + return result; + } - /// return difference - difference_type operator-(const json_reverse_iterator& other) const - { - return this->base() - other.base(); - } + /// return difference + difference_type operator-(const json_reverse_iterator& other) const + { + return this->base() - other.base(); + } - /// access to successor - reference operator[](difference_type n) const - { - return *(this->operator+(n)); - } + /// access to successor + reference operator[](difference_type n) const + { + return *(this->operator+(n)); + } - /// return the key of an object iterator - typename object_t::key_type key() const - { - auto it = --this->base(); - return it.key(); - } + /// return the key of an object iterator + typename object_t::key_type key() const + { + auto it = --this->base(); + return it.key(); + } - /// return the value of an iterator - reference value() const - { - auto it = --this->base(); - return it.operator * (); - } - }; + /// return the value of an iterator + reference value() const + { + auto it = --this->base(); + return it.operator * (); + } + }; - private: - ////////////////////// - // lexer and parser // - ////////////////////// + private: + ////////////////////// + // lexer and parser // + ////////////////////// - /*! + /*! @brief lexical analysis This class organizes the lexical analysis during JSON deserialization. The core of it is a scanner generated by [re2c](http://re2c.org) that processes a buffer and recognizes tokens according to RFC 7159. */ - class lexer - { - public: - /// token types for the parser - enum class token_type - { - uninitialized, ///< indicating the scanner is uninitialized - literal_true, ///< the `true` literal - literal_false, ///< the `false` literal - literal_null, ///< the `null` literal - value_string, ///< a string -- use get_string() for actual value - value_number, ///< a number -- use get_number() for actual value - begin_array, ///< the character for array begin `[` - begin_object, ///< the character for object begin `{` - end_array, ///< the character for array end `]` - end_object, ///< the character for object end `}` - name_separator, ///< the name separator `:` - value_separator, ///< the value separator `,` - parse_error, ///< indicating a parse error - end_of_input ///< indicating the end of the input buffer - }; + class lexer + { + public: + /// token types for the parser + enum class token_type + { + uninitialized, ///< indicating the scanner is uninitialized + literal_true, ///< the `true` literal + literal_false, ///< the `false` literal + literal_null, ///< the `null` literal + value_string, ///< a string -- use get_string() for actual value + value_number, ///< a number -- use get_number() for actual value + begin_array, ///< the character for array begin `[` + begin_object, ///< the character for object begin `{` + end_array, ///< the character for array end `]` + end_object, ///< the character for object end `}` + name_separator, ///< the name separator `:` + value_separator, ///< the value separator `,` + parse_error, ///< indicating a parse error + end_of_input ///< indicating the end of the input buffer + }; - /// the char type to use in the lexer - using lexer_char_t = unsigned char; + /// the char type to use in the lexer + using lexer_char_t = unsigned char; - /// a lexer from a buffer with given length - lexer(const lexer_char_t* buff, const size_t len) noexcept - : m_content(buff) - { - assert(m_content != nullptr); - m_start = m_cursor = m_content; - m_limit = m_content + len; - } + /// a lexer from a buffer with given length + lexer(const lexer_char_t* buff, const size_t len) noexcept + : m_content(buff) + { + assert(m_content != nullptr); + m_start = m_cursor = m_content; + m_limit = m_content + len; + } - /// a lexer from an input stream - explicit lexer(std::istream& s) - : m_stream(&s), m_line_buffer() - { - // fill buffer - fill_line_buffer(); - } + /// a lexer from an input stream + explicit lexer(std::istream& s) + : m_stream(&s), m_line_buffer() + { + // fill buffer + fill_line_buffer(); + + // skip UTF-8 byte-order mark + if (m_line_buffer.size() >= 3 and m_line_buffer.substr(0, 3) == "\xEF\xBB\xBF") + { + m_line_buffer[0] = ' '; + m_line_buffer[1] = ' '; + m_line_buffer[2] = ' '; + } + } - // switch off unwanted functions (due to pointer members) - lexer() = delete; - lexer(const lexer&) = delete; - lexer operator=(const lexer&) = delete; + // switch off unwanted functions (due to pointer members) + lexer() = delete; + lexer(const lexer&) = delete; + lexer operator=(const lexer&) = delete; - /*! + /*! @brief create a string from one or two Unicode code points There are two cases: (1) @a codepoint1 is in the Basic Multilingual @@ -7646,112 +7658,112 @@ class basic_json @see */ - static string_t to_unicode(const std::size_t codepoint1, - const std::size_t codepoint2 = 0) - { - // calculate the code point from the given code points - std::size_t codepoint = codepoint1; - - // check if codepoint1 is a high surrogate - if (codepoint1 >= 0xD800 and codepoint1 <= 0xDBFF) + static string_t to_unicode(const std::size_t codepoint1, + const std::size_t codepoint2 = 0) { - // check if codepoint2 is a low surrogate - if (codepoint2 >= 0xDC00 and codepoint2 <= 0xDFFF) + // calculate the code point from the given code points + std::size_t codepoint = codepoint1; + + // check if codepoint1 is a high surrogate + if (codepoint1 >= 0xD800 and codepoint1 <= 0xDBFF) { - codepoint = - // high surrogate occupies the most significant 22 bits - (codepoint1 << 10) - // low surrogate occupies the least significant 15 bits - + codepoint2 - // there is still the 0xD800, 0xDC00 and 0x10000 noise - // in the result so we have to subtract with: - // (0xD800 << 10) + DC00 - 0x10000 = 0x35FDC00 - - 0x35FDC00; - } + // check if codepoint2 is a low surrogate + if (codepoint2 >= 0xDC00 and codepoint2 <= 0xDFFF) + { + codepoint = + // high surrogate occupies the most significant 22 bits + (codepoint1 << 10) + // low surrogate occupies the least significant 15 bits + + codepoint2 + // there is still the 0xD800, 0xDC00 and 0x10000 noise + // in the result so we have to subtract with: + // (0xD800 << 10) + DC00 - 0x10000 = 0x35FDC00 + - 0x35FDC00; + } + else + { + throw std::invalid_argument("missing or wrong low surrogate"); + } + } + + string_t result; + + if (codepoint < 0x80) + { + // 1-byte characters: 0xxxxxxx (ASCII) + result.append(1, static_cast(codepoint)); + } + else if (codepoint <= 0x7ff) + { + // 2-byte characters: 110xxxxx 10xxxxxx + result.append(1, static_cast(0xC0 | ((codepoint >> 6) & 0x1F))); + result.append(1, static_cast(0x80 | (codepoint & 0x3F))); + } + else if (codepoint <= 0xffff) + { + // 3-byte characters: 1110xxxx 10xxxxxx 10xxxxxx + result.append(1, static_cast(0xE0 | ((codepoint >> 12) & 0x0F))); + result.append(1, static_cast(0x80 | ((codepoint >> 6) & 0x3F))); + result.append(1, static_cast(0x80 | (codepoint & 0x3F))); + } + else if (codepoint <= 0x10ffff) + { + // 4-byte characters: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx + result.append(1, static_cast(0xF0 | ((codepoint >> 18) & 0x07))); + result.append(1, static_cast(0x80 | ((codepoint >> 12) & 0x3F))); + result.append(1, static_cast(0x80 | ((codepoint >> 6) & 0x3F))); + result.append(1, static_cast(0x80 | (codepoint & 0x3F))); + } else { - throw std::invalid_argument("missing or wrong low surrogate"); + throw std::out_of_range("code points above 0x10FFFF are invalid"); } - } - - string_t result; - if (codepoint < 0x80) - { - // 1-byte characters: 0xxxxxxx (ASCII) - result.append(1, static_cast(codepoint)); - } - else if (codepoint <= 0x7ff) - { - // 2-byte characters: 110xxxxx 10xxxxxx - result.append(1, static_cast(0xC0 | ((codepoint >> 6) & 0x1F))); - result.append(1, static_cast(0x80 | (codepoint & 0x3F))); - } - else if (codepoint <= 0xffff) - { - // 3-byte characters: 1110xxxx 10xxxxxx 10xxxxxx - result.append(1, static_cast(0xE0 | ((codepoint >> 12) & 0x0F))); - result.append(1, static_cast(0x80 | ((codepoint >> 6) & 0x3F))); - result.append(1, static_cast(0x80 | (codepoint & 0x3F))); - } - else if (codepoint <= 0x10ffff) - { - // 4-byte characters: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx - result.append(1, static_cast(0xF0 | ((codepoint >> 18) & 0x07))); - result.append(1, static_cast(0x80 | ((codepoint >> 12) & 0x3F))); - result.append(1, static_cast(0x80 | ((codepoint >> 6) & 0x3F))); - result.append(1, static_cast(0x80 | (codepoint & 0x3F))); - } - else - { - throw std::out_of_range("code points above 0x10FFFF are invalid"); + return result; } - return result; - } - - /// return name of values of type token_type (only used for errors) - static std::string token_type_name(const token_type t) - { - switch (t) - { - case token_type::uninitialized: - return ""; - case token_type::literal_true: - return "true literal"; - case token_type::literal_false: - return "false literal"; - case token_type::literal_null: - return "null literal"; - case token_type::value_string: - return "string literal"; - case token_type::value_number: - return "number literal"; - case token_type::begin_array: - return "'['"; - case token_type::begin_object: - return "'{'"; - case token_type::end_array: - return "']'"; - case token_type::end_object: - return "'}'"; - case token_type::name_separator: - return "':'"; - case token_type::value_separator: - return "','"; - case token_type::parse_error: - return ""; - case token_type::end_of_input: - return "end of input"; - default: - { - // catch non-enum values - return "unknown token"; // LCOV_EXCL_LINE + /// return name of values of type token_type (only used for errors) + static std::string token_type_name(const token_type t) + { + switch (t) + { + case token_type::uninitialized: + return ""; + case token_type::literal_true: + return "true literal"; + case token_type::literal_false: + return "false literal"; + case token_type::literal_null: + return "null literal"; + case token_type::value_string: + return "string literal"; + case token_type::value_number: + return "number literal"; + case token_type::begin_array: + return "'['"; + case token_type::begin_object: + return "'{'"; + case token_type::end_array: + return "']'"; + case token_type::end_object: + return "'}'"; + case token_type::name_separator: + return "':'"; + case token_type::value_separator: + return "','"; + case token_type::parse_error: + return ""; + case token_type::end_of_input: + return "end of input"; + default: + { + // catch non-enum values + return "unknown token"; // LCOV_EXCL_LINE + } } } - } - /*! + /*! This function implements a scanner for JSON. It is specified using regular expressions that try to follow RFC 7159 as close as possible. These regular expressions are then translated into a minimized @@ -7772,789 +7784,933 @@ class basic_json infinite sequence of whitespace or byte-order-marks. This contradicts the assumption of finite input, q.e.d. */ - token_type scan() - { - while (true) + token_type scan() { - // pointer for backtracking information - m_marker = nullptr; + while (true) + { + // pointer for backtracking information + m_marker = nullptr; - // remember the begin of the token - m_start = m_cursor; - assert(m_start != nullptr); + // remember the begin of the token + m_start = m_cursor; + assert(m_start != nullptr); - { - lexer_char_t yych; - unsigned int yyaccept = 0; - static const unsigned char yybm[] = - { - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 32, 32, 0, 0, 32, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 160, 128, 0, 128, 128, 128, 128, 128, - 128, 128, 128, 128, 128, 128, 128, 128, - 192, 192, 192, 192, 192, 192, 192, 192, - 192, 192, 128, 128, 128, 128, 128, 128, - 128, 128, 128, 128, 128, 128, 128, 128, - 128, 128, 128, 128, 128, 128, 128, 128, - 128, 128, 128, 128, 128, 128, 128, 128, - 128, 128, 128, 128, 0, 128, 128, 128, - 128, 128, 128, 128, 128, 128, 128, 128, - 128, 128, 128, 128, 128, 128, 128, 128, - 128, 128, 128, 128, 128, 128, 128, 128, - 128, 128, 128, 128, 128, 128, 128, 128, - 128, 128, 128, 128, 128, 128, 128, 128, - 128, 128, 128, 128, 128, 128, 128, 128, - 128, 128, 128, 128, 128, 128, 128, 128, - 128, 128, 128, 128, 128, 128, 128, 128, - 128, 128, 128, 128, 128, 128, 128, 128, - 128, 128, 128, 128, 128, 128, 128, 128, - 128, 128, 128, 128, 128, 128, 128, 128, - 128, 128, 128, 128, 128, 128, 128, 128, - 128, 128, 128, 128, 128, 128, 128, 128, - 128, 128, 128, 128, 128, 128, 128, 128, - 128, 128, 128, 128, 128, 128, 128, 128, - 128, 128, 128, 128, 128, 128, 128, 128, - 128, 128, 128, 128, 128, 128, 128, 128, - 128, 128, 128, 128, 128, 128, 128, 128, - 128, 128, 128, 128, 128, 128, 128, 128, - 128, 128, 128, 128, 128, 128, 128, 128, - }; - if ((m_limit - m_cursor) < 5) - { - fill_line_buffer(); - } - yych = *m_cursor; - if (yybm[0 + yych] & 32) - { - goto basic_json_parser_6; - } - if (yych <= '\\') - { - if (yych <= '-') - { - if (yych <= '"') + { + lexer_char_t yych; + unsigned int yyaccept = 0; + static const unsigned char yybm[] = + { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 32, 32, 0, 0, 32, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 160, 128, 0, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 192, 192, 192, 192, 192, 192, 192, 192, + 192, 192, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 0, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + }; + if ((m_limit - m_cursor) < 5) + { + fill_line_buffer(5); // LCOV_EXCL_LINE + } + yych = *m_cursor; + if (yybm[0 + yych] & 32) + { + goto basic_json_parser_6; + } + if (yych <= '[') + { + if (yych <= '-') { - if (yych <= 0x00) + if (yych <= '"') { - goto basic_json_parser_2; + if (yych <= 0x00) + { + goto basic_json_parser_2; + } + if (yych <= '!') + { + goto basic_json_parser_4; + } + goto basic_json_parser_9; } - if (yych <= '!') + else { - goto basic_json_parser_4; + if (yych <= '+') + { + goto basic_json_parser_4; + } + if (yych <= ',') + { + goto basic_json_parser_10; + } + goto basic_json_parser_12; } - goto basic_json_parser_9; } else { - if (yych <= '+') + if (yych <= '9') { - goto basic_json_parser_4; + if (yych <= '/') + { + goto basic_json_parser_4; + } + if (yych <= '0') + { + goto basic_json_parser_13; + } + goto basic_json_parser_15; } - if (yych <= ',') + else { - goto basic_json_parser_10; + if (yych <= ':') + { + goto basic_json_parser_17; + } + if (yych <= 'Z') + { + goto basic_json_parser_4; + } + goto basic_json_parser_19; } - goto basic_json_parser_12; } } else { - if (yych <= '9') + if (yych <= 'n') { - if (yych <= '/') + if (yych <= 'e') { + if (yych == ']') + { + goto basic_json_parser_21; + } goto basic_json_parser_4; } - if (yych <= '0') + else { - goto basic_json_parser_13; + if (yych <= 'f') + { + goto basic_json_parser_23; + } + if (yych <= 'm') + { + goto basic_json_parser_4; + } + goto basic_json_parser_24; } - goto basic_json_parser_15; } else { - if (yych <= ':') + if (yych <= 'z') { - goto basic_json_parser_17; + if (yych == 't') + { + goto basic_json_parser_25; + } + goto basic_json_parser_4; } - if (yych == '[') + else { - goto basic_json_parser_19; + if (yych <= '{') + { + goto basic_json_parser_26; + } + if (yych == '}') + { + goto basic_json_parser_28; + } + goto basic_json_parser_4; } - goto basic_json_parser_4; } } - } - else - { - if (yych <= 't') + basic_json_parser_2: + ++m_cursor; { - if (yych <= 'f') + last_token_type = token_type::end_of_input; + break; + } + basic_json_parser_4: + ++m_cursor; + basic_json_parser_5: + { + last_token_type = token_type::parse_error; + break; + } + basic_json_parser_6: + ++m_cursor; + if (m_limit <= m_cursor) + { + fill_line_buffer(1); // LCOV_EXCL_LINE + } + yych = *m_cursor; + if (yybm[0 + yych] & 32) + { + goto basic_json_parser_6; + } + { + continue; + } + basic_json_parser_9: + yyaccept = 0; + yych = *(m_marker = ++m_cursor); + if (yych <= 0x1F) + { + goto basic_json_parser_5; + } + if (yych <= 0x7F) + { + goto basic_json_parser_31; + } + if (yych <= 0xC1) + { + goto basic_json_parser_5; + } + if (yych <= 0xF4) + { + goto basic_json_parser_31; + } + goto basic_json_parser_5; + basic_json_parser_10: + ++m_cursor; + { + last_token_type = token_type::value_separator; + break; + } + basic_json_parser_12: + yych = *++m_cursor; + if (yych <= '/') + { + goto basic_json_parser_5; + } + if (yych <= '0') + { + goto basic_json_parser_13; + } + if (yych <= '9') + { + goto basic_json_parser_15; + } + goto basic_json_parser_5; + basic_json_parser_13: + yyaccept = 1; + yych = *(m_marker = ++m_cursor); + if (yych <= 'D') + { + if (yych == '.') + { + goto basic_json_parser_43; + } + } + else + { + if (yych <= 'E') + { + goto basic_json_parser_44; + } + if (yych == 'e') + { + goto basic_json_parser_44; + } + } + basic_json_parser_14: + { + last_token_type = token_type::value_number; + break; + } + basic_json_parser_15: + yyaccept = 1; + m_marker = ++m_cursor; + if ((m_limit - m_cursor) < 3) + { + fill_line_buffer(3); // LCOV_EXCL_LINE + } + yych = *m_cursor; + if (yybm[0 + yych] & 64) + { + goto basic_json_parser_15; + } + if (yych <= 'D') + { + if (yych == '.') + { + goto basic_json_parser_43; + } + goto basic_json_parser_14; + } + else + { + if (yych <= 'E') + { + goto basic_json_parser_44; + } + if (yych == 'e') { - if (yych <= ']') + goto basic_json_parser_44; + } + goto basic_json_parser_14; + } + basic_json_parser_17: + ++m_cursor; + { + last_token_type = token_type::name_separator; + break; + } + basic_json_parser_19: + ++m_cursor; + { + last_token_type = token_type::begin_array; + break; + } + basic_json_parser_21: + ++m_cursor; + { + last_token_type = token_type::end_array; + break; + } + basic_json_parser_23: + yyaccept = 0; + yych = *(m_marker = ++m_cursor); + if (yych == 'a') + { + goto basic_json_parser_45; + } + goto basic_json_parser_5; + basic_json_parser_24: + yyaccept = 0; + yych = *(m_marker = ++m_cursor); + if (yych == 'u') + { + goto basic_json_parser_46; + } + goto basic_json_parser_5; + basic_json_parser_25: + yyaccept = 0; + yych = *(m_marker = ++m_cursor); + if (yych == 'r') + { + goto basic_json_parser_47; + } + goto basic_json_parser_5; + basic_json_parser_26: + ++m_cursor; + { + last_token_type = token_type::begin_object; + break; + } + basic_json_parser_28: + ++m_cursor; + { + last_token_type = token_type::end_object; + break; + } + basic_json_parser_30: + ++m_cursor; + if (m_limit <= m_cursor) + { + fill_line_buffer(1); // LCOV_EXCL_LINE + } + yych = *m_cursor; + basic_json_parser_31: + if (yybm[0 + yych] & 128) + { + goto basic_json_parser_30; + } + if (yych <= 0xE0) + { + if (yych <= '\\') + { + if (yych <= 0x1F) { - goto basic_json_parser_21; + goto basic_json_parser_32; } - if (yych <= 'e') + if (yych <= '"') { - goto basic_json_parser_4; + goto basic_json_parser_33; } - goto basic_json_parser_23; + goto basic_json_parser_35; } else { - if (yych == 'n') + if (yych <= 0xC1) { - goto basic_json_parser_24; + goto basic_json_parser_32; } - if (yych <= 's') + if (yych <= 0xDF) { - goto basic_json_parser_4; + goto basic_json_parser_36; + } + goto basic_json_parser_37; + } + } + else + { + if (yych <= 0xEF) + { + if (yych == 0xED) + { + goto basic_json_parser_39; + } + goto basic_json_parser_38; + } + else + { + if (yych <= 0xF0) + { + goto basic_json_parser_40; + } + if (yych <= 0xF3) + { + goto basic_json_parser_41; + } + if (yych <= 0xF4) + { + goto basic_json_parser_42; } - goto basic_json_parser_25; } } + basic_json_parser_32: + m_cursor = m_marker; + if (yyaccept == 0) + { + goto basic_json_parser_5; + } else { - if (yych <= '|') + goto basic_json_parser_14; + } + basic_json_parser_33: + ++m_cursor; + { + last_token_type = token_type::value_string; + break; + } + basic_json_parser_35: + ++m_cursor; + if (m_limit <= m_cursor) + { + fill_line_buffer(1); // LCOV_EXCL_LINE + } + yych = *m_cursor; + if (yych <= 'e') + { + if (yych <= '/') { - if (yych == '{') + if (yych == '"') { - goto basic_json_parser_26; + goto basic_json_parser_30; } - goto basic_json_parser_4; + if (yych <= '.') + { + goto basic_json_parser_32; + } + goto basic_json_parser_30; } else { - if (yych <= '}') + if (yych <= '\\') + { + if (yych <= '[') + { + goto basic_json_parser_32; + } + goto basic_json_parser_30; + } + else + { + if (yych == 'b') + { + goto basic_json_parser_30; + } + goto basic_json_parser_32; + } + } + } + else + { + if (yych <= 'q') + { + if (yych <= 'f') { - goto basic_json_parser_28; + goto basic_json_parser_30; } - if (yych == 0xEF) + if (yych == 'n') { goto basic_json_parser_30; } - goto basic_json_parser_4; + goto basic_json_parser_32; + } + else + { + if (yych <= 's') + { + if (yych <= 'r') + { + goto basic_json_parser_30; + } + goto basic_json_parser_32; + } + else + { + if (yych <= 't') + { + goto basic_json_parser_30; + } + if (yych <= 'u') + { + goto basic_json_parser_48; + } + goto basic_json_parser_32; + } } } - } -basic_json_parser_2: - ++m_cursor; - { - last_token_type = token_type::end_of_input; - break; - } -basic_json_parser_4: - ++m_cursor; -basic_json_parser_5: - { - last_token_type = token_type::parse_error; - break; - } -basic_json_parser_6: - ++m_cursor; - if (m_limit <= m_cursor) - { - fill_line_buffer(); - } - yych = *m_cursor; - if (yybm[0 + yych] & 32) - { - goto basic_json_parser_6; - } - { - continue; - } -basic_json_parser_9: - yyaccept = 0; - yych = *(m_marker = ++m_cursor); - if (yych <= 0x1F) - { - goto basic_json_parser_5; - } - goto basic_json_parser_32; -basic_json_parser_10: - ++m_cursor; - { - last_token_type = token_type::value_separator; - break; - } -basic_json_parser_12: - yych = *++m_cursor; - if (yych <= '/') - { - goto basic_json_parser_5; - } - if (yych <= '0') - { - goto basic_json_parser_13; - } - if (yych <= '9') - { - goto basic_json_parser_15; - } - goto basic_json_parser_5; -basic_json_parser_13: - yyaccept = 1; - yych = *(m_marker = ++m_cursor); - if (yych <= 'D') - { - if (yych == '.') + basic_json_parser_36: + ++m_cursor; + if (m_limit <= m_cursor) { - goto basic_json_parser_37; + fill_line_buffer(1); // LCOV_EXCL_LINE } - } - else - { - if (yych <= 'E') + yych = *m_cursor; + if (yych <= 0x7F) { - goto basic_json_parser_38; + goto basic_json_parser_32; } - if (yych == 'e') + if (yych <= 0xBF) + { + goto basic_json_parser_30; + } + goto basic_json_parser_32; + basic_json_parser_37: + ++m_cursor; + if (m_limit <= m_cursor) + { + fill_line_buffer(1); // LCOV_EXCL_LINE + } + yych = *m_cursor; + if (yych <= 0x9F) + { + goto basic_json_parser_32; + } + if (yych <= 0xBF) + { + goto basic_json_parser_36; + } + goto basic_json_parser_32; + basic_json_parser_38: + ++m_cursor; + if (m_limit <= m_cursor) + { + fill_line_buffer(1); // LCOV_EXCL_LINE + } + yych = *m_cursor; + if (yych <= 0x7F) + { + goto basic_json_parser_32; + } + if (yych <= 0xBF) + { + goto basic_json_parser_36; + } + goto basic_json_parser_32; + basic_json_parser_39: + ++m_cursor; + if (m_limit <= m_cursor) + { + fill_line_buffer(1); // LCOV_EXCL_LINE + } + yych = *m_cursor; + if (yych <= 0x7F) + { + goto basic_json_parser_32; + } + if (yych <= 0x9F) + { + goto basic_json_parser_36; + } + goto basic_json_parser_32; + basic_json_parser_40: + ++m_cursor; + if (m_limit <= m_cursor) + { + fill_line_buffer(1); // LCOV_EXCL_LINE + } + yych = *m_cursor; + if (yych <= 0x8F) + { + goto basic_json_parser_32; + } + if (yych <= 0xBF) { goto basic_json_parser_38; } - } -basic_json_parser_14: - { - last_token_type = token_type::value_number; - break; - } -basic_json_parser_15: - yyaccept = 1; - m_marker = ++m_cursor; - if ((m_limit - m_cursor) < 3) - { - fill_line_buffer(); - } - yych = *m_cursor; - if (yybm[0 + yych] & 64) - { - goto basic_json_parser_15; - } - if (yych <= 'D') - { - if (yych == '.') + goto basic_json_parser_32; + basic_json_parser_41: + ++m_cursor; + if (m_limit <= m_cursor) { - goto basic_json_parser_37; + fill_line_buffer(1); // LCOV_EXCL_LINE } - goto basic_json_parser_14; - } - else - { - if (yych <= 'E') + yych = *m_cursor; + if (yych <= 0x7F) + { + goto basic_json_parser_32; + } + if (yych <= 0xBF) { goto basic_json_parser_38; } - if (yych == 'e') + goto basic_json_parser_32; + basic_json_parser_42: + ++m_cursor; + if (m_limit <= m_cursor) + { + fill_line_buffer(1); // LCOV_EXCL_LINE + } + yych = *m_cursor; + if (yych <= 0x7F) + { + goto basic_json_parser_32; + } + if (yych <= 0x8F) { goto basic_json_parser_38; } - goto basic_json_parser_14; - } -basic_json_parser_17: - ++m_cursor; - { - last_token_type = token_type::name_separator; - break; - } -basic_json_parser_19: - ++m_cursor; - { - last_token_type = token_type::begin_array; - break; - } -basic_json_parser_21: - ++m_cursor; - { - last_token_type = token_type::end_array; - break; - } -basic_json_parser_23: - yyaccept = 0; - yych = *(m_marker = ++m_cursor); - if (yych == 'a') - { - goto basic_json_parser_39; - } - goto basic_json_parser_5; -basic_json_parser_24: - yyaccept = 0; - yych = *(m_marker = ++m_cursor); - if (yych == 'u') - { - goto basic_json_parser_40; - } - goto basic_json_parser_5; -basic_json_parser_25: - yyaccept = 0; - yych = *(m_marker = ++m_cursor); - if (yych == 'r') - { - goto basic_json_parser_41; - } - goto basic_json_parser_5; -basic_json_parser_26: - ++m_cursor; - { - last_token_type = token_type::begin_object; - break; - } -basic_json_parser_28: - ++m_cursor; - { - last_token_type = token_type::end_object; - break; - } -basic_json_parser_30: - yyaccept = 0; - yych = *(m_marker = ++m_cursor); - if (yych == 0xBB) - { - goto basic_json_parser_42; - } - goto basic_json_parser_5; -basic_json_parser_31: - ++m_cursor; - if (m_limit <= m_cursor) - { - fill_line_buffer(); - } - yych = *m_cursor; -basic_json_parser_32: - if (yybm[0 + yych] & 128) - { - goto basic_json_parser_31; - } - if (yych <= 0x1F) - { - goto basic_json_parser_33; - } - if (yych <= '"') - { - goto basic_json_parser_34; - } - goto basic_json_parser_36; -basic_json_parser_33: - m_cursor = m_marker; - if (yyaccept == 0) - { - goto basic_json_parser_5; - } - else - { - goto basic_json_parser_14; - } -basic_json_parser_34: - ++m_cursor; - { - last_token_type = token_type::value_string; - break; - } -basic_json_parser_36: - ++m_cursor; - if (m_limit <= m_cursor) - { - fill_line_buffer(); - } - yych = *m_cursor; - if (yych <= 'e') - { + goto basic_json_parser_32; + basic_json_parser_43: + yych = *++m_cursor; if (yych <= '/') { - if (yych == '"') + goto basic_json_parser_32; + } + if (yych <= '9') + { + goto basic_json_parser_49; + } + goto basic_json_parser_32; + basic_json_parser_44: + yych = *++m_cursor; + if (yych <= ',') + { + if (yych == '+') + { + goto basic_json_parser_51; + } + goto basic_json_parser_32; + } + else + { + if (yych <= '-') + { + goto basic_json_parser_51; + } + if (yych <= '/') + { + goto basic_json_parser_32; + } + if (yych <= '9') + { + goto basic_json_parser_52; + } + goto basic_json_parser_32; + } + basic_json_parser_45: + yych = *++m_cursor; + if (yych == 'l') + { + goto basic_json_parser_54; + } + goto basic_json_parser_32; + basic_json_parser_46: + yych = *++m_cursor; + if (yych == 'l') + { + goto basic_json_parser_55; + } + goto basic_json_parser_32; + basic_json_parser_47: + yych = *++m_cursor; + if (yych == 'u') + { + goto basic_json_parser_56; + } + goto basic_json_parser_32; + basic_json_parser_48: + ++m_cursor; + if (m_limit <= m_cursor) + { + fill_line_buffer(1); // LCOV_EXCL_LINE + } + yych = *m_cursor; + if (yych <= '@') + { + if (yych <= '/') { - goto basic_json_parser_31; + goto basic_json_parser_32; } - if (yych <= '.') + if (yych <= '9') { - goto basic_json_parser_33; + goto basic_json_parser_57; } - goto basic_json_parser_31; + goto basic_json_parser_32; } else { - if (yych <= '\\') + if (yych <= 'F') { - if (yych <= '[') - { - goto basic_json_parser_33; - } - goto basic_json_parser_31; + goto basic_json_parser_57; } - else + if (yych <= '`') { - if (yych == 'b') - { - goto basic_json_parser_31; - } - goto basic_json_parser_33; + goto basic_json_parser_32; + } + if (yych <= 'f') + { + goto basic_json_parser_57; } + goto basic_json_parser_32; } - } - else - { - if (yych <= 'q') + basic_json_parser_49: + yyaccept = 1; + m_marker = ++m_cursor; + if ((m_limit - m_cursor) < 3) { - if (yych <= 'f') + fill_line_buffer(3); // LCOV_EXCL_LINE + } + yych = *m_cursor; + if (yych <= 'D') + { + if (yych <= '/') { - goto basic_json_parser_31; + goto basic_json_parser_14; } - if (yych == 'n') + if (yych <= '9') { - goto basic_json_parser_31; + goto basic_json_parser_49; } - goto basic_json_parser_33; + goto basic_json_parser_14; } else { - if (yych <= 's') + if (yych <= 'E') { - if (yych <= 'r') - { - goto basic_json_parser_31; - } - goto basic_json_parser_33; + goto basic_json_parser_44; } - else + if (yych == 'e') { - if (yych <= 't') - { - goto basic_json_parser_31; - } - if (yych <= 'u') - { - goto basic_json_parser_43; - } - goto basic_json_parser_33; + goto basic_json_parser_44; } + goto basic_json_parser_14; } - } -basic_json_parser_37: - yych = *++m_cursor; - if (yych <= '/') - { - goto basic_json_parser_33; - } - if (yych <= '9') - { - goto basic_json_parser_44; - } - goto basic_json_parser_33; -basic_json_parser_38: - yych = *++m_cursor; - if (yych <= ',') - { - if (yych == '+') - { - goto basic_json_parser_46; - } - goto basic_json_parser_33; - } - else - { - if (yych <= '-') - { - goto basic_json_parser_46; - } - if (yych <= '/') - { - goto basic_json_parser_33; - } - if (yych <= '9') - { - goto basic_json_parser_47; - } - goto basic_json_parser_33; - } -basic_json_parser_39: - yych = *++m_cursor; - if (yych == 'l') - { - goto basic_json_parser_49; - } - goto basic_json_parser_33; -basic_json_parser_40: - yych = *++m_cursor; - if (yych == 'l') - { - goto basic_json_parser_50; - } - goto basic_json_parser_33; -basic_json_parser_41: - yych = *++m_cursor; - if (yych == 'u') - { - goto basic_json_parser_51; - } - goto basic_json_parser_33; -basic_json_parser_42: - yych = *++m_cursor; - if (yych == 0xBF) - { - goto basic_json_parser_52; - } - goto basic_json_parser_33; -basic_json_parser_43: - ++m_cursor; - if (m_limit <= m_cursor) - { - fill_line_buffer(); - } - yych = *m_cursor; - if (yych <= '@') - { + basic_json_parser_51: + yych = *++m_cursor; if (yych <= '/') { - goto basic_json_parser_33; - } - if (yych <= '9') - { - goto basic_json_parser_54; - } - goto basic_json_parser_33; - } - else - { - if (yych <= 'F') - { - goto basic_json_parser_54; + goto basic_json_parser_32; } - if (yych <= '`') + if (yych >= ':') { - goto basic_json_parser_33; + goto basic_json_parser_32; } - if (yych <= 'f') + basic_json_parser_52: + ++m_cursor; + if (m_limit <= m_cursor) { - goto basic_json_parser_54; + fill_line_buffer(1); // LCOV_EXCL_LINE } - goto basic_json_parser_33; - } -basic_json_parser_44: - yyaccept = 1; - m_marker = ++m_cursor; - if ((m_limit - m_cursor) < 3) - { - fill_line_buffer(); - } - yych = *m_cursor; - if (yych <= 'D') - { + yych = *m_cursor; if (yych <= '/') { goto basic_json_parser_14; } if (yych <= '9') { - goto basic_json_parser_44; + goto basic_json_parser_52; } goto basic_json_parser_14; - } - else - { - if (yych <= 'E') + basic_json_parser_54: + yych = *++m_cursor; + if (yych == 's') { - goto basic_json_parser_38; - } - if (yych == 'e') - { - goto basic_json_parser_38; + goto basic_json_parser_58; } - goto basic_json_parser_14; - } -basic_json_parser_46: - yych = *++m_cursor; - if (yych <= '/') - { - goto basic_json_parser_33; - } - if (yych >= ':') - { - goto basic_json_parser_33; - } -basic_json_parser_47: - ++m_cursor; - if (m_limit <= m_cursor) - { - fill_line_buffer(); - } - yych = *m_cursor; - if (yych <= '/') - { - goto basic_json_parser_14; - } - if (yych <= '9') - { - goto basic_json_parser_47; - } - goto basic_json_parser_14; -basic_json_parser_49: - yych = *++m_cursor; - if (yych == 's') - { - goto basic_json_parser_55; - } - goto basic_json_parser_33; -basic_json_parser_50: - yych = *++m_cursor; - if (yych == 'l') - { - goto basic_json_parser_56; - } - goto basic_json_parser_33; -basic_json_parser_51: - yych = *++m_cursor; - if (yych == 'e') - { - goto basic_json_parser_58; - } - goto basic_json_parser_33; -basic_json_parser_52: - ++m_cursor; - { - continue; - } -basic_json_parser_54: - ++m_cursor; - if (m_limit <= m_cursor) - { - fill_line_buffer(); - } - yych = *m_cursor; - if (yych <= '@') - { - if (yych <= '/') + goto basic_json_parser_32; + basic_json_parser_55: + yych = *++m_cursor; + if (yych == 'l') { - goto basic_json_parser_33; + goto basic_json_parser_59; } - if (yych <= '9') + goto basic_json_parser_32; + basic_json_parser_56: + yych = *++m_cursor; + if (yych == 'e') { - goto basic_json_parser_60; + goto basic_json_parser_61; } - goto basic_json_parser_33; - } - else - { - if (yych <= 'F') + goto basic_json_parser_32; + basic_json_parser_57: + ++m_cursor; + if (m_limit <= m_cursor) { - goto basic_json_parser_60; + fill_line_buffer(1); // LCOV_EXCL_LINE } - if (yych <= '`') + yych = *m_cursor; + if (yych <= '@') { - goto basic_json_parser_33; + if (yych <= '/') + { + goto basic_json_parser_32; + } + if (yych <= '9') + { + goto basic_json_parser_63; + } + goto basic_json_parser_32; } - if (yych <= 'f') + else { - goto basic_json_parser_60; + if (yych <= 'F') + { + goto basic_json_parser_63; + } + if (yych <= '`') + { + goto basic_json_parser_32; + } + if (yych <= 'f') + { + goto basic_json_parser_63; + } + goto basic_json_parser_32; } - goto basic_json_parser_33; - } -basic_json_parser_55: - yych = *++m_cursor; - if (yych == 'e') - { - goto basic_json_parser_61; - } - goto basic_json_parser_33; -basic_json_parser_56: - ++m_cursor; - { - last_token_type = token_type::literal_null; - break; - } -basic_json_parser_58: - ++m_cursor; - { - last_token_type = token_type::literal_true; - break; - } -basic_json_parser_60: - ++m_cursor; - if (m_limit <= m_cursor) - { - fill_line_buffer(); - } - yych = *m_cursor; - if (yych <= '@') - { - if (yych <= '/') + basic_json_parser_58: + yych = *++m_cursor; + if (yych == 'e') { - goto basic_json_parser_33; + goto basic_json_parser_64; } - if (yych <= '9') + goto basic_json_parser_32; + basic_json_parser_59: + ++m_cursor; { - goto basic_json_parser_63; + last_token_type = token_type::literal_null; + break; } - goto basic_json_parser_33; - } - else - { - if (yych <= 'F') + basic_json_parser_61: + ++m_cursor; { - goto basic_json_parser_63; + last_token_type = token_type::literal_true; + break; } - if (yych <= '`') + basic_json_parser_63: + ++m_cursor; + if (m_limit <= m_cursor) { - goto basic_json_parser_33; + fill_line_buffer(1); // LCOV_EXCL_LINE } - if (yych <= 'f') + yych = *m_cursor; + if (yych <= '@') { - goto basic_json_parser_63; + if (yych <= '/') + { + goto basic_json_parser_32; + } + if (yych <= '9') + { + goto basic_json_parser_66; + } + goto basic_json_parser_32; } - goto basic_json_parser_33; - } -basic_json_parser_61: - ++m_cursor; - { - last_token_type = token_type::literal_false; - break; - } -basic_json_parser_63: - ++m_cursor; - if (m_limit <= m_cursor) - { - fill_line_buffer(); - } - yych = *m_cursor; - if (yych <= '@') - { - if (yych <= '/') + else { - goto basic_json_parser_33; + if (yych <= 'F') + { + goto basic_json_parser_66; + } + if (yych <= '`') + { + goto basic_json_parser_32; + } + if (yych <= 'f') + { + goto basic_json_parser_66; + } + goto basic_json_parser_32; } - if (yych <= '9') + basic_json_parser_64: + ++m_cursor; { - goto basic_json_parser_31; + last_token_type = token_type::literal_false; + break; } - goto basic_json_parser_33; - } - else - { - if (yych <= 'F') + basic_json_parser_66: + ++m_cursor; + if (m_limit <= m_cursor) { - goto basic_json_parser_31; + fill_line_buffer(1); // LCOV_EXCL_LINE } - if (yych <= '`') + yych = *m_cursor; + if (yych <= '@') { - goto basic_json_parser_33; + if (yych <= '/') + { + goto basic_json_parser_32; + } + if (yych <= '9') + { + goto basic_json_parser_30; + } + goto basic_json_parser_32; } - if (yych <= 'f') + else { - goto basic_json_parser_31; + if (yych <= 'F') + { + goto basic_json_parser_30; + } + if (yych <= '`') + { + goto basic_json_parser_32; + } + if (yych <= 'f') + { + goto basic_json_parser_30; + } + goto basic_json_parser_32; } - goto basic_json_parser_33; } + } + return last_token_type; } - return last_token_type; - } - - /*! + /*! @brief append data from the stream to the line buffer This function is called by the scan() function when the end of the @@ -8582,59 +8738,63 @@ basic_json_parser_63: m_start m_content */ - void fill_line_buffer() - { - // number of processed characters (p) - const auto offset_start = m_start - m_content; - // offset for m_marker wrt. to m_start - const auto offset_marker = (m_marker == nullptr) ? 0 : m_marker - m_start; - // number of unprocessed characters (u) - const auto offset_cursor = m_cursor - m_start; - - // no stream is used or end of file is reached - if (m_stream == nullptr or m_stream->eof()) + void fill_line_buffer(size_t n = 0) { - // copy unprocessed characters to line buffer - m_line_buffer.clear(); - for (m_cursor = m_start; m_cursor != m_limit; ++m_cursor) + // number of processed characters (p) + const auto offset_start = m_start - m_content; + // offset for m_marker wrt. to m_start + const auto offset_marker = (m_marker == nullptr) ? 0 : m_marker - m_start; + // number of unprocessed characters (u) + const auto offset_cursor = m_cursor - m_start; + + // no stream is used or end of file is reached + if (m_stream == nullptr or m_stream->eof()) + { + // skip this part if we are already using the line buffer + if (m_start != reinterpret_cast(m_line_buffer.data())) + { + // copy unprocessed characters to line buffer + m_line_buffer.clear(); + for (m_cursor = m_start; m_cursor != m_limit; ++m_cursor) + { + m_line_buffer.append(1, static_cast(*m_cursor)); + } + } + + // append n characters to make sure that there is sufficient + // space between m_cursor and m_limit + m_line_buffer.append(1, '\x00'); + m_line_buffer.append(n - 1, '\x01'); + } + else { - m_line_buffer.append(1, static_cast(*m_cursor)); + // delete processed characters from line buffer + m_line_buffer.erase(0, static_cast(offset_start)); + // read next line from input stream + std::string line; + std::getline(*m_stream, line, '\n'); + // add line with newline symbol to the line buffer + m_line_buffer += line + "\n"; } - // append 5 characters (size of longest keyword "false") to - // make sure that there is sufficient space between m_cursor - // and m_limit - m_line_buffer.append(5, '\0'); + // set pointers + m_content = reinterpret_cast(m_line_buffer.c_str()); + assert(m_content != nullptr); + m_start = m_content; + m_marker = m_start + offset_marker; + m_cursor = m_start + offset_cursor; + m_limit = m_start + m_line_buffer.size(); } - else + + /// return string representation of last read token + string_t get_token_string() const { - // delete processed characters from line buffer - m_line_buffer.erase(0, static_cast(offset_start)); - // read next line from input stream - std::string line; - std::getline(*m_stream, line); - // add line with newline symbol to the line buffer - m_line_buffer += line + "\n"; + assert(m_start != nullptr); + return string_t(reinterpret_cast(m_start), + static_cast(m_cursor - m_start)); } - // set pointers - m_content = reinterpret_cast(m_line_buffer.c_str()); - assert(m_content != nullptr); - m_start = m_content; - m_marker = m_start + offset_marker; - m_cursor = m_start + offset_cursor; - m_limit = m_start + m_line_buffer.size(); - } - - /// return string representation of last read token - string_t get_token_string() const - { - assert(m_start != nullptr); - return string_t(reinterpret_cast(m_start), - static_cast(m_cursor - m_start)); - } - - /*! + /*! @brief return string value for string tokens The function iterates the characters between the opening and closing @@ -8680,123 +8840,128 @@ basic_json_parser_63: m_start + 1 + x < m_cursor - 1 must hold to loop indefinitely. This can be rephrased to m_cursor - m_start - 2 > x. With the precondition, we x <= 0, meaning that the loop condition holds - indefinitly if i is always decreased. However, observe that the value - of i is strictly increasing with each iteration, as it is incremented - by 1 in the iteration expression and never decremented inside the loop - body. Hence, the loop condition will eventually be false which - contradicts the assumption that the loop condition is a tautology, - q.e.d. - - @return string value of current token without opening and closing - quotes - @throw std::out_of_range if to_unicode fails - */ - string_t get_string() const - { - assert(m_cursor - m_start >= 2); - - string_t result; - result.reserve(static_cast(m_cursor - m_start - 2)); - - // iterate the result between the quotes - for (const lexer_char_t* i = m_start + 1; i < m_cursor - 1; ++i) - { - // process escaped characters - if (*i == '\\') - { - // read next character - ++i; - - switch (*i) - { - // the default escapes - case 't': - { - result += "\t"; - break; - } - case 'b': - { - result += "\b"; - break; - } - case 'f': - { - result += "\f"; - break; - } - case 'n': - { - result += "\n"; - break; - } - case 'r': - { - result += "\r"; - break; - } - case '\\': - { - result += "\\"; - break; - } - case '/': - { - result += "/"; - break; - } - case '"': - { - result += "\""; - break; - } + indefinitly if i is always decreased. However, observe that the value + of i is strictly increasing with each iteration, as it is incremented + by 1 in the iteration expression and never decremented inside the loop + body. Hence, the loop condition will eventually be false which + contradicts the assumption that the loop condition is a tautology, + q.e.d. + + @return string value of current token without opening and closing + quotes + @throw std::out_of_range if to_unicode fails + */ + string_t get_string() const + { + assert(m_cursor - m_start >= 2); + + string_t result; + result.reserve(static_cast(m_cursor - m_start - 2)); + + // iterate the result between the quotes + for (const lexer_char_t* i = m_start + 1; i < m_cursor - 1; ++i) + { + // process escaped characters + if (*i == '\\') + { + // read next character + ++i; - // unicode - case 'u': + switch (*i) { - // get code xxxx from uxxxx - auto codepoint = std::strtoul(std::string(reinterpret_cast(i + 1), - 4).c_str(), nullptr, 16); + // the default escapes + case 't': + { + result += "\t"; + break; + } + case 'b': + { + result += "\b"; + break; + } + case 'f': + { + result += "\f"; + break; + } + case 'n': + { + result += "\n"; + break; + } + case 'r': + { + result += "\r"; + break; + } + case '\\': + { + result += "\\"; + break; + } + case '/': + { + result += "/"; + break; + } + case '"': + { + result += "\""; + break; + } - // check if codepoint is a high surrogate - if (codepoint >= 0xD800 and codepoint <= 0xDBFF) + // unicode + case 'u': { - // make sure there is a subsequent unicode - if ((i + 6 >= m_limit) or * (i + 5) != '\\' or * (i + 6) != 'u') + // get code xxxx from uxxxx + auto codepoint = std::strtoul(std::string(reinterpret_cast(i + 1), + 4).c_str(), nullptr, 16); + + // check if codepoint is a high surrogate + if (codepoint >= 0xD800 and codepoint <= 0xDBFF) { - throw std::invalid_argument("missing low surrogate"); + // make sure there is a subsequent unicode + if ((i + 6 >= m_limit) or * (i + 5) != '\\' or * (i + 6) != 'u') + { + throw std::invalid_argument("missing low surrogate"); + } + + // get code yyyy from uxxxx\uyyyy + auto codepoint2 = std::strtoul(std::string(reinterpret_cast + (i + 7), 4).c_str(), nullptr, 16); + result += to_unicode(codepoint, codepoint2); + // skip the next 10 characters (xxxx\uyyyy) + i += 10; } - - // get code yyyy from uxxxx\uyyyy - auto codepoint2 = std::strtoul(std::string(reinterpret_cast - (i + 7), 4).c_str(), nullptr, 16); - result += to_unicode(codepoint, codepoint2); - // skip the next 10 characters (xxxx\uyyyy) - i += 10; - } - else - { - // add unicode character(s) - result += to_unicode(codepoint); - // skip the next four characters (xxxx) - i += 4; + else if (codepoint >= 0xDC00 and codepoint <= 0xDFFF) + { + // we found a lone low surrogate + throw std::invalid_argument("missing high surrogate"); + } + else + { + // add unicode character(s) + result += to_unicode(codepoint); + // skip the next four characters (xxxx) + i += 4; + } + break; } - break; } } + else + { + // all other characters are just copied to the end of the + // string + result.append(1, static_cast(*i)); + } } - else - { - // all other characters are just copied to the end of the - // string - result.append(1, static_cast(*i)); - } - } - return result; - } + return result; + } - /*! + /*! @brief parse floating point number This function (and its overloads) serves to select the most approprate @@ -8811,12 +8976,12 @@ basic_json_parser_63: @return the floating point number */ - long double str_to_float_t(long double* /* type */, char** endptr) const - { - return std::strtold(reinterpret_cast(m_start), endptr); - } + long double str_to_float_t(long double* /* type */, char** endptr) const + { + return std::strtold(reinterpret_cast(m_start), endptr); + } - /*! + /*! @brief parse floating point number This function (and its overloads) serves to select the most approprate @@ -8831,12 +8996,12 @@ basic_json_parser_63: @return the floating point number */ - double str_to_float_t(double* /* type */, char** endptr) const - { - return std::strtod(reinterpret_cast(m_start), endptr); - } + double str_to_float_t(double* /* type */, char** endptr) const + { + return std::strtod(reinterpret_cast(m_start), endptr); + } - /*! + /*! @brief parse floating point number This function (and its overloads) serves to select the most approprate @@ -8851,12 +9016,12 @@ basic_json_parser_63: @return the floating point number */ - float str_to_float_t(float* /* type */, char** endptr) const - { - return std::strtof(reinterpret_cast(m_start), endptr); - } + float str_to_float_t(float* /* type */, char** endptr) const + { + return std::strtof(reinterpret_cast(m_start), endptr); + } - /*! + /*! @brief return number value for number tokens This function translates the last token into the most appropriate @@ -8877,396 +9042,403 @@ basic_json_parser_63: NAN if the conversion read past the current token. The latter case needs to be treated by the caller function. */ - void get_number(basic_json& result) const - { - assert(m_start != nullptr); + void get_number(basic_json& result) const + { + assert(m_start != nullptr); - const lexer::lexer_char_t* curptr = m_start; + const lexer::lexer_char_t* curptr = m_start; - // accumulate the integer conversion result (unsigned for now) - number_unsigned_t value = 0; + // accumulate the integer conversion result (unsigned for now) + number_unsigned_t value = 0; - // maximum absolute value of the relevant integer type - number_unsigned_t max; + // maximum absolute value of the relevant integer type + number_unsigned_t max; - // temporarily store the type to avoid unecessary bitfield access - value_t type; + // temporarily store the type to avoid unecessary bitfield access + value_t type; - // look for sign - if (*curptr == '-') - { - type = value_t::number_integer; - max = static_cast((std::numeric_limits::max)()) + 1; - curptr++; - } - else - { - type = value_t::number_unsigned; - max = static_cast((std::numeric_limits::max)()); - } + // look for sign + if (*curptr == '-') + { + type = value_t::number_integer; + max = static_cast((std::numeric_limits::max)()) + 1; + curptr++; + } + else + { + type = value_t::number_unsigned; + max = static_cast((std::numeric_limits::max)()); + } - // count the significant figures - for (; curptr < m_cursor; curptr++) - { - // quickly skip tests if a digit - if (*curptr < '0' || *curptr > '9') + // count the significant figures + for (; curptr < m_cursor; curptr++) { - if (*curptr == '.') + // quickly skip tests if a digit + if (*curptr < '0' || *curptr > '9') { - // don't count '.' but change to float + if (*curptr == '.') + { + // don't count '.' but change to float + type = value_t::number_float; + continue; + } + // assume exponent (if not then will fail parse): change to + // float, stop counting and record exponent details type = value_t::number_float; - continue; + break; + } + + // skip if definitely not an integer + if (type != value_t::number_float) + { + // multiply last value by ten and add the new digit + auto temp = value * 10 + *curptr - '0'; + + // test for overflow + if (temp < value || temp > max) + { + // overflow + type = value_t::number_float; + } + else + { + // no overflow - save it + value = temp; + } } - // assume exponent (if not then will fail parse): change to - // float, stop counting and record exponent details - type = value_t::number_float; - break; } - // skip if definitely not an integer - if (type != value_t::number_float) + // save the value (if not a float) + if (type == value_t::number_unsigned) + { + result.m_value.number_unsigned = value; + } + else if (type == value_t::number_integer) + { + result.m_value.number_integer = -static_cast(value); + } + else { - // multiply last value by ten and add the new digit - auto temp = value * 10 + *curptr - '0'; + // parse with strtod + result.m_value.number_float = str_to_float_t(static_cast(nullptr), NULL); - // test for overflow - if (temp < value || temp > max) - { - // overflow - type = value_t::number_float; - } - else + // replace infinity and NAN by null + if (not std::isfinite(result.m_value.number_float)) { - // no overflow - save it - value = temp; + type = value_t::null; + result.m_value = basic_json::json_value(); } } - } - // save the value (if not a float) - if (type == value_t::number_unsigned) - { - result.m_value.number_unsigned = value; + // save the type + result.m_type = type; } - else if (type == value_t::number_integer) - { - result.m_value.number_integer = -static_cast(value); - } - else - { - // parse with strtod - result.m_value.number_float = str_to_float_t(static_cast(nullptr), NULL); - } - - // save the type - result.m_type = type; - } - - private: - /// optional input stream - std::istream* m_stream = nullptr; - /// line buffer buffer for m_stream - string_t m_line_buffer {}; - /// the buffer pointer - const lexer_char_t* m_content = nullptr; - /// pointer to the beginning of the current symbol - const lexer_char_t* m_start = nullptr; - /// pointer for backtracking information - const lexer_char_t* m_marker = nullptr; - /// pointer to the current symbol - const lexer_char_t* m_cursor = nullptr; - /// pointer to the end of the buffer - const lexer_char_t* m_limit = nullptr; - /// the last token type - token_type last_token_type = token_type::end_of_input; - }; - /*! + private: + /// optional input stream + std::istream* m_stream = nullptr; + /// line buffer buffer for m_stream + string_t m_line_buffer {}; + /// the buffer pointer + const lexer_char_t* m_content = nullptr; + /// pointer to the beginning of the current symbol + const lexer_char_t* m_start = nullptr; + /// pointer for backtracking information + const lexer_char_t* m_marker = nullptr; + /// pointer to the current symbol + const lexer_char_t* m_cursor = nullptr; + /// pointer to the end of the buffer + const lexer_char_t* m_limit = nullptr; + /// the last token type + token_type last_token_type = token_type::end_of_input; + }; + + /*! @brief syntax analysis This class implements a recursive decent parser. */ - class parser - { - public: - /// a parser reading from a string literal - parser(const char* buff, const parser_callback_t cb = nullptr) - : callback(cb), - m_lexer(reinterpret_cast(buff), strlen(buff)) - {} - - /// a parser reading from an input stream - parser(std::istream& is, const parser_callback_t cb = nullptr) - : callback(cb), m_lexer(is) - {} - - /// a parser reading from an iterator range with contiguous storage - template::iterator_category, std::random_access_iterator_tag>::value - , int>::type - = 0> - parser(IteratorType first, IteratorType last, const parser_callback_t cb = nullptr) - : callback(cb), - m_lexer(reinterpret_cast(&(*first)), - static_cast(std::distance(first, last))) - {} - - /// public parser interface - basic_json parse() + class parser { - // read first token - get_token(); + public: + /// a parser reading from a string literal + parser(const char* buff, const parser_callback_t cb = nullptr) + : callback(cb), + m_lexer(reinterpret_cast(buff), std::strlen(buff)) + {} - basic_json result = parse_internal(true); - result.assert_invariant(); + /// a parser reading from an input stream + parser(std::istream& is, const parser_callback_t cb = nullptr) + : callback(cb), m_lexer(is) + {} - expect(lexer::token_type::end_of_input); + /// a parser reading from an iterator range with contiguous storage + template::iterator_category, std::random_access_iterator_tag>::value + , int>::type + = 0> + parser(IteratorType first, IteratorType last, const parser_callback_t cb = nullptr) + : callback(cb), + m_lexer(reinterpret_cast(&(*first)), + static_cast(std::distance(first, last))) + {} - // return parser result and replace it with null in case the - // top-level value was discarded by the callback function - return result.is_discarded() ? basic_json() : std::move(result); - } + /// public parser interface + basic_json parse() + { + // read first token + get_token(); - private: - /// the actual parser - basic_json parse_internal(bool keep) - { - auto result = basic_json(value_t::discarded); + basic_json result = parse_internal(true); + result.assert_invariant(); + + expect(lexer::token_type::end_of_input); + + // return parser result and replace it with null in case the + // top-level value was discarded by the callback function + return result.is_discarded() ? basic_json() : std::move(result); + } - switch (last_token) + private: + /// the actual parser + basic_json parse_internal(bool keep) { - case lexer::token_type::begin_object: + auto result = basic_json(value_t::discarded); + + switch (last_token) { - if (keep and (not callback - or ((keep = callback(depth++, parse_event_t::object_start, result)) != 0))) + case lexer::token_type::begin_object: { - // explicitly set result to object to cope with {} - result.m_type = value_t::object; - result.m_value = value_t::object; - } + if (keep and (not callback + or ((keep = callback(depth++, parse_event_t::object_start, result)) != 0))) + { + // explicitly set result to object to cope with {} + result.m_type = value_t::object; + result.m_value = value_t::object; + } - // read next token - get_token(); + // read next token + get_token(); - // closing } -> we are done - if (last_token == lexer::token_type::end_object) - { + // closing } -> we are done + if (last_token == lexer::token_type::end_object) + { + get_token(); + if (keep and callback and not callback(--depth, parse_event_t::object_end, result)) + { + result = basic_json(value_t::discarded); + } + return result; + } + + // no comma is expected here + unexpect(lexer::token_type::value_separator); + + // otherwise: parse key-value pairs + do + { + // ugly, but could be fixed with loop reorganization + if (last_token == lexer::token_type::value_separator) + { + get_token(); + } + + // store key + expect(lexer::token_type::value_string); + const auto key = m_lexer.get_string(); + + bool keep_tag = false; + if (keep) + { + if (callback) + { + basic_json k(key); + keep_tag = callback(depth, parse_event_t::key, k); + } + else + { + keep_tag = true; + } + } + + // parse separator (:) + get_token(); + expect(lexer::token_type::name_separator); + + // parse and add value + get_token(); + auto value = parse_internal(keep); + if (keep and keep_tag and not value.is_discarded()) + { + result[key] = std::move(value); + } + } + while (last_token == lexer::token_type::value_separator); + + // closing } + expect(lexer::token_type::end_object); get_token(); if (keep and callback and not callback(--depth, parse_event_t::object_end, result)) { result = basic_json(value_t::discarded); } + return result; } - // no comma is expected here - unexpect(lexer::token_type::value_separator); - - // otherwise: parse key-value pairs - do + case lexer::token_type::begin_array: { - // ugly, but could be fixed with loop reorganization - if (last_token == lexer::token_type::value_separator) + if (keep and (not callback + or ((keep = callback(depth++, parse_event_t::array_start, result)) != 0))) + { + // explicitly set result to object to cope with [] + result.m_type = value_t::array; + result.m_value = value_t::array; + } + + // read next token + get_token(); + + // closing ] -> we are done + if (last_token == lexer::token_type::end_array) { get_token(); + if (callback and not callback(--depth, parse_event_t::array_end, result)) + { + result = basic_json(value_t::discarded); + } + return result; } - // store key - expect(lexer::token_type::value_string); - const auto key = m_lexer.get_string(); + // no comma is expected here + unexpect(lexer::token_type::value_separator); - bool keep_tag = false; - if (keep) + // otherwise: parse values + do { - if (callback) + // ugly, but could be fixed with loop reorganization + if (last_token == lexer::token_type::value_separator) { - basic_json k(key); - keep_tag = callback(depth, parse_event_t::key, k); + get_token(); } - else + + // parse value + auto value = parse_internal(keep); + if (keep and not value.is_discarded()) { - keep_tag = true; + result.push_back(std::move(value)); } } + while (last_token == lexer::token_type::value_separator); - // parse separator (:) - get_token(); - expect(lexer::token_type::name_separator); - - // parse and add value + // closing ] + expect(lexer::token_type::end_array); get_token(); - auto value = parse_internal(keep); - if (keep and keep_tag and not value.is_discarded()) + if (keep and callback and not callback(--depth, parse_event_t::array_end, result)) { - result[key] = std::move(value); + result = basic_json(value_t::discarded); } + + return result; } - while (last_token == lexer::token_type::value_separator); - // closing } - expect(lexer::token_type::end_object); - get_token(); - if (keep and callback and not callback(--depth, parse_event_t::object_end, result)) + case lexer::token_type::literal_null: { - result = basic_json(value_t::discarded); + get_token(); + result.m_type = value_t::null; + break; } - return result; - } - - case lexer::token_type::begin_array: - { - if (keep and (not callback - or ((keep = callback(depth++, parse_event_t::array_start, result)) != 0))) + case lexer::token_type::value_string: { - // explicitly set result to object to cope with [] - result.m_type = value_t::array; - result.m_value = value_t::array; + const auto s = m_lexer.get_string(); + get_token(); + result = basic_json(s); + break; } - // read next token - get_token(); - - // closing ] -> we are done - if (last_token == lexer::token_type::end_array) + case lexer::token_type::literal_true: { get_token(); - if (callback and not callback(--depth, parse_event_t::array_end, result)) - { - result = basic_json(value_t::discarded); - } - return result; + result.m_type = value_t::boolean; + result.m_value = true; + break; } - // no comma is expected here - unexpect(lexer::token_type::value_separator); - - // otherwise: parse values - do + case lexer::token_type::literal_false: { - // ugly, but could be fixed with loop reorganization - if (last_token == lexer::token_type::value_separator) - { - get_token(); - } - - // parse value - auto value = parse_internal(keep); - if (keep and not value.is_discarded()) - { - result.push_back(std::move(value)); - } + get_token(); + result.m_type = value_t::boolean; + result.m_value = false; + break; } - while (last_token == lexer::token_type::value_separator); - // closing ] - expect(lexer::token_type::end_array); - get_token(); - if (keep and callback and not callback(--depth, parse_event_t::array_end, result)) + case lexer::token_type::value_number: { - result = basic_json(value_t::discarded); + m_lexer.get_number(result); + get_token(); + break; } - return result; - } - - case lexer::token_type::literal_null: - { - get_token(); - result.m_type = value_t::null; - break; - } - - case lexer::token_type::value_string: - { - const auto s = m_lexer.get_string(); - get_token(); - result = basic_json(s); - break; - } - - case lexer::token_type::literal_true: - { - get_token(); - result.m_type = value_t::boolean; - result.m_value = true; - break; - } - - case lexer::token_type::literal_false: - { - get_token(); - result.m_type = value_t::boolean; - result.m_value = false; - break; - } - - case lexer::token_type::value_number: - { - m_lexer.get_number(result); - get_token(); - break; + default: + { + // the last token was unexpected + unexpect(last_token); + } } - default: + if (keep and callback and not callback(depth, parse_event_t::value, result)) { - // the last token was unexpected - unexpect(last_token); + result = basic_json(value_t::discarded); } + return result; } - if (keep and callback and not callback(depth, parse_event_t::value, result)) + /// get next token from lexer + typename lexer::token_type get_token() { - result = basic_json(value_t::discarded); + last_token = m_lexer.scan(); + return last_token; } - return result; - } - - /// get next token from lexer - typename lexer::token_type get_token() - { - last_token = m_lexer.scan(); - return last_token; - } - void expect(typename lexer::token_type t) const - { - if (t != last_token) + void expect(typename lexer::token_type t) const { - std::string error_msg = "parse error - unexpected "; - error_msg += (last_token == lexer::token_type::parse_error ? ("'" + m_lexer.get_token_string() + - "'") : - lexer::token_type_name(last_token)); - error_msg += "; expected " + lexer::token_type_name(t); - throw std::invalid_argument(error_msg); + if (t != last_token) + { + std::string error_msg = "parse error - unexpected "; + error_msg += (last_token == lexer::token_type::parse_error ? ("'" + m_lexer.get_token_string() + + "'") : + lexer::token_type_name(last_token)); + error_msg += "; expected " + lexer::token_type_name(t); + throw std::invalid_argument(error_msg); + } } - } - void unexpect(typename lexer::token_type t) const - { - if (t == last_token) + void unexpect(typename lexer::token_type t) const { - std::string error_msg = "parse error - unexpected "; - error_msg += (last_token == lexer::token_type::parse_error ? ("'" + m_lexer.get_token_string() + - "'") : - lexer::token_type_name(last_token)); - throw std::invalid_argument(error_msg); + if (t == last_token) + { + std::string error_msg = "parse error - unexpected "; + error_msg += (last_token == lexer::token_type::parse_error ? ("'" + m_lexer.get_token_string() + + "'") : + lexer::token_type_name(last_token)); + throw std::invalid_argument(error_msg); + } } - } - private: - /// current level of recursion - int depth = 0; - /// callback function - const parser_callback_t callback = nullptr; - /// the type of the last read token - typename lexer::token_type last_token = lexer::token_type::uninitialized; - /// the lexer - lexer m_lexer; - }; + private: + /// current level of recursion + int depth = 0; + /// callback function + const parser_callback_t callback = nullptr; + /// the type of the last read token + typename lexer::token_type last_token = lexer::token_type::uninitialized; + /// the lexer + lexer m_lexer; + }; - public: - /*! + public: + /*! @brief JSON Pointer A JSON pointer defines a string syntax for identifying a specific value @@ -9277,13 +9449,13 @@ basic_json_parser_63: @since version 2.0.0 */ - class json_pointer - { - /// allow basic_json to access private members - friend class basic_json; + class json_pointer + { + /// allow basic_json to access private members + friend class basic_json; - public: - /*! + public: + /*! @brief create JSON pointer Create a JSON pointer according to the syntax described in @@ -9305,11 +9477,11 @@ basic_json_parser_63: @since version 2.0.0 */ - explicit json_pointer(const std::string& s = "") - : reference_tokens(split(s)) - {} + explicit json_pointer(const std::string& s = "") + : reference_tokens(split(s)) + {} - /*! + /*! @brief return a string representation of the JSON pointer @invariant For each JSON pointer `ptr`, it holds: @@ -9322,120 +9494,126 @@ basic_json_parser_63: @liveexample{The example shows the result of `to_string`., json_pointer__to_string} - @since version 2.0.0 - */ - std::string to_string() const noexcept - { - return std::accumulate(reference_tokens.begin(), - reference_tokens.end(), std::string{}, - [](const std::string & a, const std::string & b) - { - return a + "/" + escape(b); - }); - } - - /// @copydoc to_string() - operator std::string() const - { - return to_string(); - } + @since version 2.0.0 + */ + std::string to_string() const noexcept + { + return std::accumulate(reference_tokens.begin(), + reference_tokens.end(), std::string{}, + [](const std::string & a, const std::string & b) + { + return a + "/" + escape(b); + }); + } - private: - /// remove and return last reference pointer - std::string pop_back() - { - if (is_root()) + /// @copydoc to_string() + operator std::string() const { - throw std::domain_error("JSON pointer has no parent"); + return to_string(); } - auto last = reference_tokens.back(); - reference_tokens.pop_back(); - return last; - } + private: + /// remove and return last reference pointer + std::string pop_back() + { + if (is_root()) + { + throw std::domain_error("JSON pointer has no parent"); + } - /// return whether pointer points to the root document - bool is_root() const - { - return reference_tokens.empty(); - } + auto last = reference_tokens.back(); + reference_tokens.pop_back(); + return last; + } - json_pointer top() const - { - if (is_root()) + /// return whether pointer points to the root document + bool is_root() const { - throw std::domain_error("JSON pointer has no parent"); + return reference_tokens.empty(); } - json_pointer result = *this; - result.reference_tokens = {reference_tokens[0]}; - return result; - } + json_pointer top() const + { + if (is_root()) + { + throw std::domain_error("JSON pointer has no parent"); + } - /*! + json_pointer result = *this; + result.reference_tokens = {reference_tokens[0]}; + return result; + } + + /*! @brief create and return a reference to the pointed to value @complexity Linear in the number of reference tokens. */ - reference get_and_create(reference j) const - { - pointer result = &j; - - // in case no reference tokens exist, return a reference to the - // JSON value j which will be overwritten by a primitive value - for (const auto& reference_token : reference_tokens) + reference get_and_create(reference j) const { - switch (result->m_type) + pointer result = &j; + + // in case no reference tokens exist, return a reference to the + // JSON value j which will be overwritten by a primitive value + for (const auto& reference_token : reference_tokens) { - case value_t::null: + switch (result->m_type) { - if (reference_token == "0") + case value_t::null: { - // start a new array if reference token is 0 - result = &result->operator[](0); + if (reference_token == "0") + { + // start a new array if reference token is 0 + result = &result->operator[](0); + } + else + { + // start a new object otherwise + result = &result->operator[](reference_token); + } + break; } - else + + case value_t::object: { - // start a new object otherwise + // create an entry in the object result = &result->operator[](reference_token); + break; } - break; - } - - case value_t::object: - { - // create an entry in the object - result = &result->operator[](reference_token); - break; - } - case value_t::array: - { - // create an entry in the array - result = &result->operator[](static_cast(std::stoi(reference_token))); - break; - } + case value_t::array: + { + // create an entry in the array + result = &result->operator[](static_cast(std::stoi(reference_token))); + break; + } - /* + /* The following code is only reached if there exists a reference token _and_ the current value is primitive. In this case, we have an error situation, because primitive values may only occur as single value; that is, with an empty list of reference tokens. */ - default: - { - throw std::domain_error("invalid value to unflatten"); + default: + { + throw std::domain_error("invalid value to unflatten"); + } } } - } - return *result; - } + return *result; + } - /*! + /*! @brief return a reference to the pointed to value + @note This version does not throw if a value is not present, but tries + to create nested values instead. For instance, calling this function + with pointer `"/this/that"` on a null value is equivalent to calling + `operator[]("this").operator[]("that")` on that value, effectively + changing the null value to an object. + @param[in] ptr a JSON value @return reference to the JSON value pointed to by the JSON pointer @@ -9446,95 +9624,118 @@ basic_json_parser_63: @throw std::domain_error if an array index begins with '0' @throw std::invalid_argument if an array index was not a number */ - reference get_unchecked(pointer ptr) const - { - for (const auto& reference_token : reference_tokens) + reference get_unchecked(pointer ptr) const { - switch (ptr->m_type) + for (const auto& reference_token : reference_tokens) { - case value_t::object: + // convert null values to arrays or objects before continuing + if (ptr->m_type == value_t::null) { - // use unchecked object access - ptr = &ptr->operator[](reference_token); - break; + // check if reference token is a number + const bool nums = std::all_of(reference_token.begin(), + reference_token.end(), + [](const char x) + { + return std::isdigit(x); + }); + + // change value to array for numbers or "-" or to object + // otherwise + if (nums or reference_token == "-") + { + *ptr = value_t::array; + } + else + { + *ptr = value_t::object; + } } - case value_t::array: + switch (ptr->m_type) { - // error condition (cf. RFC 6901, Sect. 4) - if (reference_token.size() > 1 and reference_token[0] == '0') + case value_t::object: { - throw std::domain_error("array index must not begin with '0'"); + // use unchecked object access + ptr = &ptr->operator[](reference_token); + break; } - if (reference_token == "-") + case value_t::array: { - // explicityly treat "-" as index beyond the end - ptr = &ptr->operator[](ptr->m_value.array->size()); + // error condition (cf. RFC 6901, Sect. 4) + if (reference_token.size() > 1 and reference_token[0] == '0') + { + throw std::domain_error("array index must not begin with '0'"); + } + + if (reference_token == "-") + { + // explicityly treat "-" as index beyond the end + ptr = &ptr->operator[](ptr->m_value.array->size()); + } + else + { + // convert array index to number; unchecked access + ptr = &ptr->operator[](static_cast(std::stoi(reference_token))); + } + break; } - else + + default: { - // convert array index to number; unchecked access - ptr = &ptr->operator[](static_cast(std::stoi(reference_token))); + throw std::out_of_range("unresolved reference token '" + reference_token + "'"); } - break; - } - - default: - { - throw std::out_of_range("unresolved reference token '" + reference_token + "'"); } } - } - return *ptr; - } + return *ptr; + } - reference get_checked(pointer ptr) const - { - for (const auto& reference_token : reference_tokens) + reference get_checked(pointer ptr) const { - switch (ptr->m_type) + for (const auto& reference_token : reference_tokens) { - case value_t::object: - { - // note: at performs range check - ptr = &ptr->at(reference_token); - break; - } - - case value_t::array: + switch (ptr->m_type) { - if (reference_token == "-") + case value_t::object: { - // "-" always fails the range check - throw std::out_of_range("array index '-' (" + - std::to_string(ptr->m_value.array->size()) + - ") is out of range"); + // note: at performs range check + ptr = &ptr->at(reference_token); + break; } - // error condition (cf. RFC 6901, Sect. 4) - if (reference_token.size() > 1 and reference_token[0] == '0') + case value_t::array: { - throw std::domain_error("array index must not begin with '0'"); - } + if (reference_token == "-") + { + // "-" always fails the range check + throw std::out_of_range("array index '-' (" + + std::to_string(ptr->m_value.array->size()) + + ") is out of range"); + } - // note: at performs range check - ptr = &ptr->at(static_cast(std::stoi(reference_token))); - break; - } + // error condition (cf. RFC 6901, Sect. 4) + if (reference_token.size() > 1 and reference_token[0] == '0') + { + throw std::domain_error("array index must not begin with '0'"); + } - default: - { - throw std::out_of_range("unresolved reference token '" + reference_token + "'"); + // note: at performs range check + ptr = &ptr->at(static_cast(std::stoi(reference_token))); + break; + } + + default: + { + throw std::out_of_range("unresolved reference token '" + reference_token + "'"); + } } } - } - return *ptr; - } + return *ptr; + } - /*! + /*! @brief return a const reference to the pointed to value @param[in] ptr a JSON value @@ -9542,157 +9743,157 @@ basic_json_parser_63: @return const reference to the JSON value pointed to by the JSON pointer */ - const_reference get_unchecked(const_pointer ptr) const - { - for (const auto& reference_token : reference_tokens) + const_reference get_unchecked(const_pointer ptr) const { - switch (ptr->m_type) + for (const auto& reference_token : reference_tokens) { - case value_t::object: - { - // use unchecked object access - ptr = &ptr->operator[](reference_token); - break; - } - - case value_t::array: + switch (ptr->m_type) { - if (reference_token == "-") + case value_t::object: { - // "-" cannot be used for const access - throw std::out_of_range("array index '-' (" + - std::to_string(ptr->m_value.array->size()) + - ") is out of range"); + // use unchecked object access + ptr = &ptr->operator[](reference_token); + break; } - // error condition (cf. RFC 6901, Sect. 4) - if (reference_token.size() > 1 and reference_token[0] == '0') + case value_t::array: { - throw std::domain_error("array index must not begin with '0'"); - } + if (reference_token == "-") + { + // "-" cannot be used for const access + throw std::out_of_range("array index '-' (" + + std::to_string(ptr->m_value.array->size()) + + ") is out of range"); + } - // use unchecked array access - ptr = &ptr->operator[](static_cast(std::stoi(reference_token))); - break; - } + // error condition (cf. RFC 6901, Sect. 4) + if (reference_token.size() > 1 and reference_token[0] == '0') + { + throw std::domain_error("array index must not begin with '0'"); + } - default: - { - throw std::out_of_range("unresolved reference token '" + reference_token + "'"); + // use unchecked array access + ptr = &ptr->operator[](static_cast(std::stoi(reference_token))); + break; + } + + default: + { + throw std::out_of_range("unresolved reference token '" + reference_token + "'"); + } } } - } - return *ptr; - } + return *ptr; + } - const_reference get_checked(const_pointer ptr) const - { - for (const auto& reference_token : reference_tokens) + const_reference get_checked(const_pointer ptr) const { - switch (ptr->m_type) + for (const auto& reference_token : reference_tokens) { - case value_t::object: - { - // note: at performs range check - ptr = &ptr->at(reference_token); - break; - } - - case value_t::array: + switch (ptr->m_type) { - if (reference_token == "-") + case value_t::object: { - // "-" always fails the range check - throw std::out_of_range("array index '-' (" + - std::to_string(ptr->m_value.array->size()) + - ") is out of range"); + // note: at performs range check + ptr = &ptr->at(reference_token); + break; } - // error condition (cf. RFC 6901, Sect. 4) - if (reference_token.size() > 1 and reference_token[0] == '0') + case value_t::array: { - throw std::domain_error("array index must not begin with '0'"); - } + if (reference_token == "-") + { + // "-" always fails the range check + throw std::out_of_range("array index '-' (" + + std::to_string(ptr->m_value.array->size()) + + ") is out of range"); + } - // note: at performs range check - ptr = &ptr->at(static_cast(std::stoi(reference_token))); - break; - } + // error condition (cf. RFC 6901, Sect. 4) + if (reference_token.size() > 1 and reference_token[0] == '0') + { + throw std::domain_error("array index must not begin with '0'"); + } - default: - { - throw std::out_of_range("unresolved reference token '" + reference_token + "'"); + // note: at performs range check + ptr = &ptr->at(static_cast(std::stoi(reference_token))); + break; + } + + default: + { + throw std::out_of_range("unresolved reference token '" + reference_token + "'"); + } } } - } - - return *ptr; - } - - /// split the string input to reference tokens - static std::vector split(const std::string& reference_string) - { - std::vector result; - // special case: empty reference string -> no reference tokens - if (reference_string.empty()) - { - return result; + return *ptr; } - // check if nonempty reference string begins with slash - if (reference_string[0] != '/') + /// split the string input to reference tokens + static std::vector split(const std::string& reference_string) { - throw std::domain_error("JSON pointer must be empty or begin with '/'"); - } + std::vector result; - // extract the reference tokens: - // - slash: position of the last read slash (or end of string) - // - start: position after the previous slash - for ( - // search for the first slash after the first character - size_t slash = reference_string.find_first_of("/", 1), - // set the beginning of the first reference token - start = 1; - // we can stop if start == string::npos+1 = 0 - start != 0; - // set the beginning of the next reference token - // (will eventually be 0 if slash == std::string::npos) - start = slash + 1, - // find next slash - slash = reference_string.find_first_of("/", start)) - { - // use the text between the beginning of the reference token - // (start) and the last slash (slash). - auto reference_token = reference_string.substr(start, slash - start); + // special case: empty reference string -> no reference tokens + if (reference_string.empty()) + { + return result; + } + + // check if nonempty reference string begins with slash + if (reference_string[0] != '/') + { + throw std::domain_error("JSON pointer must be empty or begin with '/'"); + } - // check reference tokens are properly escaped - for (size_t pos = reference_token.find_first_of("~"); - pos != std::string::npos; - pos = reference_token.find_first_of("~", pos + 1)) + // extract the reference tokens: + // - slash: position of the last read slash (or end of string) + // - start: position after the previous slash + for ( + // search for the first slash after the first character + size_t slash = reference_string.find_first_of("/", 1), + // set the beginning of the first reference token + start = 1; + // we can stop if start == string::npos+1 = 0 + start != 0; + // set the beginning of the next reference token + // (will eventually be 0 if slash == std::string::npos) + start = slash + 1, + // find next slash + slash = reference_string.find_first_of("/", start)) { - assert(reference_token[pos] == '~'); + // use the text between the beginning of the reference token + // (start) and the last slash (slash). + auto reference_token = reference_string.substr(start, slash - start); + + // check reference tokens are properly escaped + for (size_t pos = reference_token.find_first_of("~"); + pos != std::string::npos; + pos = reference_token.find_first_of("~", pos + 1)) + { + assert(reference_token[pos] == '~'); - // ~ must be followed by 0 or 1 - if (pos == reference_token.size() - 1 or + // ~ must be followed by 0 or 1 + if (pos == reference_token.size() - 1 or (reference_token[pos + 1] != '0' and reference_token[pos + 1] != '1')) - { - throw std::domain_error("escape error: '~' must be followed with '0' or '1'"); + { + throw std::domain_error("escape error: '~' must be followed with '0' or '1'"); + } } + + // finally, store the reference token + unescape(reference_token); + result.push_back(reference_token); } - // finally, store the reference token - unescape(reference_token); - result.push_back(reference_token); + return result; } - return result; - } - - private: - /*! + private: + /*! @brief replace all occurrences of a substring by another string @param[in,out] s the string to manipulate @@ -9706,144 +9907,144 @@ basic_json_parser_63: @since version 2.0.0 */ - static void replace_substring(std::string& s, - const std::string& f, - const std::string& t) - { - assert(not f.empty()); + static void replace_substring(std::string& s, + const std::string& f, + const std::string& t) + { + assert(not f.empty()); - for ( - size_t pos = s.find(f); // find first occurrence of f - pos != std::string::npos; // make sure f was found - s.replace(pos, f.size(), t), // replace with t - pos = s.find(f, pos + t.size()) // find next occurrence of f - ); - } + for ( + size_t pos = s.find(f); // find first occurrence of f + pos != std::string::npos; // make sure f was found + s.replace(pos, f.size(), t), // replace with t + pos = s.find(f, pos + t.size()) // find next occurrence of f + ); + } - /// escape tilde and slash - static std::string escape(std::string s) - { - // escape "~"" to "~0" and "/" to "~1" - replace_substring(s, "~", "~0"); - replace_substring(s, "/", "~1"); - return s; - } + /// escape tilde and slash + static std::string escape(std::string s) + { + // escape "~"" to "~0" and "/" to "~1" + replace_substring(s, "~", "~0"); + replace_substring(s, "/", "~1"); + return s; + } - /// unescape tilde and slash - static void unescape(std::string& s) - { - // first transform any occurrence of the sequence '~1' to '/' - replace_substring(s, "~1", "/"); - // then transform any occurrence of the sequence '~0' to '~' - replace_substring(s, "~0", "~"); - } + /// unescape tilde and slash + static void unescape(std::string& s) + { + // first transform any occurrence of the sequence '~1' to '/' + replace_substring(s, "~1", "/"); + // then transform any occurrence of the sequence '~0' to '~' + replace_substring(s, "~0", "~"); + } - /*! + /*! @param[in] reference_string the reference string to the current value @param[in] value the value to consider @param[in,out] result the result object to insert values to @note Empty objects or arrays are flattened to `null`. */ - static void flatten(const std::string& reference_string, - const basic_json& value, - basic_json& result) - { - switch (value.m_type) + static void flatten(const std::string& reference_string, + const basic_json& value, + basic_json& result) { - case value_t::array: + switch (value.m_type) { - if (value.m_value.array->empty()) - { - // flatten empty array as null - result[reference_string] = nullptr; - } - else + case value_t::array: { - // iterate array and use index as reference string - for (size_t i = 0; i < value.m_value.array->size(); ++i) + if (value.m_value.array->empty()) { - flatten(reference_string + "/" + std::to_string(i), - value.m_value.array->operator[](i), result); + // flatten empty array as null + result[reference_string] = nullptr; } + else + { + // iterate array and use index as reference string + for (size_t i = 0; i < value.m_value.array->size(); ++i) + { + flatten(reference_string + "/" + std::to_string(i), + value.m_value.array->operator[](i), result); + } + } + break; } - break; - } - case value_t::object: - { - if (value.m_value.object->empty()) - { - // flatten empty object as null - result[reference_string] = nullptr; - } - else + case value_t::object: { - // iterate object and use keys as reference string - for (const auto& element : *value.m_value.object) + if (value.m_value.object->empty()) + { + // flatten empty object as null + result[reference_string] = nullptr; + } + else { - flatten(reference_string + "/" + escape(element.first), - element.second, result); + // iterate object and use keys as reference string + for (const auto& element : *value.m_value.object) + { + flatten(reference_string + "/" + escape(element.first), + element.second, result); + } } + break; } - break; - } - default: - { - // add primitive value with its reference string - result[reference_string] = value; - break; + default: + { + // add primitive value with its reference string + result[reference_string] = value; + break; + } } } - } - /*! + /*! @param[in] value flattened JSON @return unflattened JSON */ - static basic_json unflatten(const basic_json& value) - { - if (not value.is_object()) + static basic_json unflatten(const basic_json& value) { - throw std::domain_error("only objects can be unflattened"); - } + if (not value.is_object()) + { + throw std::domain_error("only objects can be unflattened"); + } - basic_json result; + basic_json result; - // iterate the JSON object values - for (const auto& element : *value.m_value.object) - { - if (not element.second.is_primitive()) + // iterate the JSON object values + for (const auto& element : *value.m_value.object) { - throw std::domain_error("values in object must be primitive"); + if (not element.second.is_primitive()) + { + throw std::domain_error("values in object must be primitive"); + } + + // assign value to reference pointed to by JSON pointer; Note + // that if the JSON pointer is "" (i.e., points to the whole + // value), function get_and_create returns a reference to + // result itself. An assignment will then create a primitive + // value. + json_pointer(element.first).get_and_create(result) = element.second; } - // assign value to reference pointed to by JSON pointer; Note - // that if the JSON pointer is "" (i.e., points to the whole - // value), function get_and_create returns a reference to - // result itself. An assignment will then create a primitive - // value. - json_pointer(element.first).get_and_create(result) = element.second; + return result; } - return result; - } - - private: - /// the reference tokens - std::vector reference_tokens {}; - }; + private: + /// the reference tokens + std::vector reference_tokens {}; + }; - ////////////////////////// - // JSON Pointer support // - ////////////////////////// + ////////////////////////// + // JSON Pointer support // + ////////////////////////// - /// @name JSON Pointer functions - /// @{ + /// @name JSON Pointer functions + /// @{ - /*! + /*! @brief access specified element via JSON Pointer Uses a JSON pointer to retrieve a reference to the respective JSON value. @@ -9876,12 +10077,12 @@ basic_json_parser_63: @since version 2.0.0 */ - reference operator[](const json_pointer& ptr) - { - return ptr.get_unchecked(this); - } + reference operator[](const json_pointer& ptr) + { + return ptr.get_unchecked(this); + } - /*! + /*! @brief access specified element via JSON Pointer Uses a JSON pointer to retrieve a reference to the respective JSON value. @@ -9903,12 +10104,12 @@ basic_json_parser_63: @since version 2.0.0 */ - const_reference operator[](const json_pointer& ptr) const - { - return ptr.get_unchecked(this); - } + const_reference operator[](const json_pointer& ptr) const + { + return ptr.get_unchecked(this); + } - /*! + /*! @brief access specified element via JSON Pointer Returns a reference to the element at with specified JSON pointer @a ptr, @@ -9928,12 +10129,12 @@ basic_json_parser_63: @since version 2.0.0 */ - reference at(const json_pointer& ptr) - { - return ptr.get_checked(this); - } + reference at(const json_pointer& ptr) + { + return ptr.get_checked(this); + } - /*! + /*! @brief access specified element via JSON Pointer Returns a const reference to the element at with specified JSON pointer @a @@ -9953,12 +10154,12 @@ basic_json_parser_63: @since version 2.0.0 */ - const_reference at(const json_pointer& ptr) const - { - return ptr.get_checked(this); - } + const_reference at(const json_pointer& ptr) const + { + return ptr.get_checked(this); + } - /*! + /*! @brief return flattened JSON value The function creates a JSON object whose keys are JSON pointers (see [RFC @@ -9980,14 +10181,14 @@ basic_json_parser_63: @since version 2.0.0 */ - basic_json flatten() const - { - basic_json result(value_t::object); - json_pointer::flatten("", *this, result); - return result; - } + basic_json flatten() const + { + basic_json result(value_t::object); + json_pointer::flatten("", *this, result); + return result; + } - /*! + /*! @brief unflatten a previously flattened JSON value The function restores the arbitrary nesting of a JSON value that has been @@ -10014,21 +10215,21 @@ basic_json_parser_63: @since version 2.0.0 */ - basic_json unflatten() const - { - return json_pointer::unflatten(*this); - } + basic_json unflatten() const + { + return json_pointer::unflatten(*this); + } - /// @} + /// @} - ////////////////////////// - // JSON Patch functions // - ////////////////////////// + ////////////////////////// + // JSON Patch functions // + ////////////////////////// - /// @name JSON Patch functions - /// @{ + /// @name JSON Patch functions + /// @{ - /*! + /*! @brief applies a JSON patch [JSON Patch](http://jsonpatch.com) defines a JSON document structure for @@ -10064,268 +10265,268 @@ basic_json_parser_63: @since version 2.0.0 */ - basic_json patch(const basic_json& json_patch) const - { - // make a working copy to apply the patch to - basic_json result = *this; - - // the valid JSON Patch operations - enum class patch_operations {add, remove, replace, move, copy, test, invalid}; - - const auto get_op = [](const std::string op) + basic_json patch(const basic_json& json_patch) const { - if (op == "add") - { - return patch_operations::add; - } - if (op == "remove") - { - return patch_operations::remove; - } - if (op == "replace") - { - return patch_operations::replace; - } - if (op == "move") - { - return patch_operations::move; - } - if (op == "copy") - { - return patch_operations::copy; - } - if (op == "test") - { - return patch_operations::test; - } + // make a working copy to apply the patch to + basic_json result = *this; - return patch_operations::invalid; - }; + // the valid JSON Patch operations + enum class patch_operations {add, remove, replace, move, copy, test, invalid}; - // wrapper for "add" operation; add value at ptr - const auto operation_add = [&result](json_pointer & ptr, basic_json val) - { - // adding to the root of the target document means replacing it - if (ptr.is_root()) - { - result = val; - } - else + const auto get_op = [](const std::string op) { - // make sure the top element of the pointer exists - json_pointer top_pointer = ptr.top(); - if (top_pointer != ptr) + if (op == "add") + { + return patch_operations::add; + } + if (op == "remove") + { + return patch_operations::remove; + } + if (op == "replace") + { + return patch_operations::replace; + } + if (op == "move") + { + return patch_operations::move; + } + if (op == "copy") + { + return patch_operations::copy; + } + if (op == "test") { - result.at(top_pointer); + return patch_operations::test; } - // get reference to parent of JSON pointer ptr - const auto last_path = ptr.pop_back(); - basic_json& parent = result[ptr]; + return patch_operations::invalid; + }; - switch (parent.m_type) + // wrapper for "add" operation; add value at ptr + const auto operation_add = [&result](json_pointer & ptr, basic_json val) + { + // adding to the root of the target document means replacing it + if (ptr.is_root()) { - case value_t::null: - case value_t::object: + result = val; + } + else + { + // make sure the top element of the pointer exists + json_pointer top_pointer = ptr.top(); + if (top_pointer != ptr) { - // use operator[] to add value - parent[last_path] = val; - break; + result.at(top_pointer); } - case value_t::array: + // get reference to parent of JSON pointer ptr + const auto last_path = ptr.pop_back(); + basic_json& parent = result[ptr]; + + switch (parent.m_type) { - if (last_path == "-") + case value_t::null: + case value_t::object: { - // special case: append to back - parent.push_back(val); + // use operator[] to add value + parent[last_path] = val; + break; } - else + + case value_t::array: { - const auto idx = std::stoi(last_path); - if (static_cast(idx) > parent.size()) + if (last_path == "-") { - // avoid undefined behavior - throw std::out_of_range("array index " + std::to_string(idx) + " is out of range"); + // special case: append to back + parent.push_back(val); } else { - // default case: insert add offset - parent.insert(parent.begin() + static_cast(idx), val); + const auto idx = std::stoi(last_path); + if (static_cast(idx) > parent.size()) + { + // avoid undefined behavior + throw std::out_of_range("array index " + std::to_string(idx) + " is out of range"); + } + else + { + // default case: insert add offset + parent.insert(parent.begin() + static_cast(idx), val); + } } + break; } - break; - } - default: - { - // if there exists a parent it cannot be primitive - assert(false); // LCOV_EXCL_LINE + default: + { + // if there exists a parent it cannot be primitive + assert(false); // LCOV_EXCL_LINE + } } } - } - }; - - // wrapper for "remove" operation; remove value at ptr - const auto operation_remove = [&result](json_pointer & ptr) - { - // get reference to parent of JSON pointer ptr - const auto last_path = ptr.pop_back(); - basic_json& parent = result.at(ptr); - - // remove child - if (parent.is_object()) - { - // perform range check - auto it = parent.find(last_path); - if (it != parent.end()) - { - parent.erase(it); - } - else - { - throw std::out_of_range("key '" + last_path + "' not found"); - } - } - else if (parent.is_array()) - { - // note erase performs range check - parent.erase(static_cast(std::stoi(last_path))); - } - }; - - // type check - if (not json_patch.is_array()) - { - // a JSON patch must be an array of objects - throw std::invalid_argument("JSON patch must be an array of objects"); - } + }; - // iterate and apply th eoperations - for (const auto& val : json_patch) - { - // wrapper to get a value for an operation - const auto get_value = [&val](const std::string & op, - const std::string & member, - bool string_type) -> basic_json& + // wrapper for "remove" operation; remove value at ptr + const auto operation_remove = [&result](json_pointer & ptr) { - // find value - auto it = val.m_value.object->find(member); - - // context-sensitive error message - const auto error_msg = (op == "op") ? "operation" : "operation '" + op + "'"; + // get reference to parent of JSON pointer ptr + const auto last_path = ptr.pop_back(); + basic_json& parent = result.at(ptr); - // check if desired value is present - if (it == val.m_value.object->end()) + // remove child + if (parent.is_object()) { - throw std::invalid_argument(error_msg + " must have member '" + member + "'"); + // perform range check + auto it = parent.find(last_path); + if (it != parent.end()) + { + parent.erase(it); + } + else + { + throw std::out_of_range("key '" + last_path + "' not found"); + } } - - // check if result is of type string - if (string_type and not it->second.is_string()) + else if (parent.is_array()) { - throw std::invalid_argument(error_msg + " must have string member '" + member + "'"); + // note erase performs range check + parent.erase(static_cast(std::stoi(last_path))); } - - // no error: return value - return it->second; }; // type check - if (not val.is_object()) + if (not json_patch.is_array()) { + // a JSON patch must be an array of objects throw std::invalid_argument("JSON patch must be an array of objects"); } - // collect mandatory members - const std::string op = get_value("op", "op", true); - const std::string path = get_value(op, "path", true); - json_pointer ptr(path); - - switch (get_op(op)) + // iterate and apply th eoperations + for (const auto& val : json_patch) { - case patch_operations::add: + // wrapper to get a value for an operation + const auto get_value = [&val](const std::string & op, + const std::string & member, + bool string_type) -> basic_json& { - operation_add(ptr, get_value("add", "value", false)); - break; - } + // find value + auto it = val.m_value.object->find(member); - case patch_operations::remove: - { - operation_remove(ptr); - break; - } + // context-sensitive error message + const auto error_msg = (op == "op") ? "operation" : "operation '" + op + "'"; - case patch_operations::replace: - { - // the "path" location must exist - use at() - result.at(ptr) = get_value("replace", "value", false); - break; - } + // check if desired value is present + if (it == val.m_value.object->end()) + { + throw std::invalid_argument(error_msg + " must have member '" + member + "'"); + } - case patch_operations::move: - { - const std::string from_path = get_value("move", "from", true); - json_pointer from_ptr(from_path); + // check if result is of type string + if (string_type and not it->second.is_string()) + { + throw std::invalid_argument(error_msg + " must have string member '" + member + "'"); + } - // the "from" location must exist - use at() - basic_json v = result.at(from_ptr); + // no error: return value + return it->second; + }; - // The move operation is functionally identical to a - // "remove" operation on the "from" location, followed - // immediately by an "add" operation at the target - // location with the value that was just removed. - operation_remove(from_ptr); - operation_add(ptr, v); - break; + // type check + if (not val.is_object()) + { + throw std::invalid_argument("JSON patch must be an array of objects"); } - case patch_operations::copy: + // collect mandatory members + const std::string op = get_value("op", "op", true); + const std::string path = get_value(op, "path", true); + json_pointer ptr(path); + + switch (get_op(op)) { - const std::string from_path = get_value("copy", "from", true);; - const json_pointer from_ptr(from_path); + case patch_operations::add: + { + operation_add(ptr, get_value("add", "value", false)); + break; + } - // the "from" location must exist - use at() - result[ptr] = result.at(from_ptr); - break; - } + case patch_operations::remove: + { + operation_remove(ptr); + break; + } - case patch_operations::test: - { - bool success = false; - try + case patch_operations::replace: { - // check if "value" matches the one at "path" // the "path" location must exist - use at() - success = (result.at(ptr) == get_value("test", "value", false)); + result.at(ptr) = get_value("replace", "value", false); + break; } - catch (std::out_of_range&) + + case patch_operations::move: { - // ignore out of range errors: success remains false + const std::string from_path = get_value("move", "from", true); + json_pointer from_ptr(from_path); + + // the "from" location must exist - use at() + basic_json v = result.at(from_ptr); + + // The move operation is functionally identical to a + // "remove" operation on the "from" location, followed + // immediately by an "add" operation at the target + // location with the value that was just removed. + operation_remove(from_ptr); + operation_add(ptr, v); + break; } - // throw an exception if test fails - if (not success) + case patch_operations::copy: { - throw std::domain_error("unsuccessful: " + val.dump()); + const std::string from_path = get_value("copy", "from", true);; + const json_pointer from_ptr(from_path); + + // the "from" location must exist - use at() + result[ptr] = result.at(from_ptr); + break; } - break; - } + case patch_operations::test: + { + bool success = false; + try + { + // check if "value" matches the one at "path" + // the "path" location must exist - use at() + success = (result.at(ptr) == get_value("test", "value", false)); + } + catch (std::out_of_range&) + { + // ignore out of range errors: success remains false + } - case patch_operations::invalid: - { - // op must be "add", "remove", "replace", "move", "copy", or - // "test" - throw std::invalid_argument("operation value '" + op + "' is invalid"); + // throw an exception if test fails + if (not success) + { + throw std::domain_error("unsuccessful: " + val.dump()); + } + + break; + } + + case patch_operations::invalid: + { + // op must be "add", "remove", "replace", "move", "copy", or + // "test" + throw std::invalid_argument("operation value '" + op + "' is invalid"); + } } } - } - return result; - } + return result; + } - /*! + /*! @brief creates a diff as a JSON patch Creates a [JSON Patch](http://jsonpatch.com) so that value @a source can @@ -10357,140 +10558,140 @@ basic_json_parser_63: @since version 2.0.0 */ - static basic_json diff(const basic_json& source, - const basic_json& target, - const std::string& path = "") - { - // the patch - basic_json result(value_t::array); - - // if the values are the same, return empty patch - if (source == target) + static basic_json diff(const basic_json& source, + const basic_json& target, + const std::string& path = "") { - return result; - } + // the patch + basic_json result(value_t::array); - if (source.type() != target.type()) - { - // different types: replace value - result.push_back( + // if the values are the same, return empty patch + if (source == target) { - {"op", "replace"}, - {"path", path}, - {"value", target} - }); - } - else - { - switch (source.type()) + return result; + } + + if (source.type() != target.type()) { - case value_t::array: + // different types: replace value + result.push_back( + { + {"op", "replace"}, + {"path", path}, + {"value", target} + }); + } + else + { + switch (source.type()) { - // first pass: traverse common elements - size_t i = 0; - while (i < source.size() and i < target.size()) + case value_t::array: { - // recursive call to compare array values at index i - auto temp_diff = diff(source[i], target[i], path + "/" + std::to_string(i)); - result.insert(result.end(), temp_diff.begin(), temp_diff.end()); - ++i; - } + // first pass: traverse common elements + size_t i = 0; + while (i < source.size() and i < target.size()) + { + // recursive call to compare array values at index i + auto temp_diff = diff(source[i], target[i], path + "/" + std::to_string(i)); + result.insert(result.end(), temp_diff.begin(), temp_diff.end()); + ++i; + } - // i now reached the end of at least one array - // in a second pass, traverse the remaining elements + // i now reached the end of at least one array + // in a second pass, traverse the remaining elements - // remove my remaining elements - const auto end_index = static_cast(result.size()); - while (i < source.size()) - { - // add operations in reverse order to avoid invalid - // indices - result.insert(result.begin() + end_index, object( + // remove my remaining elements + const auto end_index = static_cast(result.size()); + while (i < source.size()) { - {"op", "remove"}, - {"path", path + "/" + std::to_string(i)} - })); - ++i; - } + // add operations in reverse order to avoid invalid + // indices + result.insert(result.begin() + end_index, object( + { + {"op", "remove"}, + {"path", path + "/" + std::to_string(i)} + })); + ++i; + } - // add other remaining elements - while (i < target.size()) - { - result.push_back( + // add other remaining elements + while (i < target.size()) { - {"op", "add"}, - {"path", path + "/" + std::to_string(i)}, - {"value", target[i]} - }); - ++i; - } + result.push_back( + { + {"op", "add"}, + {"path", path + "/" + std::to_string(i)}, + {"value", target[i]} + }); + ++i; + } - break; - } + break; + } - case value_t::object: - { - // first pass: traverse this object's elements - for (auto it = source.begin(); it != source.end(); ++it) + case value_t::object: { - // escape the key name to be used in a JSON patch - const auto key = json_pointer::escape(it.key()); - - if (target.find(it.key()) != target.end()) - { - // recursive call to compare object values at key it - auto temp_diff = diff(it.value(), target[it.key()], path + "/" + key); - result.insert(result.end(), temp_diff.begin(), temp_diff.end()); - } - else + // first pass: traverse this object's elements + for (auto it = source.begin(); it != source.end(); ++it) { - // found a key that is not in o -> remove it - result.push_back(object( + // escape the key name to be used in a JSON patch + const auto key = json_pointer::escape(it.key()); + + if (target.find(it.key()) != target.end()) { - {"op", "remove"}, - {"path", path + "/" + key} - })); + // recursive call to compare object values at key it + auto temp_diff = diff(it.value(), target[it.key()], path + "/" + key); + result.insert(result.end(), temp_diff.begin(), temp_diff.end()); + } + else + { + // found a key that is not in o -> remove it + result.push_back(object( + { + {"op", "remove"}, + {"path", path + "/" + key} + })); + } } - } - // second pass: traverse other object's elements - for (auto it = target.begin(); it != target.end(); ++it) - { - if (source.find(it.key()) == source.end()) + // second pass: traverse other object's elements + for (auto it = target.begin(); it != target.end(); ++it) { - // found a key that is not in this -> add it - const auto key = json_pointer::escape(it.key()); - result.push_back( + if (source.find(it.key()) == source.end()) { - {"op", "add"}, - {"path", path + "/" + key}, - {"value", it.value()} - }); + // found a key that is not in this -> add it + const auto key = json_pointer::escape(it.key()); + result.push_back( + { + {"op", "add"}, + {"path", path + "/" + key}, + {"value", it.value()} + }); + } } - } - break; - } + break; + } - default: - { - // both primitive type: replace value - result.push_back( + default: { - {"op", "replace"}, - {"path", path}, - {"value", target} - }); - break; + // both primitive type: replace value + result.push_back( + { + {"op", "replace"}, + {"path", path}, + {"value", target} + }); + break; + } } } - } - return result; - } + return result; + } - /// @} -}; + /// @} + }; ///////////// @@ -10505,7 +10706,7 @@ uses the standard template types. @since version 1.0.0 */ -using json = basic_json<>; + using json = basic_json<>; } @@ -10521,32 +10722,32 @@ namespace std @since version 1.0.0 */ -template<> -inline void swap(nlohmann::json& j1, - nlohmann::json& j2) noexcept( - is_nothrow_move_constructible::value and - is_nothrow_move_assignable::value - ) -{ - j1.swap(j2); -} + template<> + inline void swap(nlohmann::json& j1, + nlohmann::json& j2) noexcept( + is_nothrow_move_constructible::value and + is_nothrow_move_assignable::value + ) + { + j1.swap(j2); + } /// hash value for JSON objects -template<> -struct hash -{ - /*! + template<> + struct hash + { + /*! @brief return a hash value for a JSON object @since version 1.0.0 */ - std::size_t operator()(const nlohmann::json& j) const - { - // a naive hashing via the string representation - const auto& h = hash(); - return h(j.dump()); - } -}; + std::size_t operator()(const nlohmann::json& j) const + { + // a naive hashing via the string representation + const auto& h = hash(); + return h(j.dump()); + } + }; } /*! @@ -10557,35 +10758,37 @@ can be used by adding `"_json"` to a string literal and returns a JSON object if no parse error occurred. @param[in] s a string representation of a JSON object +@param[in] n the length of string @a s @return a JSON object @since version 1.0.0 */ -inline nlohmann::json operator "" _json(const char* s, std::size_t) +inline nlohmann::json operator "" _json(const char* s, std::size_t n) { - return nlohmann::json::parse(s); + return nlohmann::json::parse(s, s + n); } /*! @brief user-defined string literal for JSON pointer This operator implements a user-defined string literal for JSON Pointers. It -can be used by adding `"_json"` to a string literal and returns a JSON pointer +can be used by adding `"_json_pointer"` to a string literal and returns a JSON pointer object if no parse error occurred. @param[in] s a string representation of a JSON Pointer +@param[in] n the length of string @a s @return a JSON pointer object @since version 2.0.0 */ -inline nlohmann::json::json_pointer operator "" _json_pointer(const char* s, std::size_t) +inline nlohmann::json::json_pointer operator "" _json_pointer(const char* s, std::size_t n) { - return nlohmann::json::json_pointer(s); + return nlohmann::json::json_pointer(std::string(s, n)); } // restore GCC/clang diagnostic settings #if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) - #pragma GCC diagnostic pop +#pragma GCC diagnostic pop #endif #endif