Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/ArthurSonzogni/nlohmann_json_cmake_fetchcontent.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitHub Actions <action@github.com>2020-06-28 14:43:44 +0300
committerGitHub Actions <action@github.com>2020-06-28 14:43:44 +0300
commit69d0b3584248a6a2eaf5938bef59bd497743d374 (patch)
treeef78645db552b5fcbaff2996280a7bca29a14d0d
parentb23232e80116232b8a0a3968e064e1f9de90930e (diff)
Upstream release v2.0.0v2.0.0
-rw-r--r--README.md2
-rw-r--r--include/nlohmann/json.hpp3718
2 files changed, 2758 insertions, 962 deletions
diff --git a/README.md b/README.md
index 1844d03..2c70f79 100644
--- a/README.md
+++ b/README.md
@@ -13,7 +13,7 @@ include(FetchContent)
FetchContent_Declare(json
GIT_REPOSITORY https://github.com/ArthurSonzogni/nlohman_json
- GIT_TAG v1.1.0)
+ GIT_TAG v2.0.0)
FetchContent_GetProperties(json)
if(NOT json_POPULATED)
diff --git a/include/nlohmann/json.hpp b/include/nlohmann/json.hpp
index db73336..b02a134 100644
--- a/include/nlohmann/json.hpp
+++ b/include/nlohmann/json.hpp
@@ -1,38 +1,29 @@
-/*!
-@mainpage
-
-These pages contain the API documentation of JSON for Modern C++, a C++11
-header-only JSON class.
-
-Class @ref nlohmann::basic_json is a good entry point for the documentation.
-
-@copyright The code is licensed under the [MIT
- License](http://opensource.org/licenses/MIT):
- <br>
- Copyright &copy; 2013-2016 Niels Lohmann.
- <br>
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
- <br>
- The above copyright notice and this permission notice shall be included in
- all copies or substantial portions of the Software.
- <br>
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- SOFTWARE.
-
-@author [Niels Lohmann](http://nlohmann.me)
-@see https://github.com/nlohmann/json to download the source code
-
-@version 1.1.0
+/*
+ __ _____ _____ _____
+ __| | __| | | | JSON for Modern C++
+| | |__ | | | | | | version 2.0.0
+|_____|_____|_____|_|___| https://github.com/nlohmann/json
+
+Licensed under the MIT License <http://opensource.org/licenses/MIT>.
+Copyright (c) 2013-2016 Niels Lohmann <http://nlohmann.me>.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
*/
#ifndef NLOHMANN_JSON_HPP
@@ -41,6 +32,7 @@ Class @ref nlohmann::basic_json is a good entry point for the documentation.
#include <algorithm>
#include <array>
#include <cassert>
+#include <cerrno>
#include <ciso646>
#include <cmath>
#include <cstddef>
@@ -61,25 +53,12 @@ Class @ref nlohmann::basic_json is a good entry point for the documentation.
#include <utility>
#include <vector>
-// enable ssize_t on MinGW
-#ifdef __GNUC__
- #ifdef __MINGW32__
- #include <sys/types.h>
- #endif
-#endif
-
// disable float-equal warnings on GCC/clang
#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wfloat-equal"
#endif
-// enable ssize_t for MSVC
-#ifdef _MSC_VER
- #include <basetsd.h>
- using ssize_t = SSIZE_T;
-#endif
-
/*!
@brief namespace for Niels Lohmann
@see https://github.com/nlohmann
@@ -109,24 +88,39 @@ struct has_mapped_type
static constexpr bool value = sizeof(test<T>(0)) == 1;
};
+/*!
+@brief helper class to create locales with decimal point
+@sa https://github.com/nlohmann/json/issues/51#issuecomment-86869315
+*/
+class DecimalSeparator : public std::numpunct<char>
+{
+ protected:
+ char do_decimal_point() const
+ {
+ return '.';
+ }
+};
+
}
/*!
@brief a class to store JSON values
-@tparam ObjectType type for JSON objects (@c std::map by default; will be used
+@tparam ObjectType type for JSON objects (`std::map` by default; will be used
in @ref object_t)
-@tparam ArrayType type for JSON arrays (@c std::vector by default; will be used
+@tparam ArrayType type for JSON arrays (`std::vector` by default; will be used
in @ref array_t)
-@tparam StringType type for JSON strings and object keys (@c std::string by
+@tparam StringType type for JSON strings and object keys (`std::string` by
default; will be used in @ref string_t)
-@tparam BooleanType type for JSON booleans (@c `bool` by default; will be used
+@tparam BooleanType type for JSON booleans (`bool` by default; will be used
in @ref boolean_t)
-@tparam NumberIntegerType type for JSON integer numbers (@c `int64_t` by
+@tparam NumberIntegerType type for JSON integer numbers (`int64_t` by
default; will be used in @ref number_integer_t)
-@tparam NumberFloatType type for JSON floating-point numbers (@c `double` by
+@tparam NumberUnsignedType type for JSON unsigned integer numbers (@c
+`uint64_t` by default; will be used in @ref number_unsigned_t)
+@tparam NumberFloatType type for JSON floating-point numbers (`double` by
default; will be used in @ref number_float_t)
-@tparam AllocatorType type of the allocator to use (@c `std::allocator` by
+@tparam AllocatorType type of the allocator to use (`std::allocator` by
default)
@requirement The class satisfies the following concept requirements:
@@ -173,7 +167,8 @@ default)
@note ObjectType trick from http://stackoverflow.com/a/9860911
@endinternal
-@see RFC 7159 <http://rfc7159.net/rfc7159>
+@see [RFC 7159: The JavaScript Object Notation (JSON) Data Interchange
+Format](http://rfc7159.net/rfc7159)
@since version 1.0.0
@@ -184,7 +179,8 @@ template <
template<typename U, typename... Args> class ArrayType = std::vector,
class StringType = std::string,
class BooleanType = bool,
- class NumberIntegerType = int64_t,
+ class NumberIntegerType = std::int64_t,
+ class NumberUnsignedType = std::uint64_t,
class NumberFloatType = double,
template<typename U> class AllocatorType = std::allocator
>
@@ -197,10 +193,14 @@ class basic_json
StringType,
BooleanType,
NumberIntegerType,
+ NumberUnsignedType,
NumberFloatType,
AllocatorType>;
public:
+ // forward declarations
+ template<typename Base> class json_reverse_iterator;
+ class json_pointer;
/////////////////////
// container types //
@@ -230,9 +230,6 @@ class basic_json
/// the type of an element const pointer
using const_pointer = typename std::allocator_traits<allocator_type>::const_pointer;
- // forward declaration
- template<typename Base> class json_reverse_iterator;
-
/// an iterator for a basic_json container
class iterator;
/// a const iterator for a basic_json container
@@ -274,8 +271,8 @@ class basic_json
@tparam ObjectType the container to store objects (e.g., `std::map` or
`std::unordered_map`)
- @tparam StringType the type of the keys or names (e.g., `std::string`). The
- comparison function `std::less<StringType>` is used to order elements
+ @tparam StringType the type of the keys or names (e.g., `std::string`).
+ The comparison function `std::less<StringType>` is used to order elements
inside the container.
@tparam AllocatorType the allocator to use for objects (e.g.,
`std::allocator`)
@@ -283,8 +280,8 @@ class basic_json
#### Default type
With the default values for @a ObjectType (`std::map`), @a StringType
- (`std::string`), and @a AllocatorType (`std::allocator`), the default value
- for @a object_t is:
+ (`std::string`), and @a AllocatorType (`std::allocator`), the default
+ value for @a object_t is:
@code {.cpp}
std::map<
@@ -301,16 +298,16 @@ class basic_json
the default type, objects have the following behavior:
- When all names are unique, objects will be interoperable in the sense
- that all software implementations receiving that object will agree on the
- name-value mappings.
+ that all software implementations receiving that object will agree on
+ the name-value mappings.
- When the names within an object are not unique, later stored name/value
pairs overwrite previously stored name/value pairs, leaving the used
names unique. For instance, `{"key": 1}` and `{"key": 2, "key": 1}` will
be treated as equal and both stored as `{"key": 1}`.
- Internally, name/value pairs are stored in lexicographical order of the
- names. Objects will also be serialized (see @ref dump) in this order. For
- instance, `{"b": 1, "a": 2}` and `{"a": 2, "b": 1}` will be stored and
- serialized as `{"a": 2, "b": 1}`.
+ names. Objects will also be serialized (see @ref dump) in this order.
+ For instance, `{"b": 1, "a": 2}` and `{"a": 2, "b": 1}` will be stored
+ and serialized as `{"a": 2, "b": 1}`.
- When comparing objects, the order of the name/value pairs is irrelevant.
This makes objects interoperable in the sense that they will not be
affected by these differences. For instance, `{"b": 1, "a": 2}` and
@@ -323,23 +320,24 @@ class basic_json
In this class, the object's limit of nesting is not constraint explicitly.
However, a maximum depth of nesting may be introduced by the compiler or
- runtime environment. A theoretical limit can be queried by calling the @ref
- max_size function of a JSON object.
+ runtime environment. A theoretical limit can be queried by calling the
+ @ref max_size function of a JSON object.
#### Storage
Objects are stored as pointers in a @ref basic_json type. That is, for any
- access to object values, a pointer of type `object_t*` must be dereferenced.
+ access to object values, a pointer of type `object_t*` must be
+ dereferenced.
@sa @ref array_t -- type for an array value
@since version 1.0.0
- @note The order name/value pairs are added to the object is *not* preserved
- by the library. Therefore, iterating an object may return name/value pairs
- in a different order than they were originally stored. In fact, keys will
- be traversed in alphabetical order as `std::map` with `std::less` is used
- by default. Please note this behavior conforms to [RFC
+ @note The order name/value pairs are added to the object is *not*
+ preserved by the library. Therefore, iterating an object may return
+ name/value pairs in a different order than they were originally stored. In
+ fact, keys will be traversed in alphabetical order as `std::map` with
+ `std::less` is used by default. Please note this behavior conforms to [RFC
7159](http://rfc7159.net/rfc7159), because any order implements the
specified "unordered" nature of JSON objects.
*/
@@ -381,8 +379,8 @@ class basic_json
In this class, the array's limit of nesting is not constraint explicitly.
However, a maximum depth of nesting may be introduced by the compiler or
- runtime environment. A theoretical limit can be queried by calling the @ref
- max_size function of a JSON array.
+ runtime environment. A theoretical limit can be queried by calling the
+ @ref max_size function of a JSON array.
#### Storage
@@ -402,8 +400,8 @@ class basic_json
> A string is a sequence of zero or more Unicode characters.
To store objects in C++, a type is defined by the template parameter
- described below. Unicode values are split by the JSON class into byte-sized
- characters during deserialization.
+ described below. Unicode values are split by the JSON class into
+ byte-sized characters during deserialization.
@tparam StringType the container to store strings (e.g., `std::string`).
Note this container is used for keys/names in objects, see @ref object_t.
@@ -472,18 +470,19 @@ class basic_json
@brief a type for a number (integer)
[RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows:
- > The representation of numbers is similar to that used in most programming
- > languages. A number is represented in base 10 using decimal digits. It
- > contains an integer component that may be prefixed with an optional minus
- > sign, which may be followed by a fraction part and/or an exponent part.
- > Leading zeros are not allowed. (...) Numeric values that cannot be
- > represented in the grammar below (such as Infinity and NaN) are not
- > permitted.
-
- This description includes both integer and floating-point numbers. However,
- C++ allows more precise storage if it is known whether the number is an
- integer or a floating-point number. Therefore, two different types, @ref
- number_integer_t and @ref number_float_t are used.
+ > The representation of numbers is similar to that used in most
+ > programming languages. A number is represented in base 10 using decimal
+ > digits. It contains an integer component that may be prefixed with an
+ > optional minus sign, which may be followed by a fraction part and/or an
+ > exponent part. Leading zeros are not allowed. (...) Numeric values that
+ > cannot be represented in the grammar below (such as Infinity and NaN)
+ > are not permitted.
+
+ This description includes both integer and floating-point numbers.
+ However, C++ allows more precise storage if it is known whether the number
+ is a signed integer, an unsigned integer or a floating-point number.
+ Therefore, three different types, @ref number_integer_t, @ref
+ number_unsigned_t and @ref number_float_t are used.
To store integer numbers in C++, a type is defined by the template
parameter @a NumberIntegerType which chooses the type to use.
@@ -502,8 +501,8 @@ class basic_json
- The restrictions about leading zeros is not enforced in C++. Instead,
leading zeros in integer literals lead to an interpretation as octal
number. Internally, the value will be stored as decimal number. For
- instance, the C++ integer literal `010` will be serialized to `8`. During
- deserialization, leading zeros yield an error.
+ instance, the C++ integer literal `010` will be serialized to `8`.
+ During deserialization, leading zeros yield an error.
- Not-a-number (NaN) values will be serialized to `null`.
#### Limits
@@ -514,9 +513,10 @@ class basic_json
When the default type is used, the maximal integer number that can be
stored is `9223372036854775807` (INT64_MAX) and the minimal integer number
that can be stored is `-9223372036854775808` (INT64_MIN). Integer numbers
- that are out of range will yield over/underflow when used in a constructor.
- During deserialization, too large or small integer numbers will be
- automatically be stored as @ref number_float_t.
+ that are out of range will yield over/underflow when used in a
+ constructor. During deserialization, too large or small integer numbers
+ will be automatically be stored as @ref number_unsigned_t or @ref
+ number_float_t.
[RFC 7159](http://rfc7159.net/rfc7159) further states:
> Note that when such software is used, numbers that are integers and are
@@ -532,26 +532,101 @@ class basic_json
@sa @ref number_float_t -- type for number values (floating-point)
+ @sa @ref number_unsigned_t -- type for number values (unsigned integer)
+
@since version 1.0.0
*/
using number_integer_t = NumberIntegerType;
/*!
+ @brief a type for a number (unsigned)
+
+ [RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows:
+ > The representation of numbers is similar to that used in most
+ > programming languages. A number is represented in base 10 using decimal
+ > digits. It contains an integer component that may be prefixed with an
+ > optional minus sign, which may be followed by a fraction part and/or an
+ > exponent part. Leading zeros are not allowed. (...) Numeric values that
+ > cannot be represented in the grammar below (such as Infinity and NaN)
+ > are not permitted.
+
+ This description includes both integer and floating-point numbers.
+ However, C++ allows more precise storage if it is known whether the number
+ is a signed integer, an unsigned integer or a floating-point number.
+ Therefore, three different types, @ref number_integer_t, @ref
+ number_unsigned_t and @ref number_float_t are used.
+
+ To store unsigned integer numbers in C++, a type is defined by the
+ template parameter @a NumberUnsignedType which chooses the type to use.
+
+ #### Default type
+
+ With the default values for @a NumberUnsignedType (`uint64_t`), the
+ default value for @a number_unsigned_t is:
+
+ @code {.cpp}
+ uint64_t
+ @endcode
+
+ #### Default behavior
+
+ - The restrictions about leading zeros is not enforced in C++. Instead,
+ leading zeros in integer literals lead to an interpretation as octal
+ number. Internally, the value will be stored as decimal number. For
+ instance, the C++ integer literal `010` will be serialized to `8`.
+ During deserialization, leading zeros yield an error.
+ - Not-a-number (NaN) values will be serialized to `null`.
+
+ #### Limits
+
+ [RFC 7159](http://rfc7159.net/rfc7159) specifies:
+ > An implementation may set limits on the range and precision of numbers.
+
+ When the default type is used, the maximal integer number that can be
+ stored is `18446744073709551615` (UINT64_MAX) and the minimal integer
+ number that can be stored is `0`. Integer numbers that are out of range
+ will yield over/underflow when used in a constructor. During
+ deserialization, too large or small integer numbers will be automatically
+ be stored as @ref number_integer_t or @ref number_float_t.
+
+ [RFC 7159](http://rfc7159.net/rfc7159) further states:
+ > Note that when such software is used, numbers that are integers and are
+ > in the range \f$[-2^{53}+1, 2^{53}-1]\f$ are interoperable in the sense
+ > that implementations will agree exactly on their numeric values.
+
+ As this range is a subrange (when considered in conjunction with the
+ number_integer_t type) of the exactly supported range [0, UINT64_MAX], this
+ class's integer type is interoperable.
+
+ #### Storage
+
+ Integer number values are stored directly inside a @ref basic_json type.
+
+ @sa @ref number_float_t -- type for number values (floating-point)
+
+ @sa @ref number_integer_t -- type for number values (integer)
+
+ @since version 2.0.0
+ */
+ using number_unsigned_t = NumberUnsignedType;
+
+ /*!
@brief a type for a number (floating-point)
[RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows:
- > The representation of numbers is similar to that used in most programming
- > languages. A number is represented in base 10 using decimal digits. It
- > contains an integer component that may be prefixed with an optional minus
- > sign, which may be followed by a fraction part and/or an exponent part.
- > Leading zeros are not allowed. (...) Numeric values that cannot be
- > represented in the grammar below (such as Infinity and NaN) are not
- > permitted.
-
- This description includes both integer and floating-point numbers. However,
- C++ allows more precise storage if it is known whether the number is an
- integer or a floating-point number. Therefore, two different types, @ref
- number_integer_t and @ref number_float_t are used.
+ > The representation of numbers is similar to that used in most
+ > programming languages. A number is represented in base 10 using decimal
+ > digits. It contains an integer component that may be prefixed with an
+ > optional minus sign, which may be followed by a fraction part and/or an
+ > exponent part. Leading zeros are not allowed. (...) Numeric values that
+ > cannot be represented in the grammar below (such as Infinity and NaN)
+ > are not permitted.
+
+ This description includes both integer and floating-point numbers.
+ However, C++ allows more precise storage if it is known whether the number
+ is a signed integer, an unsigned integer or a floating-point number.
+ Therefore, three different types, @ref number_integer_t, @ref
+ number_unsigned_t and @ref number_float_t are used.
To store floating-point numbers in C++, a type is defined by the template
parameter @a NumberFloatType which chooses the type to use.
@@ -568,8 +643,8 @@ class basic_json
#### Default behavior
- The restrictions about leading zeros is not enforced in C++. Instead,
- leading zeros in floating-point literals will be ignored. Internally, the
- value will be stored as decimal number. For instance, the C++
+ leading zeros in floating-point literals will be ignored. Internally,
+ the value will be stored as decimal number. For instance, the C++
floating-point literal `01.2` will be serialized to `1.2`. During
deserialization, leading zeros yield an error.
- Not-a-number (NaN) values will be serialized to `null`.
@@ -580,9 +655,9 @@ class basic_json
> This specification allows implementations to set limits on the range and
> precision of numbers accepted. Since software that implements IEEE
> 754-2008 binary64 (double precision) numbers is generally available and
- > widely used, good interoperability can be achieved by implementations that
- > expect no more precision or range than these provide, in the sense that
- > implementations will approximate JSON numbers within the expected
+ > widely used, good interoperability can be achieved by implementations
+ > that expect no more precision or range than these provide, in the sense
+ > that implementations will approximate JSON numbers within the expected
> precision.
This implementation does exactly follow this approach, as it uses double
@@ -597,6 +672,8 @@ class basic_json
@sa @ref number_integer_t -- type for number values (integer)
+ @sa @ref number_unsigned_t -- type for number values (unsigned integer)
+
@since version 1.0.0
*/
using number_float_t = NumberFloatType;
@@ -620,18 +697,20 @@ class basic_json
*/
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 (integer)
- number_float, ///< number value (floating-point)
- discarded ///< discarded by the the parser callback function
+ 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 (integer)
+ number_unsigned, ///< number value (unsigned integer)
+ number_float, ///< number value (floating-point)
+ discarded ///< discarded by the the parser callback function
};
private:
+
/// helper for exception-safe object creation
template<typename T, typename... Args>
static T* create(Args&& ... args)
@@ -669,15 +748,19 @@ class basic_json
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() noexcept = default;
+ 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
@@ -715,6 +798,12 @@ class basic_json
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);
@@ -784,9 +873,9 @@ class basic_json
influenced. When passed to @ref parse(std::istream&, parser_callback_t) or
@ref parse(const string_t&, parser_callback_t), it is called on certain
events (passed as @ref parse_event_t via parameter @a event) with a set
- recursion depth @a depth and context JSON value @a parsed. The return value
- of the callback function is a boolean indicating whether the element that
- emitted the callback shall be kept or not.
+ recursion depth @a depth and context JSON value @a parsed. The return
+ value of the callback function is a boolean indicating whether the element
+ that emitted the callback shall be kept or not.
We distinguish six scenarios (determined by the event type) in which the
callback function can be called. The following table describes the values
@@ -806,8 +895,8 @@ class basic_json
- Discarded values in structured types are skipped. That is, the parser
will behave as if the discarded value was never read.
- - In case a value outside a structured type is skipped, it is replaced with
- `null`. This case happens if the top-level element is skipped.
+ - In case a value outside a structured type is skipped, it is replaced
+ with `null`. This case happens if the top-level element is skipped.
@param[in] depth the depth of the recursion during parsing
@@ -870,6 +959,8 @@ class basic_json
(floating-point) value
@sa @ref basic_json(const number_integer_t) -- create a number (integer)
value
+ @sa @ref basic_json(const number_unsigned_t) -- create a number (unsigned)
+ value
@since version 1.0.0
*/
@@ -885,7 +976,12 @@ class basic_json
@complexity Constant.
- @requirement This function satisfies the Container requirements:
+ @exceptionsafety No-throw guarantee: this constructor never throws
+ exceptions.
+
+ @requirement This function helps `basic_json` satisfying the
+ [Container](http://en.cppreference.com/w/cpp/concept/Container)
+ requirements:
- The complexity is constant.
- As postcondition, it holds: `basic_json().empty() == true`.
@@ -896,19 +992,22 @@ class basic_json
@since version 1.0.0
*/
- basic_json() noexcept = default;
+ basic_json() = default;
/*!
@brief create a null object (explicitly)
Create a `null` JSON value. This is the explicitly version of the `null`
value constructor as it takes a null pointer as parameter. It allows to
- create `null` values by explicitly assigning a @c nullptr to a JSON value.
- The passed null pointer itself is not read -- it is only used to choose the
- right constructor.
+ create `null` values by explicitly assigning a `nullptr` to a JSON value.
+ The passed null pointer itself is not read -- it is only used to choose
+ the right constructor.
@complexity Constant.
+ @exceptionsafety No-throw guarantee: this constructor never throws
+ exceptions.
+
@liveexample{The following code shows the constructor with null pointer
parameter.,basic_json__nullptr_t}
@@ -932,8 +1031,8 @@ class basic_json
@throw std::bad_alloc if allocation for object value fails
- @liveexample{The following code shows the constructor with an @ref object_t
- parameter.,basic_json__object_t}
+ @liveexample{The following code shows the constructor with an @ref
+ object_t parameter.,basic_json__object_t}
@sa @ref basic_json(const CompatibleObjectType&) -- create an object value
from a compatible STL container
@@ -948,11 +1047,14 @@ class basic_json
@brief create an object (implicit)
Create an object JSON value with a given content. This constructor allows
- any type that can be used to construct values of type @ref object_t.
- Examples include the types `std::map` and `std::unordered_map`.
+ any type @a CompatibleObjectType that can be used to construct values of
+ type @ref object_t.
- @tparam CompatibleObjectType an object type whose `key_type` and
- `value_type` is compatible to @ref object_t
+ @tparam CompatibleObjectType An object type whose `key_type` and
+ `value_type` is compatible to @ref object_t. Examples include `std::map`,
+ `std::unordered_map`, `std::multimap`, and `std::unordered_multimap` with
+ a `key_type` of `std::string`, and a `value_type` from which a @ref
+ basic_json value can be constructed.
@param[in] val a value for the object
@@ -1007,11 +1109,14 @@ class basic_json
@brief create an array (implicit)
Create an array JSON value with a given content. This constructor allows
- any type that can be used to construct values of type @ref array_t.
- Examples include the types `std::vector`, `std::list`, and `std::set`.
+ any type @a CompatibleArrayType that can be used to construct values of
+ type @ref array_t.
- @tparam CompatibleArrayType an object type whose `value_type` is compatible
- to @ref array_t
+ @tparam CompatibleArrayType An object type whose `value_type` is
+ compatible to @ref array_t. Examples include `std::vector`, `std::deque`,
+ `std::list`, `std::forward_list`, `std::array`, `std::set`,
+ `std::unordered_set`, `std::multiset`, and `unordered_multiset` with a
+ `value_type` from which a @ref basic_json value can be constructed.
@param[in] val a value for the array
@@ -1055,8 +1160,8 @@ class basic_json
@throw std::bad_alloc if allocation for string value fails
- @liveexample{The following code shows the constructor with an @ref string_t
- parameter.,basic_json__string_t}
+ @liveexample{The following code shows the constructor with an @ref
+ string_t parameter.,basic_json__string_t}
@sa @ref basic_json(const typename string_t::value_type*) -- create a
string value from a character pointer
@@ -1101,7 +1206,7 @@ class basic_json
@param[in] val a value for the string
@tparam CompatibleStringType an string type which is compatible to @ref
- string_t
+ string_t, for instance `std::string`.
@complexity Linear in the size of the passed @a val.
@@ -1138,7 +1243,7 @@ class basic_json
@since version 1.0.0
*/
- basic_json(boolean_t val)
+ basic_json(boolean_t val) noexcept
: m_type(value_t::boolean), m_value(val)
{}
@@ -1147,18 +1252,16 @@ class basic_json
Create an integer number JSON value with a given content.
- @tparam T helper type to compare number_integer_t and int (not visible in)
- the interface.
+ @tparam T A helper type to remove this function via SFINAE in case @ref
+ number_integer_t is the same as `int`. In this case, this constructor
+ would have the same signature as @ref basic_json(const int value). Note
+ the helper type @a T is not visible in this constructor's interface.
@param[in] val an integer to create a JSON number from
- @note This constructor would have the same signature as @ref
- basic_json(const int value), so we need to switch this one off in case
- number_integer_t is the same as int. This is done via the helper type @a T.
-
@complexity Constant.
- @liveexample{The example below shows the construction of a JSON integer
+ @liveexample{The example below shows the construction of an integer
number value.,basic_json__number_integer_t}
@sa @ref basic_json(const int) -- create a number value (integer)
@@ -1171,8 +1274,9 @@ class basic_json
typename std::enable_if<
not (std::is_same<T, int>::value)
and std::is_same<T, number_integer_t>::value
- , int>::type = 0>
- basic_json(const number_integer_t val)
+ , int>::type
+ = 0>
+ basic_json(const number_integer_t val) noexcept
: m_type(value_t::number_integer), m_value(val)
{}
@@ -1186,12 +1290,12 @@ class basic_json
@note This constructor allows to pass enums directly to a constructor. As
C++ has no way of specifying the type of an anonymous enum explicitly, we
can only rely on the fact that such values implicitly convert to int. As
- int may already be the same type of number_integer_t, we may need to switch
- off the constructor @ref basic_json(const number_integer_t).
+ int may already be the same type of number_integer_t, we may need to
+ switch off the constructor @ref basic_json(const number_integer_t).
@complexity Constant.
- @liveexample{The example below shows the construction of a JSON integer
+ @liveexample{The example below shows the construction of an integer
number value from an anonymous enum.,basic_json__const_int}
@sa @ref basic_json(const number_integer_t) -- create a number value
@@ -1201,7 +1305,7 @@ class basic_json
@since version 1.0.0
*/
- basic_json(const int val)
+ basic_json(const int val) noexcept
: m_type(value_t::number_integer),
m_value(static_cast<number_integer_t>(val))
{}
@@ -1210,19 +1314,19 @@ class basic_json
@brief create an integer number (implicit)
Create an integer number JSON value with a given content. This constructor
- allows any type that can be used to construct values of type @ref
- number_integer_t. Examples may include the types `int`, `int32_t`, or
- `short`.
+ allows any type @a CompatibleNumberIntegerType that can be used to
+ construct values of type @ref number_integer_t.
- @tparam CompatibleNumberIntegerType an integer type which is compatible to
- @ref number_integer_t.
+ @tparam CompatibleNumberIntegerType An integer type which is compatible to
+ @ref number_integer_t. Examples include the types `int`, `int32_t`,
+ `long`, and `short`.
@param[in] val an integer to create a JSON number from
@complexity Constant.
- @liveexample{The example below shows the construction of several JSON
- integer number values from compatible
+ @liveexample{The example below shows the construction of several integer
+ number values from compatible
types.,basic_json__CompatibleIntegerNumberType}
@sa @ref basic_json(const number_integer_t) -- create a number value
@@ -1234,7 +1338,9 @@ class basic_json
template<typename CompatibleNumberIntegerType, typename
std::enable_if<
std::is_constructible<number_integer_t, CompatibleNumberIntegerType>::value and
- std::numeric_limits<CompatibleNumberIntegerType>::is_integer, CompatibleNumberIntegerType>::type
+ std::numeric_limits<CompatibleNumberIntegerType>::is_integer and
+ std::numeric_limits<CompatibleNumberIntegerType>::is_signed,
+ CompatibleNumberIntegerType>::type
= 0>
basic_json(const CompatibleNumberIntegerType val) noexcept
: m_type(value_t::number_integer),
@@ -1242,16 +1348,75 @@ class basic_json
{}
/*!
+ @brief create an unsigned integer number (explicit)
+
+ Create an unsigned integer number JSON value with a given content.
+
+ @tparam T helper type to compare number_unsigned_t and unsigned int
+ (not visible in) the interface.
+
+ @param[in] val an integer to create a JSON number from
+
+ @complexity Constant.
+
+ @sa @ref basic_json(const CompatibleNumberUnsignedType) -- create a number
+ value (unsigned integer) from a compatible number type
+
+ @since version 2.0.0
+ */
+ template<typename T,
+ typename std::enable_if<
+ not (std::is_same<T, int>::value)
+ and std::is_same<T, number_unsigned_t>::value
+ , int>::type
+ = 0>
+ basic_json(const number_unsigned_t val) noexcept
+ : m_type(value_t::number_unsigned), m_value(val)
+ {}
+
+ /*!
+ @brief create an unsigned number (implicit)
+
+ Create an unsigned number JSON value with a given content. This
+ constructor allows any type @a CompatibleNumberUnsignedType that can be
+ used to construct values of type @ref number_unsigned_t.
+
+ @tparam CompatibleNumberUnsignedType An integer type which is compatible
+ to @ref number_unsigned_t. Examples may include the types `unsigned int`,
+ `uint32_t`, or `unsigned short`.
+
+ @param[in] val an unsigned integer to create a JSON number from
+
+ @complexity Constant.
+
+ @sa @ref basic_json(const number_unsigned_t) -- create a number value
+ (unsigned)
+
+ @since version 2.0.0
+ */
+ template <typename CompatibleNumberUnsignedType, typename
+ std::enable_if <
+ std::is_constructible<number_unsigned_t, CompatibleNumberUnsignedType>::value and
+ std::numeric_limits<CompatibleNumberUnsignedType>::is_integer and
+ not std::numeric_limits<CompatibleNumberUnsignedType>::is_signed,
+ CompatibleNumberUnsignedType>::type
+ = 0>
+ basic_json(const CompatibleNumberUnsignedType val) noexcept
+ : m_type(value_t::number_unsigned),
+ m_value(static_cast<number_unsigned_t>(val))
+ {}
+
+ /*!
@brief create a floating-point number (explicit)
Create a floating-point number JSON value with a given content.
@param[in] val a floating-point value to create a JSON number from
- @note RFC 7159 <http://www.rfc-editor.org/rfc/rfc7159.txt>, section 6
+ @note [RFC 7159](http://www.rfc-editor.org/rfc/rfc7159.txt), section 6
disallows NaN values:
- > Numeric values that cannot be represented in the grammar below (such
- > as Infinity and NaN) are not permitted.
+ > Numeric values that cannot be represented in the grammar below (such as
+ > Infinity and NaN) are not permitted.
In case the parameter @a val is not a number, a JSON null value is
created instead.
@@ -1265,7 +1430,7 @@ class basic_json
@since version 1.0.0
*/
- basic_json(const number_float_t val)
+ basic_json(const number_float_t val) noexcept
: m_type(value_t::number_float), m_value(val)
{
// replace infinity and NAN by null
@@ -1280,24 +1445,25 @@ class basic_json
@brief create an floating-point number (implicit)
Create an floating-point number JSON value with a given content. This
- constructor allows any type that can be used to construct values of type
- @ref number_float_t. Examples may include the types `float`.
+ constructor allows any type @a CompatibleNumberFloatType that can be used
+ to construct values of type @ref number_float_t.
- @tparam CompatibleNumberFloatType a floating-point type which is compatible
- to @ref number_float_t.
+ @tparam CompatibleNumberFloatType A floating-point type which is
+ compatible to @ref number_float_t. Examples may include the types `float`
+ or `double`.
@param[in] val a floating-point to create a JSON number from
- @note RFC 7159 <http://www.rfc-editor.org/rfc/rfc7159.txt>, section 6
+ @note [RFC 7159](http://www.rfc-editor.org/rfc/rfc7159.txt), section 6
disallows NaN values:
- > Numeric values that cannot be represented in the grammar below (such
- > as Infinity and NaN) are not permitted.
+ > Numeric values that cannot be represented in the grammar below (such as
+ > Infinity and NaN) are not permitted.
In case the parameter @a val is not a number, a JSON null value is
created instead.
@complexity Constant.
- @liveexample{The example below shows the construction of several JSON
+ @liveexample{The example below shows the construction of several
floating-point number values from compatible
types.,basic_json__CompatibleNumberFloatType}
@@ -1362,20 +1528,20 @@ class basic_json
used by the functions @ref array(std::initializer_list<basic_json>) and
@ref object(std::initializer_list<basic_json>).
- @param[in] manual_type internal parameter; when @a type_deduction is set to
- `false`, the created JSON value will use the provided type (only @ref
+ @param[in] manual_type internal parameter; when @a type_deduction is set
+ to `false`, the created JSON value will use the provided type (only @ref
value_t::array and @ref value_t::object are valid); when @a type_deduction
is set to `true`, this parameter has no effect
- @throw std::domain_error if @a type_deduction is `false`, @a manual_type is
- `value_t::object`, but @a init contains an element which is not a pair
+ @throw std::domain_error if @a type_deduction is `false`, @a manual_type
+ is `value_t::object`, but @a init contains an element which is not a pair
whose first element is a string; example: `"cannot create object from
initializer list"`
@complexity Linear in the size of the initializer list @a init.
@liveexample{The example below shows how JSON values are created from
- initializer lists,basic_json__list_init_t}
+ initializer lists.,basic_json__list_init_t}
@sa @ref array(std::initializer_list<basic_json>) -- create a JSON array
value from an initializer list
@@ -1431,14 +1597,14 @@ class basic_json
for (auto& element : init)
{
- m_value.object->emplace(std::move(*(element[0].m_value.string)), std::move(element[1]));
+ 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<array_t>(std::move(init));
+ m_value.array = create<array_t>(init);
}
}
@@ -1449,8 +1615,8 @@ class basic_json
list of values `a, b, c`, creates the JSON value `[a, b, c]`. If the
initializer list is empty, the empty array `[]` is created.
- @note This function is only needed to express two edge cases that cannot be
- realized with the initializer list constructor (@ref
+ @note This function is only needed to express two edge cases that cannot
+ be realized with the initializer list constructor (@ref
basic_json(std::initializer_list<basic_json>, bool, value_t)). These cases
are:
1. creating an array whose elements are all pairs whose first element is a
@@ -1466,7 +1632,7 @@ class basic_json
@complexity Linear in the size of @a init.
- @liveexample{The following code shows an example for the @ref array
+ @liveexample{The following code shows an example for the `array`
function.,array}
@sa @ref basic_json(std::initializer_list<basic_json>, bool, value_t) --
@@ -1493,8 +1659,8 @@ class basic_json
related function @ref array(std::initializer_list<basic_json>), there are
no cases which can only be expressed by this function. That is, any
initializer list @a init can also be passed to the initializer list
- constructor
- @ref basic_json(std::initializer_list<basic_json>, bool, value_t).
+ constructor @ref basic_json(std::initializer_list<basic_json>, bool,
+ value_t).
@param[in] init initializer list to create an object from (optional)
@@ -1506,7 +1672,7 @@ class basic_json
@complexity Linear in the size of @a init.
- @liveexample{The following code shows an example for the @ref object
+ @liveexample{The following code shows an example for the `object`
function.,object}
@sa @ref basic_json(std::initializer_list<basic_json>, bool, value_t) --
@@ -1525,8 +1691,8 @@ class basic_json
/*!
@brief construct an array with count copies of given value
- Constructs a JSON array value by creating @a cnt copies of a passed
- value. In case @a cnt is `0`, an empty array is created. As postcondition,
+ Constructs a JSON array value by creating @a cnt copies of a passed value.
+ In case @a cnt is `0`, an empty array is created. As postcondition,
`std::distance(begin(),end()) == cnt` holds.
@param[in] cnt the number of JSON copies of @a val to create
@@ -1554,8 +1720,8 @@ class basic_json
- In case of primitive types (number, boolean, or string), @a first must
be `begin()` and @a last must be `end()`. In this case, the value is
copied. Otherwise, std::out_of_range is thrown.
- - In case of structured types (array, object), the constructor behaves
- as similar versions for `std::vector`.
+ - In case of structured types (array, object), the constructor behaves as
+ similar versions for `std::vector`.
- In case of a null type, std::domain_error is thrown.
@tparam InputIT an input iterator type (@ref iterator or @ref
@@ -1570,8 +1736,8 @@ class basic_json
boolean, or string) where an out of range error can be detected easily;
example: `"iterators out of range"`
@throw std::bad_alloc if allocation for object, array, or string fails
- @throw std::domain_error if called with a null value; example: `"cannot use
- construct with iterators from null"`
+ @throw std::domain_error if called with a null value; example: `"cannot
+ use construct with iterators from null"`
@complexity Linear in distance between @a first and @a last.
@@ -1600,6 +1766,7 @@ class basic_json
case value_t::boolean:
case value_t::number_float:
case value_t::number_integer:
+ case value_t::number_unsigned:
case value_t::string:
{
if (not first.m_it.primitive_iterator.is_begin() or not last.m_it.primitive_iterator.is_end())
@@ -1624,6 +1791,13 @@ class basic_json
break;
}
+ case value_t::number_unsigned:
+ {
+ assert(first.m_object != nullptr);
+ m_value.number_unsigned = first.m_object->m_value.number_unsigned;
+ break;
+ }
+
case value_t::number_float:
{
assert(first.m_object != nullptr);
@@ -1665,6 +1839,31 @@ class basic_json
}
}
+ /*!
+ @brief construct a JSON value given an input stream
+
+ @param[in,out] i stream to read a serialized JSON value from
+ @param[in] cb a parser callback function of type @ref parser_callback_t
+ which is used to control the deserialization by filtering unwanted values
+ (optional)
+
+ @complexity Linear in the length of the input. The parser is a predictive
+ LL(1) parser. The complexity can be higher if the parser callback function
+ @a cb has a super-linear complexity.
+
+ @note A UTF-8 byte order mark is silently ignored.
+
+ @liveexample{The example below demonstrates constructing a JSON value from
+ a `std::stringstream` with and without callback
+ function.,basic_json__istream}
+
+ @since version 2.0.0
+ */
+ explicit basic_json(std::istream& i, parser_callback_t cb = nullptr)
+ {
+ *this = parser(i, cb).parse();
+ }
+
///////////////////////////////////////
// other constructors and destructor //
///////////////////////////////////////
@@ -1678,7 +1877,9 @@ class basic_json
@complexity Linear in the size of @a other.
- @requirement This function satisfies the Container requirements:
+ @requirement This function helps `basic_json` satisfying the
+ [Container](http://en.cppreference.com/w/cpp/concept/Container)
+ requirements:
- The complexity is linear.
- As postcondition, it holds: `other == basic_json(other)`.
@@ -1727,6 +1928,12 @@ class basic_json
break;
}
+ case value_t::number_unsigned:
+ {
+ m_value = other.m_value.number_unsigned;
+ break;
+ }
+
case value_t::number_float:
{
m_value = other.m_value.number_float;
@@ -1771,14 +1978,16 @@ class basic_json
@brief copy assignment
Copy assignment operator. Copies a JSON value via the "copy and swap"
- strategy: It is expressed in terms of the copy constructor, destructor, and
- the swap() member function.
+ strategy: It is expressed in terms of the copy constructor, destructor,
+ and the swap() member function.
@param[in] other value to copy from
@complexity Linear.
- @requirement This function satisfies the Container requirements:
+ @requirement This function helps `basic_json` satisfying the
+ [Container](http://en.cppreference.com/w/cpp/concept/Container)
+ requirements:
- The complexity is linear.
@liveexample{The code below shows and example for the copy assignment. It
@@ -1808,7 +2017,9 @@ class basic_json
@complexity Linear.
- @requirement This function satisfies the Container requirements:
+ @requirement This function helps `basic_json` satisfying the
+ [Container](http://en.cppreference.com/w/cpp/concept/Container)
+ requirements:
- The complexity is linear.
- All stored elements are destroyed and all memory is freed.
@@ -1868,8 +2079,8 @@ class basic_json
parameter.
@param[in] indent if indent is nonnegative, then array elements and object
- members will be pretty-printed with that indent level. An indent level of 0
- will only insert newlines. -1 (the default) selects the most compact
+ members will be pretty-printed with that indent level. An indent level of
+ 0 will only insert newlines. -1 (the default) selects the most compact
representation
@return string containing the serialization of the JSON value
@@ -1909,12 +2120,15 @@ class basic_json
@complexity Constant.
- @liveexample{The following code exemplifies @ref type() for all JSON
+ @exceptionsafety No-throw guarantee: this member function never throws
+ exceptions.
+
+ @liveexample{The following code exemplifies `type()` for all JSON
types.,type}
@since version 1.0.0
*/
- value_t type() const noexcept
+ constexpr value_t type() const noexcept
{
return m_type;
}
@@ -1930,12 +2144,21 @@ class basic_json
@complexity Constant.
- @liveexample{The following code exemplifies @ref is_primitive for all JSON
+ @exceptionsafety No-throw guarantee: this member function never throws
+ exceptions.
+
+ @liveexample{The following code exemplifies `is_primitive()` for all JSON
types.,is_primitive}
+ @sa @ref is_structured() -- returns whether JSON value is structured
+ @sa @ref is_null() -- returns whether JSON value is `null`
+ @sa @ref is_string() -- returns whether JSON value is a string
+ @sa @ref is_boolean() -- returns whether JSON value is a boolean
+ @sa @ref is_number() -- returns whether JSON value is a number
+
@since version 1.0.0
*/
- bool is_primitive() const noexcept
+ constexpr bool is_primitive() const noexcept
{
return is_null() or is_string() or is_boolean() or is_number();
}
@@ -1950,12 +2173,19 @@ class basic_json
@complexity Constant.
- @liveexample{The following code exemplifies @ref is_structured for all JSON
+ @exceptionsafety No-throw guarantee: this member function never throws
+ exceptions.
+
+ @liveexample{The following code exemplifies `is_structured()` for all JSON
types.,is_structured}
+ @sa @ref is_primitive() -- returns whether value is primitive
+ @sa @ref is_array() -- returns whether value is an array
+ @sa @ref is_object() -- returns whether value is an object
+
@since version 1.0.0
*/
- bool is_structured() const noexcept
+ constexpr bool is_structured() const noexcept
{
return is_array() or is_object();
}
@@ -1969,12 +2199,15 @@ class basic_json
@complexity Constant.
- @liveexample{The following code exemplifies @ref is_null for all JSON
+ @exceptionsafety No-throw guarantee: this member function never throws
+ exceptions.
+
+ @liveexample{The following code exemplifies `is_null()` for all JSON
types.,is_null}
@since version 1.0.0
*/
- bool is_null() const noexcept
+ constexpr bool is_null() const noexcept
{
return m_type == value_t::null;
}
@@ -1988,12 +2221,15 @@ class basic_json
@complexity Constant.
- @liveexample{The following code exemplifies @ref is_boolean for all JSON
+ @exceptionsafety No-throw guarantee: this member function never throws
+ exceptions.
+
+ @liveexample{The following code exemplifies `is_boolean()` for all JSON
types.,is_boolean}
@since version 1.0.0
*/
- bool is_boolean() const noexcept
+ constexpr bool is_boolean() const noexcept
{
return m_type == value_t::boolean;
}
@@ -2004,20 +2240,26 @@ class basic_json
This function returns true iff the JSON value is a number. This includes
both integer and floating-point values.
- @return `true` if type is number (regardless whether integer or
- floating-type), `false` otherwise.
+ @return `true` if type is number (regardless whether integer, unsigned
+ integer or floating-type), `false` otherwise.
@complexity Constant.
- @liveexample{The following code exemplifies @ref is_number for all JSON
+ @exceptionsafety No-throw guarantee: this member function never throws
+ exceptions.
+
+ @liveexample{The following code exemplifies `is_number()` for all JSON
types.,is_number}
- @sa @ref is_number_integer() -- check if value is an integer number
+ @sa @ref is_number_integer() -- check if value is an integer or unsigned
+ integer number
+ @sa @ref is_number_unsigned() -- check if value is an unsigned integer
+ number
@sa @ref is_number_float() -- check if value is a floating-point number
@since version 1.0.0
*/
- bool is_number() const noexcept
+ constexpr bool is_number() const noexcept
{
return is_number_integer() or is_number_float();
}
@@ -2025,45 +2267,84 @@ class basic_json
/*!
@brief return whether value is an integer number
- This function returns true iff the JSON value is an integer number. This
- excludes floating-point values.
+ This function returns true iff the JSON value is an integer or unsigned
+ integer number. This excludes floating-point values.
- @return `true` if type is an integer number, `false` otherwise.
+ @return `true` if type is an integer or unsigned integer number, `false`
+ otherwise.
@complexity Constant.
- @liveexample{The following code exemplifies @ref is_number_integer for all
+ @exceptionsafety No-throw guarantee: this member function never throws
+ exceptions.
+
+ @liveexample{The following code exemplifies `is_number_integer()` for all
JSON types.,is_number_integer}
@sa @ref is_number() -- check if value is a number
+ @sa @ref is_number_unsigned() -- check if value is an unsigned integer
+ number
@sa @ref is_number_float() -- check if value is a floating-point number
@since version 1.0.0
*/
- bool is_number_integer() const noexcept
+ 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
+ number. This excludes floating-point and (signed) integer values.
+
+ @return `true` if type is an unsigned integer number, `false` otherwise.
+
+ @complexity Constant.
+
+ @exceptionsafety No-throw guarantee: this member function never throws
+ exceptions.
+
+ @liveexample{The following code exemplifies `is_number_unsigned()` for all
+ JSON types.,is_number_unsigned}
+
+ @sa @ref is_number() -- check if value is a number
+ @sa @ref is_number_integer() -- check if value is an integer or unsigned
+ integer number
+ @sa @ref is_number_float() -- check if value is a floating-point number
+
+ @since version 2.0.0
+ */
+ constexpr bool is_number_unsigned() const noexcept
{
- return m_type == value_t::number_integer;
+ 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.
- This excludes integer values.
+ This excludes integer and unsigned integer values.
@return `true` if type is a floating-point number, `false` otherwise.
@complexity Constant.
- @liveexample{The following code exemplifies @ref is_number_float for all
+ @exceptionsafety No-throw guarantee: this member function never throws
+ exceptions.
+
+ @liveexample{The following code exemplifies `is_number_float()` for all
JSON types.,is_number_float}
@sa @ref is_number() -- check if value is number
@sa @ref is_number_integer() -- check if value is an integer number
+ @sa @ref is_number_unsigned() -- check if value is an unsigned integer
+ number
@since version 1.0.0
*/
- bool is_number_float() const noexcept
+ constexpr bool is_number_float() const noexcept
{
return m_type == value_t::number_float;
}
@@ -2077,12 +2358,15 @@ class basic_json
@complexity Constant.
- @liveexample{The following code exemplifies @ref is_object for all JSON
+ @exceptionsafety No-throw guarantee: this member function never throws
+ exceptions.
+
+ @liveexample{The following code exemplifies `is_object()` for all JSON
types.,is_object}
@since version 1.0.0
*/
- bool is_object() const noexcept
+ constexpr bool is_object() const noexcept
{
return m_type == value_t::object;
}
@@ -2096,12 +2380,15 @@ class basic_json
@complexity Constant.
- @liveexample{The following code exemplifies @ref is_array for all JSON
+ @exceptionsafety No-throw guarantee: this member function never throws
+ exceptions.
+
+ @liveexample{The following code exemplifies `is_array()` for all JSON
types.,is_array}
@since version 1.0.0
*/
- bool is_array() const noexcept
+ constexpr bool is_array() const noexcept
{
return m_type == value_t::array;
}
@@ -2115,12 +2402,15 @@ class basic_json
@complexity Constant.
- @liveexample{The following code exemplifies @ref is_string for all JSON
+ @exceptionsafety No-throw guarantee: this member function never throws
+ exceptions.
+
+ @liveexample{The following code exemplifies `is_string()` for all JSON
types.,is_string}
@since version 1.0.0
*/
- bool is_string() const noexcept
+ constexpr bool is_string() const noexcept
{
return m_type == value_t::string;
}
@@ -2139,12 +2429,15 @@ class basic_json
@complexity Constant.
- @liveexample{The following code exemplifies @ref is_discarded for all JSON
+ @exceptionsafety No-throw guarantee: this member function never throws
+ exceptions.
+
+ @liveexample{The following code exemplifies `is_discarded()` for all JSON
types.,is_discarded}
@since version 1.0.0
*/
- bool is_discarded() const noexcept
+ constexpr bool is_discarded() const noexcept
{
return m_type == value_t::discarded;
}
@@ -2159,12 +2452,15 @@ class basic_json
@complexity Constant.
- @liveexample{The following code exemplifies the value_t operator for all
- JSON types.,operator__value_t}
+ @exceptionsafety No-throw guarantee: this member function never throws
+ exceptions.
+
+ @liveexample{The following code exemplifies the @ref value_t operator for
+ all JSON types.,operator__value_t}
@since version 1.0.0
*/
- operator value_t() const noexcept
+ constexpr operator value_t() const noexcept
{
return m_type;
}
@@ -2328,6 +2624,11 @@ class basic_json
return static_cast<T>(m_value.number_integer);
}
+ case value_t::number_unsigned:
+ {
+ return static_cast<T>(m_value.number_unsigned);
+ }
+
case value_t::number_float:
{
return static_cast<T>(m_value.number_float);
@@ -2341,16 +2642,11 @@ class basic_json
}
/// get a boolean (explicit)
- boolean_t get_impl(boolean_t*) const
+ constexpr boolean_t get_impl(boolean_t*) const
{
- if (is_boolean())
- {
- return m_value.boolean;
- }
- else
- {
- throw std::domain_error("type must be boolean, but is " + type_name());
- }
+ 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)
@@ -2360,7 +2656,7 @@ class basic_json
}
/// get a pointer to the value (object)
- const object_t* get_impl_ptr(const object_t*) const noexcept
+ constexpr const object_t* get_impl_ptr(const object_t*) const noexcept
{
return is_object() ? m_value.object : nullptr;
}
@@ -2372,7 +2668,7 @@ class basic_json
}
/// get a pointer to the value (array)
- const array_t* get_impl_ptr(const array_t*) const noexcept
+ constexpr const array_t* get_impl_ptr(const array_t*) const noexcept
{
return is_array() ? m_value.array : nullptr;
}
@@ -2384,7 +2680,7 @@ class basic_json
}
/// get a pointer to the value (string)
- const string_t* get_impl_ptr(const string_t*) const noexcept
+ constexpr const string_t* get_impl_ptr(const string_t*) const noexcept
{
return is_string() ? m_value.string : nullptr;
}
@@ -2396,7 +2692,7 @@ class basic_json
}
/// get a pointer to the value (boolean)
- const boolean_t* get_impl_ptr(const boolean_t*) const noexcept
+ constexpr const boolean_t* get_impl_ptr(const boolean_t*) const noexcept
{
return is_boolean() ? &m_value.boolean : nullptr;
}
@@ -2408,11 +2704,23 @@ class basic_json
}
/// get a pointer to the value (integer number)
- const number_integer_t* get_impl_ptr(const number_integer_t*) const noexcept
+ 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)
+ 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
{
@@ -2420,7 +2728,7 @@ class basic_json
}
/// get a pointer to the value (floating-point number)
- const number_float_t* get_impl_ptr(const number_float_t*) const noexcept
+ constexpr const number_float_t* get_impl_ptr(const number_float_t*) const noexcept
{
return is_number_float() ? &m_value.number_float : nullptr;
}
@@ -2510,8 +2818,8 @@ class basic_json
@warning The pointer becomes invalid if the underlying JSON object changes.
@tparam PointerType pointer type; must be a pointer to @ref array_t, @ref
- object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, or @ref
- number_float_t.
+ object_t, @ref string_t, @ref boolean_t, @ref number_integer_t,
+ @ref number_unsigned_t, or @ref number_float_t.
@return pointer to the internally stored JSON value if the requested
pointer type @a PointerType fits to the JSON value; `nullptr` otherwise
@@ -2545,7 +2853,7 @@ class basic_json
std::enable_if<
std::is_pointer<PointerType>::value
, int>::type = 0>
- const PointerType get() const noexcept
+ constexpr const PointerType get() const noexcept
{
// delegate the call to get_ptr
return get_ptr<PointerType>();
@@ -2561,8 +2869,8 @@ class basic_json
state.
@tparam PointerType pointer type; must be a pointer to @ref array_t, @ref
- object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, or @ref
- number_float_t.
+ object_t, @ref string_t, @ref boolean_t, @ref number_integer_t,
+ @ref number_unsigned_t, or @ref number_float_t.
@return pointer to the internally stored JSON value if the requested
pointer type @a PointerType fits to the JSON value; `nullptr` otherwise
@@ -2595,7 +2903,7 @@ class basic_json
std::is_pointer<PointerType>::value
and std::is_const<typename std::remove_pointer<PointerType>::type>::value
, int>::type = 0>
- const PointerType get_ptr() const noexcept
+ constexpr const PointerType get_ptr() const noexcept
{
// delegate the call to get_impl_ptr<>() const
return get_impl_ptr(static_cast<const PointerType>(nullptr));
@@ -2604,8 +2912,8 @@ class basic_json
/*!
@brief get a reference value (implicit)
- Implict reference access to the internally stored JSON value. No copies are
- made.
+ Implict reference access to the internally stored JSON value. No copies
+ are made.
@warning Writing data to the referee of the result yields an undefined
state.
@@ -2655,8 +2963,8 @@ class basic_json
/*!
@brief get a value (implicit)
- Implicit type conversion between the JSON value and a compatible value. The
- call is realized by calling @ref get() const.
+ Implicit type conversion between the JSON value and a compatible value.
+ The call is realized by calling @ref get() const.
@tparam ValueType non-pointer type compatible to the JSON value, for
instance `int` for JSON integer numbers, `bool` for JSON booleans, or
@@ -2722,7 +3030,7 @@ class basic_json
@complexity Constant.
@liveexample{The example below shows how array elements can be read and
- written using at.,at__size_type}
+ written using `at()`.,at__size_type}
@since version 1.0.0
*/
@@ -2751,8 +3059,8 @@ class basic_json
/*!
@brief access specified array element with bounds checking
- Returns a const reference to the element at specified location @a idx, with
- bounds checking.
+ Returns a const reference to the element at specified location @a idx,
+ with bounds checking.
@param[in] idx index of the element to access
@@ -2766,7 +3074,7 @@ class basic_json
@complexity Constant.
@liveexample{The example below shows how array elements can be read using
- at.,at__size_type_const}
+ `at()`.,at__size_type_const}
@since version 1.0.0
*/
@@ -2810,7 +3118,7 @@ class basic_json
@complexity Logarithmic in the size of the container.
@liveexample{The example below shows how object elements can be read and
- written using at.,at__object_t_key_type}
+ written using `at()`.,at__object_t_key_type}
@sa @ref operator[](const typename object_t::key_type&) for unchecked
access by reference
@@ -2843,8 +3151,8 @@ class basic_json
/*!
@brief access specified object element with bounds checking
- Returns a const reference to the element at with specified key @a key, with
- bounds checking.
+ Returns a const reference to the element at with specified key @a key,
+ with bounds checking.
@param[in] key key of the element to access
@@ -2858,7 +3166,7 @@ class basic_json
@complexity Logarithmic in the size of the container.
@liveexample{The example below shows how object elements can be read using
- at.,at__object_t_key_type_const}
+ `at()`.,at__object_t_key_type_const}
@sa @ref operator[](const typename object_t::key_type&) for unchecked
access by reference
@@ -2901,30 +3209,31 @@ class basic_json
@return reference to the element at index @a idx
- @throw std::domain_error if JSON is not an array or null; example: `"cannot
- use operator[] with null"`
+ @throw std::domain_error if JSON is not an array or null; example:
+ `"cannot use operator[] with string"`
@complexity Constant if @a idx is in the range of the array. Otherwise
linear in `idx - size()`.
@liveexample{The example below shows how array elements can be read and
- written using [] operator. Note the addition of `null`
+ written using `[]` operator. Note the addition of `null`
values.,operatorarray__size_type}
@since version 1.0.0
*/
reference operator[](size_type idx)
{
- // implicitly convert null to object
+ // implicitly convert null value to an empty array
if (is_null())
{
m_type = value_t::array;
m_value.array = create<array_t>();
}
- // [] only works for arrays
+ // operator[] only works for arrays
if (is_array())
{
+ // fill up array with null values until given idx is reached
assert(m_value.array != nullptr);
for (size_t i = m_value.array->size(); i <= idx; ++i)
{
@@ -2954,13 +3263,13 @@ class basic_json
@complexity Constant.
@liveexample{The example below shows how array elements can be read using
- the [] operator.,operatorarray__size_type_const}
+ the `[]` operator.,operatorarray__size_type_const}
@since version 1.0.0
*/
const_reference operator[](size_type idx) const
{
- // at only works for arrays
+ // const operator[] only works for arrays
if (is_array())
{
assert(m_value.array != nullptr);
@@ -2986,12 +3295,12 @@ class basic_json
@return reference to the element at key @a key
@throw std::domain_error if JSON is not an object or null; example:
- `"cannot use operator[] with null"`
+ `"cannot use operator[] with string"`
@complexity Logarithmic in the size of the container.
@liveexample{The example below shows how object elements can be read and
- written using the [] operator.,operatorarray__key_type}
+ written using the `[]` operator.,operatorarray__key_type}
@sa @ref at(const typename object_t::key_type&) for access by reference
with range checking
@@ -3001,14 +3310,14 @@ class basic_json
*/
reference operator[](const typename object_t::key_type& key)
{
- // implicitly convert null to object
+ // implicitly convert null value to an empty object
if (is_null())
{
m_type = value_t::object;
m_value.object = create<object_t>();
}
- // [] only works for objects
+ // operator[] only works for objects
if (is_object())
{
assert(m_value.object != nullptr);
@@ -3039,7 +3348,7 @@ class basic_json
@complexity Logarithmic in the size of the container.
@liveexample{The example below shows how object elements can be read using
- the [] operator.,operatorarray__key_type_const}
+ the `[]` operator.,operatorarray__key_type_const}
@sa @ref at(const typename object_t::key_type&) for access by reference
with range checking
@@ -3049,7 +3358,7 @@ class basic_json
*/
const_reference operator[](const typename object_t::key_type& key) const
{
- // [] only works for objects
+ // const operator[] only works for objects
if (is_object())
{
assert(m_value.object != nullptr);
@@ -3076,12 +3385,12 @@ class basic_json
@return reference to the element at key @a key
@throw std::domain_error if JSON is not an object or null; example:
- `"cannot use operator[] with null"`
+ `"cannot use operator[] with string"`
@complexity Logarithmic in the size of the container.
@liveexample{The example below shows how object elements can be read and
- written using the [] operator.,operatorarray__key_type}
+ written using the `[]` operator.,operatorarray__key_type}
@sa @ref at(const typename object_t::key_type&) for access by reference
with range checking
@@ -3116,7 +3425,7 @@ class basic_json
@complexity Logarithmic in the size of the container.
@liveexample{The example below shows how object elements can be read using
- the [] operator.,operatorarray__key_type_const}
+ the `[]` operator.,operatorarray__key_type_const}
@sa @ref at(const typename object_t::key_type&) for access by reference
with range checking
@@ -3144,12 +3453,12 @@ class basic_json
@return reference to the element at key @a key
@throw std::domain_error if JSON is not an object or null; example:
- `"cannot use operator[] with null"`
+ `"cannot use operator[] with string"`
@complexity Logarithmic in the size of the container.
@liveexample{The example below shows how object elements can be read and
- written using the [] operator.,operatorarray__key_type}
+ written using the `[]` operator.,operatorarray__key_type}
@sa @ref at(const typename object_t::key_type&) for access by reference
with range checking
@@ -3198,7 +3507,7 @@ class basic_json
@complexity Logarithmic in the size of the container.
@liveexample{The example below shows how object elements can be read using
- the [] operator.,operatorarray__key_type_const}
+ the `[]` operator.,operatorarray__key_type_const}
@sa @ref at(const typename object_t::key_type&) for access by reference
with range checking
@@ -3317,11 +3626,15 @@ class basic_json
@complexity Constant.
- @note Calling `front` on an empty container is undefined.
+ @pre The JSON value must not be `null` (would throw `std::out_of_range`)
+ or an empty array or object (undefined behavior, guarded by assertions).
+ @post The JSON value remains unchanged.
+
+ @throw std::out_of_range when called on `null` value
- @throw std::out_of_range when called on null value
+ @liveexample{The following code shows an example for `front()`.,front}
- @liveexample{The following code shows an example for @ref front.,front}
+ @sa @ref back() -- access the last element
@since version 1.0.0
*/
@@ -3342,8 +3655,12 @@ class basic_json
@brief access the last element
Returns a reference to the last element in the container. For a JSON
- container `c`, the expression `c.back()` is equivalent to `{ auto tmp =
- c.end(); --tmp; return *tmp; }`.
+ container `c`, the expression `c.back()` is equivalent to
+ @code {.cpp}
+ auto tmp = c.end();
+ --tmp;
+ return *tmp;
+ @endcode
@return In case of a structured type (array or object), a reference to the
last element is returned. In cast of number, string, or boolean values, a
@@ -3351,11 +3668,15 @@ class basic_json
@complexity Constant.
- @note Calling `back` on an empty container is undefined.
+ @pre The JSON value must not be `null` (would throw `std::out_of_range`)
+ or an empty array or object (undefined behavior, guarded by assertions).
+ @post The JSON value remains unchanged.
+
+ @throw std::out_of_range when called on `null` value.
- @throw std::out_of_range when called on null value.
+ @liveexample{The following code shows an example for `back()`.,back}
- @liveexample{The following code shows an example for @ref back.,back}
+ @sa @ref front() -- access the first element
@since version 1.0.0
*/
@@ -3379,28 +3700,29 @@ class basic_json
/*!
@brief remove element given an iterator
- Removes the element specified by iterator @a pos. Invalidates iterators and
- references at or after the point of the erase, including the end()
- iterator. The iterator @a pos must be valid and dereferenceable. Thus the
- end() iterator (which is valid, but is not dereferenceable) cannot be used
- as a value for @a pos.
+ Removes the element specified by iterator @a pos. The iterator @a pos must
+ be valid and dereferenceable. Thus the `end()` iterator (which is valid,
+ but is not dereferenceable) cannot be used as a value for @a pos.
- If called on a primitive type other than null, the resulting JSON value
+ If called on a primitive type other than `null`, the resulting JSON value
will be `null`.
@param[in] pos iterator to the element to remove
- @return Iterator following the last removed element. If the iterator @a pos
- refers to the last element, the end() iterator is returned.
+ @return Iterator following the last removed element. If the iterator @a
+ pos refers to the last element, the `end()` iterator is returned.
@tparam InteratorType an @ref iterator or @ref const_iterator
- @throw std::domain_error if called on a `null` value; example: `"cannot use
- erase() with null"`
+ @post Invalidates iterators and references at or after the point of the
+ erase, including the `end()` iterator.
+
+ @throw std::domain_error if called on a `null` value; example: `"cannot
+ use erase() with null"`
@throw std::domain_error if called on an iterator which does not belong to
the current JSON value; example: `"iterator does not fit current value"`
@throw std::out_of_range if called on a primitive type with invalid
- iterator (i.e., any iterator which is not end()); example: `"iterator out
- of range"`
+ iterator (i.e., any iterator which is not `begin()`); example: `"iterator
+ out of range"`
@complexity The complexity depends on the type:
- objects: amortized constant
@@ -3408,15 +3730,15 @@ class basic_json
- strings: linear in the length of the string
- other types: constant
- @liveexample{The example shows the result of erase for different JSON
+ @liveexample{The example shows the result of `erase()` for different JSON
types.,erase__IteratorType}
- @sa @ref erase(InteratorType, InteratorType) -- removes the elements in the
- given range
+ @sa @ref erase(InteratorType, InteratorType) -- removes the elements in
+ the given range
@sa @ref erase(const typename object_t::key_type&) -- removes the element
from an object at the given key
- @sa @ref erase(const size_type) -- removes the element from an array at the
- given index
+ @sa @ref erase(const size_type) -- removes the element from an array at
+ the given index
@since version 1.0.0
*/
@@ -3441,6 +3763,7 @@ class basic_json
case value_t::boolean:
case value_t::number_float:
case value_t::number_integer:
+ case value_t::number_unsigned:
case value_t::string:
{
if (not pos.m_it.primitive_iterator.is_begin())
@@ -3484,23 +3807,25 @@ class basic_json
/*!
@brief remove elements given an iterator range
- Removes the element specified by the range `[first; last)`. Invalidates
- iterators and references at or after the point of the erase, including the
- end() iterator. The iterator @a first does not need to be dereferenceable
- if `first == last`: erasing an empty range is a no-op.
+ Removes the element specified by the range `[first; last)`. The iterator
+ @a first does not need to be dereferenceable if `first == last`: erasing
+ an empty range is a no-op.
- If called on a primitive type other than null, the resulting JSON value
+ If called on a primitive type other than `null`, the resulting JSON value
will be `null`.
@param[in] first iterator to the beginning of the range to remove
@param[in] last iterator past the end of the range to remove
@return Iterator following the last removed element. If the iterator @a
- second refers to the last element, the end() iterator is returned.
+ second refers to the last element, the `end()` iterator is returned.
@tparam InteratorType an @ref iterator or @ref const_iterator
- @throw std::domain_error if called on a `null` value; example: `"cannot use
- erase() with null"`
+ @post Invalidates iterators and references at or after the point of the
+ erase, including the `end()` iterator.
+
+ @throw std::domain_error if called on a `null` value; example: `"cannot
+ use erase() with null"`
@throw std::domain_error if called on iterators which does not belong to
the current JSON value; example: `"iterators do not fit current value"`
@throw std::out_of_range if called on a primitive type with invalid
@@ -3514,14 +3839,14 @@ class basic_json
- strings: linear in the length of the string
- other types: constant
- @liveexample{The example shows the result of erase for different JSON
+ @liveexample{The example shows the result of `erase()` for different JSON
types.,erase__IteratorType_IteratorType}
@sa @ref erase(InteratorType) -- removes the element at a given position
@sa @ref erase(const typename object_t::key_type&) -- removes the element
from an object at the given key
- @sa @ref erase(const size_type) -- removes the element from an array at the
- given index
+ @sa @ref erase(const size_type) -- removes the element from an array at
+ the given index
@since version 1.0.0
*/
@@ -3546,6 +3871,7 @@ class basic_json
case value_t::boolean:
case value_t::number_float:
case value_t::number_integer:
+ case value_t::number_unsigned:
case value_t::string:
{
if (not first.m_it.primitive_iterator.is_begin() or not last.m_it.primitive_iterator.is_end())
@@ -3595,22 +3921,25 @@ class basic_json
@param[in] key value of the elements to remove
- @return Number of elements removed. If ObjectType is the default `std::map`
- type, the return value will always be `0` (@a key was not found) or `1` (@a
- key was found).
+ @return Number of elements removed. If @a ObjectType is the default
+ `std::map` type, the return value will always be `0` (@a key was not
+ found) or `1` (@a key was found).
+
+ @post References and iterators to the erased elements are invalidated.
+ Other references and iterators are not affected.
@throw std::domain_error when called on a type other than JSON object;
example: `"cannot use erase() with null"`
@complexity `log(size()) + count(key)`
- @liveexample{The example shows the effect of erase.,erase__key_type}
+ @liveexample{The example shows the effect of `erase()`.,erase__key_type}
@sa @ref erase(InteratorType) -- removes the element at a given position
- @sa @ref erase(InteratorType, InteratorType) -- removes the elements in the
- given range
- @sa @ref erase(const size_type) -- removes the element from an array at the
- given index
+ @sa @ref erase(InteratorType, InteratorType) -- removes the elements in
+ the given range
+ @sa @ref erase(const size_type) -- removes the element from an array at
+ the given index
@since version 1.0.0
*/
@@ -3637,16 +3966,16 @@ class basic_json
@throw std::domain_error when called on a type other than JSON array;
example: `"cannot use erase() with null"`
- @throw std::out_of_range when `idx >= size()`; example: `"index out of
- range"`
+ @throw std::out_of_range when `idx >= size()`; example: `"array index 17
+ is out of range"`
@complexity Linear in distance between @a idx and the end of the container.
- @liveexample{The example shows the effect of erase.,erase__size_type}
+ @liveexample{The example shows the effect of `erase()`.,erase__size_type}
@sa @ref erase(InteratorType) -- removes the element at a given position
- @sa @ref erase(InteratorType, InteratorType) -- removes the elements in the
- given range
+ @sa @ref erase(InteratorType, InteratorType) -- removes the elements in
+ the given range
@sa @ref erase(const typename object_t::key_type&) -- removes the element
from an object at the given key
@@ -3659,7 +3988,7 @@ class basic_json
{
if (idx >= size())
{
- throw std::out_of_range("index out of range");
+ throw std::out_of_range("array index " + std::to_string(idx) + " is out of range");
}
assert(m_value.array != nullptr);
@@ -3671,11 +4000,22 @@ class basic_json
}
}
+ /// @}
+
+
+ ////////////
+ // 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
- element is not found or the JSON value is not an object, end() is returned.
+ element is not found or the JSON value is not an object, end() is
+ returned.
@param[in] key key value of the element to search for
@@ -3684,7 +4024,7 @@ class basic_json
@complexity Logarithmic in the size of the JSON object.
- @liveexample{The example shows how find is used.,find__key_type}
+ @liveexample{The example shows how `find()` is used.,find__key_type}
@since version 1.0.0
*/
@@ -3732,7 +4072,7 @@ class basic_json
@complexity Logarithmic in the size of the JSON object.
- @liveexample{The example shows how count is used.,count}
+ @liveexample{The example shows how `count()` is used.,count}
@since version 1.0.0
*/
@@ -3764,14 +4104,20 @@ class basic_json
@complexity Constant.
- @requirement This function satisfies the Container requirements:
+ @requirement This function helps `basic_json` satisfying the
+ [Container](http://en.cppreference.com/w/cpp/concept/Container)
+ requirements:
- The complexity is constant.
- @liveexample{The following code shows an example for @ref begin.,begin}
+ @liveexample{The following code shows an example for `begin()`.,begin}
+
+ @sa @ref cbegin() -- returns a const iterator to the beginning
+ @sa @ref end() -- returns an iterator to the end
+ @sa @ref cend() -- returns a const iterator to the end
@since version 1.0.0
*/
- iterator begin()
+ iterator begin() noexcept
{
iterator result(this);
result.set_begin();
@@ -3781,7 +4127,7 @@ class basic_json
/*!
@copydoc basic_json::cbegin()
*/
- const_iterator begin() const
+ const_iterator begin() const noexcept
{
return cbegin();
}
@@ -3797,15 +4143,21 @@ class basic_json
@complexity Constant.
- @requirement This function satisfies the Container requirements:
+ @requirement This function helps `basic_json` satisfying the
+ [Container](http://en.cppreference.com/w/cpp/concept/Container)
+ requirements:
- The complexity is constant.
- Has the semantics of `const_cast<const basic_json&>(*this).begin()`.
- @liveexample{The following code shows an example for @ref cbegin.,cbegin}
+ @liveexample{The following code shows an example for `cbegin()`.,cbegin}
+
+ @sa @ref begin() -- returns an iterator to the beginning
+ @sa @ref end() -- returns an iterator to the end
+ @sa @ref cend() -- returns a const iterator to the end
@since version 1.0.0
*/
- const_iterator cbegin() const
+ const_iterator cbegin() const noexcept
{
const_iterator result(this);
result.set_begin();
@@ -3823,14 +4175,20 @@ class basic_json
@complexity Constant.
- @requirement This function satisfies the Container requirements:
+ @requirement This function helps `basic_json` satisfying the
+ [Container](http://en.cppreference.com/w/cpp/concept/Container)
+ requirements:
- The complexity is constant.
- @liveexample{The following code shows an example for @ref end.,end}
+ @liveexample{The following code shows an example for `end()`.,end}
+
+ @sa @ref cend() -- returns a const iterator to the end
+ @sa @ref begin() -- returns an iterator to the beginning
+ @sa @ref cbegin() -- returns a const iterator to the beginning
@since version 1.0.0
*/
- iterator end()
+ iterator end() noexcept
{
iterator result(this);
result.set_end();
@@ -3840,7 +4198,7 @@ class basic_json
/*!
@copydoc basic_json::cend()
*/
- const_iterator end() const
+ const_iterator end() const noexcept
{
return cend();
}
@@ -3856,15 +4214,21 @@ class basic_json
@complexity Constant.
- @requirement This function satisfies the Container requirements:
+ @requirement This function helps `basic_json` satisfying the
+ [Container](http://en.cppreference.com/w/cpp/concept/Container)
+ requirements:
- The complexity is constant.
- Has the semantics of `const_cast<const basic_json&>(*this).end()`.
- @liveexample{The following code shows an example for @ref cend.,cend}
+ @liveexample{The following code shows an example for `cend()`.,cend}
+
+ @sa @ref end() -- returns an iterator to the end
+ @sa @ref begin() -- returns an iterator to the beginning
+ @sa @ref cbegin() -- returns a const iterator to the beginning
@since version 1.0.0
*/
- const_iterator cend() const
+ const_iterator cend() const noexcept
{
const_iterator result(this);
result.set_end();
@@ -3880,15 +4244,21 @@ class basic_json
@complexity Constant.
- @requirement This function satisfies the ReversibleContainer requirements:
+ @requirement This function helps `basic_json` satisfying the
+ [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer)
+ requirements:
- The complexity is constant.
- Has the semantics of `reverse_iterator(end())`.
- @liveexample{The following code shows an example for @ref rbegin.,rbegin}
+ @liveexample{The following code shows an example for `rbegin()`.,rbegin}
+
+ @sa @ref crbegin() -- returns a const reverse iterator to the beginning
+ @sa @ref rend() -- returns a reverse iterator to the end
+ @sa @ref crend() -- returns a const reverse iterator to the end
@since version 1.0.0
*/
- reverse_iterator rbegin()
+ reverse_iterator rbegin() noexcept
{
return reverse_iterator(end());
}
@@ -3896,7 +4266,7 @@ class basic_json
/*!
@copydoc basic_json::crbegin()
*/
- const_reverse_iterator rbegin() const
+ const_reverse_iterator rbegin() const noexcept
{
return crbegin();
}
@@ -3911,15 +4281,21 @@ class basic_json
@complexity Constant.
- @requirement This function satisfies the ReversibleContainer requirements:
+ @requirement This function helps `basic_json` satisfying the
+ [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer)
+ requirements:
- The complexity is constant.
- Has the semantics of `reverse_iterator(begin())`.
- @liveexample{The following code shows an example for @ref rend.,rend}
+ @liveexample{The following code shows an example for `rend()`.,rend}
+
+ @sa @ref crend() -- returns a const reverse iterator to the end
+ @sa @ref rbegin() -- returns a reverse iterator to the beginning
+ @sa @ref crbegin() -- returns a const reverse iterator to the beginning
@since version 1.0.0
*/
- reverse_iterator rend()
+ reverse_iterator rend() noexcept
{
return reverse_iterator(begin());
}
@@ -3927,7 +4303,7 @@ class basic_json
/*!
@copydoc basic_json::crend()
*/
- const_reverse_iterator rend() const
+ const_reverse_iterator rend() const noexcept
{
return crend();
}
@@ -3942,15 +4318,21 @@ class basic_json
@complexity Constant.
- @requirement This function satisfies the ReversibleContainer requirements:
+ @requirement This function helps `basic_json` satisfying the
+ [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer)
+ requirements:
- The complexity is constant.
- Has the semantics of `const_cast<const basic_json&>(*this).rbegin()`.
- @liveexample{The following code shows an example for @ref crbegin.,crbegin}
+ @liveexample{The following code shows an example for `crbegin()`.,crbegin}
+
+ @sa @ref rbegin() -- returns a reverse iterator to the beginning
+ @sa @ref rend() -- returns a reverse iterator to the end
+ @sa @ref crend() -- returns a const reverse iterator to the end
@since version 1.0.0
*/
- const_reverse_iterator crbegin() const
+ const_reverse_iterator crbegin() const noexcept
{
return const_reverse_iterator(cend());
}
@@ -3965,15 +4347,21 @@ class basic_json
@complexity Constant.
- @requirement This function satisfies the ReversibleContainer requirements:
+ @requirement This function helps `basic_json` satisfying the
+ [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer)
+ requirements:
- The complexity is constant.
- Has the semantics of `const_cast<const basic_json&>(*this).rend()`.
- @liveexample{The following code shows an example for @ref crend.,crend}
+ @liveexample{The following code shows an example for `crend()`.,crend}
+
+ @sa @ref rend() -- returns a reverse iterator to the end
+ @sa @ref rbegin() -- returns a reverse iterator to the beginning
+ @sa @ref crbegin() -- returns a const reverse iterator to the beginning
@since version 1.0.0
*/
- const_reverse_iterator crend() const
+ const_reverse_iterator crend() const noexcept
{
return const_reverse_iterator(cbegin());
}
@@ -3987,9 +4375,9 @@ class basic_json
@brief wrapper to access iterator member functions in range-based for
This function allows to access @ref iterator::key() and @ref
- iterator::value() during range-based for loops. In these loops, a reference
- to the JSON values is returned, so there is no access to the underlying
- iterator.
+ iterator::value() during range-based for loops. In these loops, a
+ reference to the JSON values is returned, so there is no access to the
+ underlying iterator.
@note The name of this function is not yet final and may change in the
future.
@@ -4026,24 +4414,28 @@ class basic_json
defined as follows:
Value type | return value
----------- | -------------
- null | @c true
- boolean | @c false
- string | @c false
- number | @c false
- object | result of function object_t::empty()
- array | result of function array_t::empty()
-
- @complexity Constant, as long as @ref array_t and @ref object_t satisfy the
- Container concept; that is, their empty() functions have constant
+ null | `true`
+ boolean | `false`
+ string | `false`
+ number | `false`
+ object | result of function `object_t::empty()`
+ array | result of function `array_t::empty()`
+
+ @complexity Constant, as long as @ref array_t and @ref object_t satisfy
+ the Container concept; that is, their `empty()` functions have constant
complexity.
- @requirement This function satisfies the Container requirements:
+ @requirement This function helps `basic_json` satisfying the
+ [Container](http://en.cppreference.com/w/cpp/concept/Container)
+ requirements:
- The complexity is constant.
- Has the semantics of `begin() == end()`.
- @liveexample{The following code uses @ref empty to check if a @ref json
+ @liveexample{The following code uses `empty()` to check if a JSON
object contains any elements.,empty}
+ @sa @ref size() -- returns the number of elements
+
@since version 1.0.0
*/
bool empty() const noexcept
@@ -4085,23 +4477,29 @@ class basic_json
defined as follows:
Value type | return value
----------- | -------------
- null | @c 0
- boolean | @c 1
- string | @c 1
- number | @c 1
+ null | `0`
+ boolean | `1`
+ string | `1`
+ number | `1`
object | result of function object_t::size()
array | result of function array_t::size()
- @complexity Constant, as long as @ref array_t and @ref object_t satisfy the
- Container concept; that is, their size() functions have constant complexity.
+ @complexity Constant, as long as @ref array_t and @ref object_t satisfy
+ the Container concept; that is, their size() functions have constant
+ complexity.
- @requirement This function satisfies the Container requirements:
+ @requirement This function helps `basic_json` satisfying the
+ [Container](http://en.cppreference.com/w/cpp/concept/Container)
+ requirements:
- The complexity is constant.
- Has the semantics of `std::distance(begin(), end())`.
- @liveexample{The following code calls @ref size on the different value
+ @liveexample{The following code calls `size()` on the different value
types.,size}
+ @sa @ref empty() -- checks whether the container is empty
+ @sa @ref max_size() -- returns the maximal number of elements
+
@since version 1.0.0
*/
size_type size() const noexcept
@@ -4145,25 +4543,29 @@ class basic_json
defined as follows:
Value type | return value
----------- | -------------
- null | @c 0 (same as size())
- boolean | @c 1 (same as size())
- string | @c 1 (same as size())
- number | @c 1 (same as size())
- object | result of function object_t::max_size()
- array | result of function array_t::max_size()
-
- @complexity Constant, as long as @ref array_t and @ref object_t satisfy the
- Container concept; that is, their max_size() functions have constant
+ null | `0` (same as `size()`)
+ boolean | `1` (same as `size()`)
+ string | `1` (same as `size()`)
+ number | `1` (same as `size()`)
+ object | result of function `object_t::max_size()`
+ array | result of function `array_t::max_size()`
+
+ @complexity Constant, as long as @ref array_t and @ref object_t satisfy
+ the Container concept; that is, their `max_size()` functions have constant
complexity.
- @requirement This function satisfies the Container requirements:
+ @requirement This function helps `basic_json` satisfying the
+ [Container](http://en.cppreference.com/w/cpp/concept/Container)
+ requirements:
- The complexity is constant.
- Has the semantics of returning `b.size()` where `b` is the largest
possible JSON value.
- @liveexample{The following code calls @ref max_size on the different value
+ @liveexample{The following code calls `max_size()` on the different value
types. Note the output is implementation specific.,max_size}
+ @sa @ref size() -- returns the number of elements
+
@since version 1.0.0
*/
size_type max_size() const noexcept
@@ -4220,7 +4622,7 @@ class basic_json
@complexity Linear in the size of the JSON value.
- @liveexample{The example below shows the effect of @ref clear to different
+ @liveexample{The example below shows the effect of `clear()` to different
JSON types.,clear}
@since version 1.0.0
@@ -4235,6 +4637,12 @@ class basic_json
break;
}
+ case value_t::number_unsigned:
+ {
+ m_value.number_unsigned = 0;
+ break;
+ }
+
case value_t::number_float:
{
m_value.number_float = 0.0;
@@ -4282,16 +4690,16 @@ class basic_json
function is called on a JSON null value, an empty array is created before
appending @a val.
- @param val the value to add to the JSON array
+ @param[in] val the value to add to the JSON array
@throw std::domain_error when called on a type other than JSON array or
null; example: `"cannot use push_back() with number"`
@complexity Amortized constant.
- @liveexample{The example shows how `push_back` and `+=` can be used to add
- elements to a JSON array. Note how the `null` value was silently converted
- to a JSON array.,push_back}
+ @liveexample{The example shows how `push_back()` and `+=` can be used to
+ add elements to a JSON array. Note how the `null` value was silently
+ converted to a JSON array.,push_back}
@since version 1.0.0
*/
@@ -4365,8 +4773,8 @@ class basic_json
@brief add an object to an object
Inserts the given element @a val to the JSON object. If the function is
- called on a JSON null value, an empty object is created before inserting @a
- val.
+ called on a JSON null value, an empty object is created before inserting
+ @a val.
@param[in] val the value to add to the JSON object
@@ -4375,9 +4783,9 @@ class basic_json
@complexity Logarithmic in the size of the container, O(log(`size()`)).
- @liveexample{The example shows how `push_back` and `+=` can be used to add
- elements to a JSON object. Note how the `null` value was silently converted
- to a JSON object.,push_back__object_t__value}
+ @liveexample{The example shows how `push_back()` and `+=` can be used to
+ add elements to a JSON object. Note how the `null` value was silently
+ converted to a JSON object.,push_back__object_t__value}
@since version 1.0.0
*/
@@ -4408,7 +4816,55 @@ class basic_json
reference operator+=(const typename object_t::value_type& val)
{
push_back(val);
- return operator[](val.first);
+ return *this;
+ }
+
+ /*!
+ @brief add an object to an object
+
+ This function allows to use `push_back` with an initializer list. In case
+
+ 1. the current value is an object,
+ 2. the initializer list @a init contains only two elements, and
+ 3. the first element of @a init is a string,
+
+ @a init is converted into an object element and added using
+ @ref push_back(const typename object_t::value_type&). Otherwise, @a init
+ is converted to a JSON value and added using @ref push_back(basic_json&&).
+
+ @param init an initializer list
+
+ @complexity Linear in the size of the initializer list @a init.
+
+ @note This function is required to resolve an ambiguous overload error,
+ because pairs like `{"key", "value"}` can be both interpreted as
+ `object_t::value_type` or `std::initializer_list<basic_json>`, see
+ https://github.com/nlohmann/json/issues/235 for more information.
+
+ @liveexample{The example shows how initializer lists are treated as
+ objects when possible.,push_back__initializer_list}
+ */
+ void push_back(std::initializer_list<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<basic_json>)
+ */
+ reference operator+=(std::initializer_list<basic_json> init)
+ {
+ push_back(init);
+ return *this;
}
/*!
@@ -4429,7 +4885,7 @@ class basic_json
@complexity Constant plus linear in the distance between pos and end of the
container.
- @liveexample{The example shows how insert is used.,insert}
+ @liveexample{The example shows how `insert()` is used.,insert}
@since version 1.0.0
*/
@@ -4485,7 +4941,7 @@ class basic_json
@complexity Linear in @a cnt plus linear in the distance between @a pos
and end of the container.
- @liveexample{The example shows how insert is used.,insert__count}
+ @liveexample{The example shows how `insert()` is used.,insert__count}
@since version 1.0.0
*/
@@ -4538,7 +4994,7 @@ class basic_json
@complexity Linear in `std::distance(first, last)` plus linear in the
distance between @a pos and end of the container.
- @liveexample{The example shows how insert is used.,insert__range}
+ @liveexample{The example shows how `insert()` is used.,insert__range}
@since version 1.0.0
*/
@@ -4556,6 +5012,7 @@ class basic_json
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");
@@ -4593,10 +5050,10 @@ class basic_json
@return iterator pointing to the first element inserted, or @a pos if
`ilist` is empty
- @complexity Linear in `ilist.size()` plus linear in the distance between @a
- pos and end of the container.
+ @complexity Linear in `ilist.size()` plus linear in the distance between
+ @a pos and end of the container.
- @liveexample{The example shows how insert is used.,insert__ilist}
+ @liveexample{The example shows how `insert()` is used.,insert__ilist}
@since version 1.0.0
*/
@@ -4633,8 +5090,8 @@ class basic_json
@complexity Constant.
- @liveexample{The example below shows how JSON arrays can be
- swapped.,swap__reference}
+ @liveexample{The example below shows how JSON values can be swapped with
+ `swap()`.,swap__reference}
@since version 1.0.0
*/
@@ -4664,8 +5121,8 @@ class basic_json
@complexity Constant.
- @liveexample{The example below shows how JSON values can be
- swapped.,swap__array_t}
+ @liveexample{The example below shows how arrays can be swapped with
+ `swap()`.,swap__array_t}
@since version 1.0.0
*/
@@ -4698,8 +5155,8 @@ class basic_json
@complexity Constant.
- @liveexample{The example below shows how JSON values can be
- swapped.,swap__object_t}
+ @liveexample{The example below shows how objects can be swapped with
+ `swap()`.,swap__object_t}
@since version 1.0.0
*/
@@ -4732,8 +5189,8 @@ class basic_json
@complexity Constant.
- @liveexample{The example below shows how JSON values can be
- swapped.,swap__string_t}
+ @liveexample{The example below shows how strings can be swapped with
+ `swap()`.,swap__string_t}
@since version 1.0.0
*/
@@ -4771,16 +5228,17 @@ class basic_json
@since version 1.0.0
*/
- friend bool operator<(const value_t lhs, const value_t rhs)
+ friend bool operator<(const value_t lhs, const value_t rhs) noexcept
{
- static constexpr std::array<uint8_t, 7> order = {{
+ static constexpr std::array<uint8_t, 8> order = {{
0, // null
3, // object
4, // array
5, // string
1, // boolean
2, // integer
- 2 // float
+ 2, // unsigned
+ 2, // float
}
};
@@ -4856,6 +5314,10 @@ class basic_json
{
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;
@@ -4874,6 +5336,23 @@ class basic_json
{
return lhs.m_value.number_float == static_cast<number_float_t>(rhs.m_value.number_integer);
}
+ else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_float)
+ {
+ return static_cast<number_float_t>(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<number_float_t>(rhs.m_value.number_unsigned);
+ }
+ else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_integer)
+ {
+ return static_cast<number_integer_t>(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<number_integer_t>(rhs.m_value.number_unsigned);
+ }
+
return false;
}
@@ -5025,6 +5504,10 @@ class basic_json
{
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;
@@ -5037,13 +5520,27 @@ class basic_json
}
else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_float)
{
- return static_cast<number_float_t>(lhs.m_value.number_integer) <
- rhs.m_value.number_float;
+ return static_cast<number_float_t>(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<number_float_t>(rhs.m_value.number_integer);
+ return lhs.m_value.number_float < static_cast<number_float_t>(rhs.m_value.number_integer);
+ }
+ else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_float)
+ {
+ return static_cast<number_float_t>(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<number_float_t>(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<number_integer_t>(rhs.m_value.number_unsigned);
+ }
+ else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_integer)
+ {
+ return static_cast<number_integer_t>(lhs.m_value.number_unsigned) < rhs.m_value.number_integer;
}
// We only reach this line if we cannot compare values. In that case,
@@ -5199,8 +5696,8 @@ class basic_json
@note A UTF-8 byte order mark is silently ignored.
- @liveexample{The example below demonstrates the parse function with and
- without callback function.,parse__string__parser_callback_t}
+ @liveexample{The example below demonstrates the `parse()` function with
+ and without callback function.,parse__string__parser_callback_t}
@sa @ref parse(std::istream&, parser_callback_t) for a version that reads
from an input stream
@@ -5228,11 +5725,11 @@ class basic_json
@note A UTF-8 byte order mark is silently ignored.
- @liveexample{The example below demonstrates the parse function with and
- without callback function.,parse__istream__parser_callback_t}
+ @liveexample{The example below demonstrates the `parse()` function with
+ and without callback function.,parse__istream__parser_callback_t}
- @sa @ref parse(const string_t&, parser_callback_t) for a version that reads
- from a string
+ @sa @ref parse(const string_t&, parser_callback_t) for a version that
+ reads from a string
@since version 1.0.0
*/
@@ -5297,7 +5794,7 @@ class basic_json
///////////////////////////
/// return the type as string
- string_t type_name() const
+ string_t type_name() const noexcept
{
switch (m_type)
{
@@ -5365,8 +5862,8 @@ class basic_json
/*!
@brief escape a string
- Escape a string by replacing certain special characters by a sequence of an
- escape character (backslash) and another character and other control
+ Escape a string by replacing certain special characters by a sequence of
+ an escape character (backslash) and another character and other control
characters by a sequence of "\u" followed by a four-digit hex
representation.
@@ -5375,7 +5872,7 @@ class basic_json
@complexity Linear in the length of string @a s.
*/
- static string_t escape_string(const string_t& s) noexcept
+ static string_t escape_string(const string_t& s)
{
const auto space = extra_space(s);
if (space == 0)
@@ -5451,10 +5948,13 @@ class basic_json
{
if (c >= 0x00 and c <= 0x1f)
{
- // convert a number 0..15 to its hex representation (0..f)
- auto hexify = [](const char v) -> char
+ // convert a number 0..15 to its hex representation
+ // (0..f)
+ const auto hexify = [](const int v) -> char
{
- return (v < 10) ? ('0' + v) : ('a' + v - 10);
+ return (v < 10)
+ ? ('0' + static_cast<char>(v))
+ : ('a' + static_cast<char>((v - 10) & 0x1f));
};
// print character c as \uxxxx
@@ -5485,12 +5985,12 @@ class basic_json
This function is called by the public member function dump and organizes
the serialization internally. The indentation level is propagated as
- additional parameter. In case of arrays and objects, the function is called
- recursively. Note that
+ additional parameter. In case of arrays and objects, the function is
+ called recursively. Note that
- - strings and object keys are escaped using escape_string()
- - integer numbers are converted implicitly via operator<<
- - floating-point numbers are converted to a string using "%g" format
+ - strings and object keys are escaped using `escape_string()`
+ - integer numbers are converted implicitly via `operator<<`
+ - floating-point numbers are converted to a string using `"%g"` format
@param[out] o stream to write to
@param[in] pretty_print whether the output shall be pretty-printed
@@ -5608,25 +6108,32 @@ class basic_json
return;
}
+ case value_t::number_unsigned:
+ {
+ o << m_value.number_unsigned;
+ return;
+ }
+
case value_t::number_float:
{
- // If the number is an integer then output as a fixed with with
- // precision 1 to output "0.0", "1.0" etc as expected for some
- // round trip tests otherwise 15 digits of precision allows
- // round-trip IEEE 754 string->double->string; to be safe, we
- // read this value from
- // std::numeric_limits<number_float_t>::digits10
- if (std::fmod(m_value.number_float, 1) == 0)
+ if (m_value.number_float == 0)
{
- o << std::fixed << std::setprecision(1);
+ // special case for zero to get "0.0"/"-0.0"
+ o << (std::signbit(m_value.number_float) ? "-0.0" : "0.0");
}
else
{
- // std::defaultfloat not supported in gcc version < 5
- o.unsetf(std::ios_base::floatfield);
- o << std::setprecision(std::numeric_limits<double>::digits10);
+ // Otherwise 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<number_float_t>::digits10
+ std::stringstream ss;
+ ss.imbue(std::locale(std::locale(), new DecimalSeparator)); // fix locale problems
+ ss << std::setprecision(std::numeric_limits<double>::digits10)
+ << m_value.number_float;
+ o << ss.str();
}
- o << m_value.number_float;
return;
}
@@ -5674,37 +6181,37 @@ class basic_json
{
public:
/// set iterator to a defined beginning
- void set_begin()
+ void set_begin() noexcept
{
m_it = begin_value;
}
/// set iterator to a defined past the end
- void set_end()
+ void set_end() noexcept
{
m_it = end_value;
}
/// return whether the iterator can be dereferenced
- bool is_begin() const
+ constexpr bool is_begin() const noexcept
{
return (m_it == begin_value);
}
/// return whether the iterator is at end
- bool is_end() const
+ constexpr bool is_end() const noexcept
{
return (m_it == end_value);
}
/// return reference to the value to change and compare
- operator difference_type& ()
+ operator difference_type& () noexcept
{
return m_it;
}
/// return value to compare
- operator difference_type () const
+ constexpr operator difference_type () const noexcept
{
return m_it;
}
@@ -5734,7 +6241,7 @@ class basic_json
primitive_iterator_t primitive_iterator;
/// create an uninitialized internal_iterator
- internal_iterator()
+ internal_iterator() noexcept
: object_iterator(), array_iterator(), primitive_iterator()
{}
};
@@ -5754,7 +6261,7 @@ class basic_json
size_t array_index = 0;
public:
- iteration_proxy_internal(IteratorType it)
+ explicit iteration_proxy_internal(IteratorType it) noexcept
: anchor(it)
{}
@@ -5818,18 +6325,18 @@ class basic_json
public:
/// construct iteration proxy from a container
- iteration_proxy(typename IteratorType::reference cont)
+ explicit iteration_proxy(typename IteratorType::reference cont)
: container(cont)
{}
/// return iterator begin (needed for range-based for)
- iteration_proxy_internal begin()
+ iteration_proxy_internal begin() noexcept
{
return iteration_proxy_internal(container.begin());
}
/// return iterator end (needed for range-based for)
- iteration_proxy_internal end()
+ iteration_proxy_internal end() noexcept
{
return iteration_proxy_internal(container.end());
}
@@ -5870,7 +6377,8 @@ class basic_json
const_iterator() = default;
/// constructor for a given JSON instance
- const_iterator(pointer object) : m_object(object)
+ explicit const_iterator(pointer object) noexcept
+ : m_object(object)
{
assert(m_object != nullptr);
@@ -5897,7 +6405,8 @@ class basic_json
}
/// copy constructor given a nonconst iterator
- const_iterator(const iterator& other) : m_object(other.m_object)
+ explicit const_iterator(const iterator& other) noexcept
+ : m_object(other.m_object)
{
assert(m_object != nullptr);
@@ -5943,7 +6452,7 @@ class basic_json
private:
/// set the iterator to the first value
- void set_begin()
+ void set_begin() noexcept
{
assert(m_object != nullptr);
@@ -5979,7 +6488,7 @@ class basic_json
}
/// set the iterator past the last value
- void set_end()
+ void set_end() noexcept
{
assert(m_object != nullptr);
@@ -6402,7 +6911,7 @@ class basic_json
iterator() = default;
/// constructor for a given JSON instance
- iterator(pointer object) noexcept
+ explicit iterator(pointer object) noexcept
: base_iterator(object)
{}
@@ -6424,13 +6933,13 @@ class basic_json
}
/// return a reference to the value pointed to by the iterator
- reference operator*()
+ reference operator*() const
{
return const_cast<reference>(base_iterator::operator*());
}
/// dereference the iterator
- pointer operator->()
+ pointer operator->() const
{
return const_cast<pointer>(base_iterator::operator->());
}
@@ -6495,6 +7004,7 @@ class basic_json
return result;
}
+ /// return difference
difference_type operator-(const iterator& other) const
{
return base_iterator::operator-(other);
@@ -6540,12 +7050,12 @@ class basic_json
using reference = typename Base::reference;
/// create reverse iterator from iterator
- json_reverse_iterator(const typename base_iterator::iterator_type& it)
+ 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)
+ json_reverse_iterator(const base_iterator& it) noexcept
: base_iterator(it)
{}
@@ -6635,8 +7145,8 @@ class basic_json
@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.
+ 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
{
@@ -6644,20 +7154,20 @@ class basic_json
/// 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
+ 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
@@ -6700,7 +7210,7 @@ class basic_json
@return string representation of the code point
- @throw std::out_of_range if code point is >0x10ffff; example: `"code
+ @throw std::out_of_range if code point is > 0x10ffff; example: `"code
points above 0x10FFFF are invalid"`
@throw std::invalid_argument if the low surrogate is invalid; example:
`""missing or wrong low surrogate""`
@@ -6710,8 +7220,6 @@ class basic_json
static string_t to_unicode(const std::size_t codepoint1,
const std::size_t codepoint2 = 0)
{
- string_t result;
-
// calculate the codepoint from the given code points
std::size_t codepoint = codepoint1;
@@ -6737,6 +7245,8 @@ class basic_json
}
}
+ string_t result;
+
if (codepoint < 0x80)
{
// 1-byte characters: 0xxxxxxx (ASCII)
@@ -6815,10 +7325,10 @@ class basic_json
/*!
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 deterministic
- finite automaton (DFA) by the tool re2c <http://re2c.org>. As a result,
- the translated code for this function consists of a large block of code
- with goto jumps.
+ These regular expressions are then translated into a minimized
+ deterministic finite automaton (DFA) by the tool
+ [re2c](http://re2c.org). As a result, the translated code for this
+ function consists of a large block of code with `goto` jumps.
@return the class of the next token read from the buffer
*/
@@ -6839,322 +7349,323 @@ class basic_json
{
0, 0, 0, 0, 0, 0, 0, 0,
0, 32, 32, 0, 0, 32, 0, 0,
- 64, 64, 64, 64, 64, 64, 64, 64,
- 64, 64, 64, 64, 64, 64, 64, 64,
- 96, 64, 0, 64, 64, 64, 64, 64,
- 64, 64, 64, 64, 64, 64, 64, 64,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 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, 64, 64, 64, 64, 64, 64,
- 64, 64, 64, 64, 64, 64, 64, 64,
- 64, 64, 64, 64, 64, 64, 64, 64,
- 64, 64, 64, 64, 64, 64, 64, 64,
- 64, 64, 64, 64, 0, 64, 64, 64,
- 64, 64, 64, 64, 64, 64, 64, 64,
- 64, 64, 64, 64, 64, 64, 64, 64,
- 64, 64, 64, 64, 64, 64, 64, 64,
- 64, 64, 64, 64, 64, 64, 64, 64,
- 64, 64, 64, 64, 64, 64, 64, 64,
- 64, 64, 64, 64, 64, 64, 64, 64,
- 64, 64, 64, 64, 64, 64, 64, 64,
- 64, 64, 64, 64, 64, 64, 64, 64,
- 64, 64, 64, 64, 64, 64, 64, 64,
- 64, 64, 64, 64, 64, 64, 64, 64,
- 64, 64, 64, 64, 64, 64, 64, 64,
- 64, 64, 64, 64, 64, 64, 64, 64,
- 64, 64, 64, 64, 64, 64, 64, 64,
- 64, 64, 64, 64, 64, 64, 64, 64,
- 64, 64, 64, 64, 64, 64, 64, 64,
- 64, 64, 64, 64, 64, 64, 64, 64,
- 64, 64, 64, 64, 64, 64, 64, 64,
- 64, 64, 64, 64, 64, 64, 64, 64,
- 64, 64, 64, 64, 64, 64, 64, 64,
- 64, 64, 64, 64, 64, 64, 64, 64,
+ 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)
{
yyfill(); // LCOV_EXCL_LINE;
}
yych = *m_cursor;
- if (yych <= ':')
+ if (yybm[0 + yych] & 32)
{
- if (yych <= ' ')
+ goto basic_json_parser_6;
+ }
+ if (yych <= '\\')
+ {
+ if (yych <= '-')
{
- if (yych <= '\n')
+ if (yych <= '"')
{
if (yych <= 0x00)
{
- goto basic_json_parser_28;
- }
- if (yych <= 0x08)
- {
- goto basic_json_parser_30;
+ goto basic_json_parser_2;
}
- if (yych >= '\n')
+ if (yych <= '!')
{
goto basic_json_parser_4;
}
+ goto basic_json_parser_9;
}
else
{
- if (yych == '\r')
+ if (yych <= '+')
{
- goto basic_json_parser_2;
+ goto basic_json_parser_4;
}
- if (yych <= 0x1F)
+ if (yych <= ',')
{
- goto basic_json_parser_30;
+ goto basic_json_parser_10;
}
+ goto basic_json_parser_12;
}
}
else
{
- if (yych <= ',')
+ if (yych <= '9')
{
- if (yych == '"')
+ if (yych <= '/')
{
- goto basic_json_parser_27;
+ goto basic_json_parser_4;
}
- if (yych <= '+')
+ if (yych <= '0')
{
- goto basic_json_parser_30;
+ goto basic_json_parser_13;
}
- goto basic_json_parser_16;
+ goto basic_json_parser_15;
}
else
{
- if (yych <= '/')
+ if (yych <= ':')
{
- if (yych <= '-')
- {
- goto basic_json_parser_23;
- }
- goto basic_json_parser_30;
+ goto basic_json_parser_17;
}
- else
+ if (yych == '[')
{
- if (yych <= '0')
- {
- goto basic_json_parser_24;
- }
- if (yych <= '9')
- {
- goto basic_json_parser_26;
- }
- goto basic_json_parser_18;
+ goto basic_json_parser_19;
}
+ goto basic_json_parser_4;
}
}
}
else
{
- if (yych <= 'n')
+ if (yych <= 't')
{
- if (yych <= ']')
+ if (yych <= 'f')
{
- if (yych == '[')
+ if (yych <= ']')
{
- goto basic_json_parser_8;
+ goto basic_json_parser_21;
}
- if (yych <= '\\')
+ if (yych <= 'e')
{
- goto basic_json_parser_30;
+ goto basic_json_parser_4;
}
- goto basic_json_parser_10;
+ goto basic_json_parser_23;
}
else
{
- if (yych == 'f')
+ if (yych == 'n')
{
- goto basic_json_parser_22;
+ goto basic_json_parser_24;
}
- if (yych <= 'm')
+ if (yych <= 's')
{
- goto basic_json_parser_30;
+ goto basic_json_parser_4;
}
- goto basic_json_parser_20;
+ goto basic_json_parser_25;
}
}
else
{
- if (yych <= '{')
+ if (yych <= '|')
{
- if (yych == 't')
+ if (yych == '{')
{
- goto basic_json_parser_21;
+ goto basic_json_parser_26;
}
- if (yych <= 'z')
- {
- goto basic_json_parser_30;
- }
- goto basic_json_parser_12;
+ goto basic_json_parser_4;
}
else
{
if (yych <= '}')
{
- if (yych <= '|')
- {
- goto basic_json_parser_30;
- }
- goto basic_json_parser_14;
+ goto basic_json_parser_28;
}
- else
+ if (yych == 0xEF)
{
- if (yych == 0xEF)
- {
- goto basic_json_parser_6;
- }
goto basic_json_parser_30;
}
+ goto basic_json_parser_4;
}
}
}
basic_json_parser_2:
++m_cursor;
- yych = *m_cursor;
- goto basic_json_parser_5;
-basic_json_parser_3:
{
- return scan();
+ return token_type::end_of_input;
}
basic_json_parser_4:
++m_cursor;
+basic_json_parser_5:
+ {
+ return token_type::parse_error;
+ }
+basic_json_parser_6:
+ ++m_cursor;
if (m_limit <= m_cursor)
{
yyfill(); // LCOV_EXCL_LINE;
}
yych = *m_cursor;
-basic_json_parser_5:
if (yybm[0 + yych] & 32)
{
- goto basic_json_parser_4;
+ goto basic_json_parser_6;
}
- goto basic_json_parser_3;
-basic_json_parser_6:
- yyaccept = 0;
- yych = *(m_marker = ++m_cursor);
- if (yych == 0xBB)
- {
- goto basic_json_parser_64;
- }
-basic_json_parser_7:
{
- return token_type::parse_error;
+ return scan();
}
-basic_json_parser_8:
- ++m_cursor;
+basic_json_parser_9:
+ yyaccept = 0;
+ yych = *(m_marker = ++m_cursor);
+ if (yych <= 0x0F)
{
- return token_type::begin_array;
+ goto basic_json_parser_5;
}
+ goto basic_json_parser_32;
basic_json_parser_10:
++m_cursor;
{
- return token_type::end_array;
+ return token_type::value_separator;
}
basic_json_parser_12:
- ++m_cursor;
- {
- return token_type::begin_object;
- }
-basic_json_parser_14:
- ++m_cursor;
- {
- return token_type::end_object;
- }
-basic_json_parser_16:
- ++m_cursor;
+ yych = *++m_cursor;
+ if (yych <= '/')
{
- return token_type::value_separator;
+ goto basic_json_parser_5;
}
-basic_json_parser_18:
- ++m_cursor;
+ if (yych <= '0')
{
- return token_type::name_separator;
+ goto basic_json_parser_13;
}
-basic_json_parser_20:
- yyaccept = 0;
- yych = *(m_marker = ++m_cursor);
- if (yych == 'u')
+ if (yych <= '9')
{
- goto basic_json_parser_60;
+ goto basic_json_parser_15;
}
- goto basic_json_parser_7;
-basic_json_parser_21:
- yyaccept = 0;
+ goto basic_json_parser_5;
+basic_json_parser_13:
+ yyaccept = 1;
yych = *(m_marker = ++m_cursor);
- if (yych == 'r')
+ if (yych <= 'D')
{
- goto basic_json_parser_56;
+ if (yych == '.')
+ {
+ goto basic_json_parser_37;
+ }
}
- goto basic_json_parser_7;
-basic_json_parser_22:
- yyaccept = 0;
- yych = *(m_marker = ++m_cursor);
- if (yych == 'a')
+ else
{
- goto basic_json_parser_51;
+ if (yych <= 'E')
+ {
+ goto basic_json_parser_38;
+ }
+ if (yych == 'e')
+ {
+ goto basic_json_parser_38;
+ }
}
- goto basic_json_parser_7;
-basic_json_parser_23:
- yych = *++m_cursor;
- if (yych <= '/')
+basic_json_parser_14:
{
- goto basic_json_parser_7;
+ return token_type::value_number;
}
- if (yych <= '0')
+basic_json_parser_15:
+ yyaccept = 1;
+ m_marker = ++m_cursor;
+ if ((m_limit - m_cursor) < 3)
{
- goto basic_json_parser_50;
+ yyfill(); // LCOV_EXCL_LINE;
}
- if (yych <= '9')
+ yych = *m_cursor;
+ if (yybm[0 + yych] & 64)
{
- goto basic_json_parser_41;
+ goto basic_json_parser_15;
}
- goto basic_json_parser_7;
-basic_json_parser_24:
- yyaccept = 1;
- yych = *(m_marker = ++m_cursor);
if (yych <= 'D')
{
if (yych == '.')
{
- goto basic_json_parser_43;
+ goto basic_json_parser_37;
}
+ goto basic_json_parser_14;
}
else
{
if (yych <= 'E')
{
- goto basic_json_parser_44;
+ goto basic_json_parser_38;
}
if (yych == 'e')
{
- goto basic_json_parser_44;
+ goto basic_json_parser_38;
}
+ goto basic_json_parser_14;
}
-basic_json_parser_25:
+basic_json_parser_17:
+ ++m_cursor;
{
- return token_type::value_number;
+ return token_type::name_separator;
}
-basic_json_parser_26:
- yyaccept = 1;
+basic_json_parser_19:
+ ++m_cursor;
+ {
+ return token_type::begin_array;
+ }
+basic_json_parser_21:
+ ++m_cursor;
+ {
+ return token_type::end_array;
+ }
+basic_json_parser_23:
+ yyaccept = 0;
yych = *(m_marker = ++m_cursor);
- goto basic_json_parser_42;
-basic_json_parser_27:
+ 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 <= 0x0F)
+ if (yych == 'u')
{
- goto basic_json_parser_7;
+ 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;
+ {
+ return token_type::begin_object;
}
- goto basic_json_parser_32;
basic_json_parser_28:
++m_cursor;
{
- return token_type::end_of_input;
+ return token_type::end_object;
}
basic_json_parser_30:
- yych = *++m_cursor;
- goto basic_json_parser_7;
+ 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)
@@ -7163,7 +7674,7 @@ basic_json_parser_31:
}
yych = *m_cursor;
basic_json_parser_32:
- if (yybm[0 + yych] & 64)
+ if (yybm[0 + yych] & 128)
{
goto basic_json_parser_31;
}
@@ -7173,21 +7684,26 @@ basic_json_parser_32:
}
if (yych <= '"')
{
- goto basic_json_parser_35;
+ goto basic_json_parser_34;
}
- 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_7;
+ goto basic_json_parser_5;
}
else
{
- goto basic_json_parser_25;
+ goto basic_json_parser_14;
}
basic_json_parser_34:
++m_cursor;
+ {
+ return token_type::value_string;
+ }
+basic_json_parser_36:
+ ++m_cursor;
if (m_limit <= m_cursor)
{
yyfill(); // LCOV_EXCL_LINE;
@@ -7259,117 +7775,78 @@ basic_json_parser_34:
}
if (yych <= 'u')
{
- goto basic_json_parser_37;
+ goto basic_json_parser_43;
}
goto basic_json_parser_33;
}
}
}
-basic_json_parser_35:
- ++m_cursor;
- {
- return token_type::value_string;
- }
basic_json_parser_37:
- ++m_cursor;
- if (m_limit <= m_cursor)
+ yych = *++m_cursor;
+ if (yych <= '/')
{
- yyfill(); // LCOV_EXCL_LINE;
+ goto basic_json_parser_33;
}
- yych = *m_cursor;
- if (yych <= '@')
+ if (yych <= '9')
{
- if (yych <= '/')
- {
- goto basic_json_parser_33;
- }
- if (yych >= ':')
- {
- goto basic_json_parser_33;
- }
- }
- else
- {
- if (yych <= 'F')
- {
- goto basic_json_parser_38;
- }
- if (yych <= '`')
- {
- goto basic_json_parser_33;
- }
- if (yych >= 'g')
- {
- goto basic_json_parser_33;
- }
+ goto basic_json_parser_44;
}
+ goto basic_json_parser_33;
basic_json_parser_38:
- ++m_cursor;
- if (m_limit <= m_cursor)
- {
- yyfill(); // LCOV_EXCL_LINE;
- }
- yych = *m_cursor;
- if (yych <= '@')
+ yych = *++m_cursor;
+ if (yych <= ',')
{
- if (yych <= '/')
+ if (yych == '+')
{
- goto basic_json_parser_33;
- }
- if (yych >= ':')
- {
- goto basic_json_parser_33;
+ goto basic_json_parser_46;
}
+ goto basic_json_parser_33;
}
else
{
- if (yych <= 'F')
+ if (yych <= '-')
{
- goto basic_json_parser_39;
+ goto basic_json_parser_46;
}
- if (yych <= '`')
+ if (yych <= '/')
{
goto basic_json_parser_33;
}
- if (yych >= 'g')
+ if (yych <= '9')
{
- goto basic_json_parser_33;
+ goto basic_json_parser_47;
}
+ goto basic_json_parser_33;
}
basic_json_parser_39:
- ++m_cursor;
- if (m_limit <= m_cursor)
+ yych = *++m_cursor;
+ if (yych == 'l')
{
- yyfill(); // LCOV_EXCL_LINE;
+ goto basic_json_parser_49;
}
- yych = *m_cursor;
- if (yych <= '@')
+ goto basic_json_parser_33;
+basic_json_parser_40:
+ yych = *++m_cursor;
+ if (yych == 'l')
{
- if (yych <= '/')
- {
- goto basic_json_parser_33;
- }
- if (yych >= ':')
- {
- goto basic_json_parser_33;
- }
+ goto basic_json_parser_50;
}
- else
+ goto basic_json_parser_33;
+basic_json_parser_41:
+ yych = *++m_cursor;
+ if (yych == 'u')
{
- if (yych <= 'F')
- {
- goto basic_json_parser_40;
- }
- if (yych <= '`')
- {
- goto basic_json_parser_33;
- }
- if (yych >= 'g')
- {
- goto basic_json_parser_33;
- }
+ goto basic_json_parser_51;
}
-basic_json_parser_40:
+ 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)
{
@@ -7384,7 +7861,7 @@ basic_json_parser_40:
}
if (yych <= '9')
{
- goto basic_json_parser_31;
+ goto basic_json_parser_54;
}
goto basic_json_parser_33;
}
@@ -7392,7 +7869,7 @@ basic_json_parser_40:
{
if (yych <= 'F')
{
- goto basic_json_parser_31;
+ goto basic_json_parser_54;
}
if (yych <= '`')
{
@@ -7400,11 +7877,11 @@ basic_json_parser_40:
}
if (yych <= 'f')
{
- goto basic_json_parser_31;
+ goto basic_json_parser_54;
}
goto basic_json_parser_33;
}
-basic_json_parser_41:
+basic_json_parser_44:
yyaccept = 1;
m_marker = ++m_cursor;
if ((m_limit - m_cursor) < 3)
@@ -7412,67 +7889,31 @@ basic_json_parser_41:
yyfill(); // LCOV_EXCL_LINE;
}
yych = *m_cursor;
-basic_json_parser_42:
- if (yybm[0 + yych] & 128)
- {
- goto basic_json_parser_41;
- }
if (yych <= 'D')
{
- if (yych != '.')
- {
- goto basic_json_parser_25;
- }
- }
- else
- {
- if (yych <= 'E')
+ if (yych <= '/')
{
- goto basic_json_parser_44;
+ goto basic_json_parser_14;
}
- if (yych == 'e')
+ if (yych <= '9')
{
goto basic_json_parser_44;
}
- goto basic_json_parser_25;
- }
-basic_json_parser_43:
- yych = *++m_cursor;
- if (yych <= '/')
- {
- goto basic_json_parser_33;
- }
- if (yych <= '9')
- {
- goto basic_json_parser_48;
- }
- goto basic_json_parser_33;
-basic_json_parser_44:
- yych = *++m_cursor;
- if (yych <= ',')
- {
- if (yych != '+')
- {
- goto basic_json_parser_33;
- }
+ goto basic_json_parser_14;
}
else
{
- if (yych <= '-')
- {
- goto basic_json_parser_45;
- }
- if (yych <= '/')
+ if (yych <= 'E')
{
- goto basic_json_parser_33;
+ goto basic_json_parser_38;
}
- if (yych <= '9')
+ if (yych == 'e')
{
- goto basic_json_parser_46;
+ goto basic_json_parser_38;
}
- goto basic_json_parser_33;
+ goto basic_json_parser_14;
}
-basic_json_parser_45:
+basic_json_parser_46:
yych = *++m_cursor;
if (yych <= '/')
{
@@ -7482,7 +7923,7 @@ basic_json_parser_45:
{
goto basic_json_parser_33;
}
-basic_json_parser_46:
+basic_json_parser_47:
++m_cursor;
if (m_limit <= m_cursor)
{
@@ -7491,131 +7932,168 @@ basic_json_parser_46:
yych = *m_cursor;
if (yych <= '/')
{
- goto basic_json_parser_25;
+ goto basic_json_parser_14;
}
if (yych <= '9')
{
- goto basic_json_parser_46;
+ goto basic_json_parser_47;
}
- goto basic_json_parser_25;
-basic_json_parser_48:
- yyaccept = 1;
- m_marker = ++m_cursor;
- if ((m_limit - m_cursor) < 3)
+ 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;
+ {
+ return scan();
+ }
+basic_json_parser_54:
+ ++m_cursor;
+ if (m_limit <= m_cursor)
{
yyfill(); // LCOV_EXCL_LINE;
}
yych = *m_cursor;
- if (yych <= 'D')
+ if (yych <= '@')
{
if (yych <= '/')
{
- goto basic_json_parser_25;
+ goto basic_json_parser_33;
}
if (yych <= '9')
{
- goto basic_json_parser_48;
+ goto basic_json_parser_60;
}
- goto basic_json_parser_25;
+ goto basic_json_parser_33;
}
else
{
- if (yych <= 'E')
- {
- goto basic_json_parser_44;
- }
- if (yych == 'e')
- {
- goto basic_json_parser_44;
- }
- goto basic_json_parser_25;
- }
-basic_json_parser_50:
- yyaccept = 1;
- yych = *(m_marker = ++m_cursor);
- if (yych <= 'D')
- {
- if (yych == '.')
+ if (yych <= 'F')
{
- goto basic_json_parser_43;
+ goto basic_json_parser_60;
}
- goto basic_json_parser_25;
- }
- else
- {
- if (yych <= 'E')
+ if (yych <= '`')
{
- goto basic_json_parser_44;
+ goto basic_json_parser_33;
}
- if (yych == 'e')
+ if (yych <= 'f')
{
- goto basic_json_parser_44;
+ goto basic_json_parser_60;
}
- goto basic_json_parser_25;
- }
-basic_json_parser_51:
- yych = *++m_cursor;
- if (yych != 'l')
- {
goto basic_json_parser_33;
}
+basic_json_parser_55:
yych = *++m_cursor;
- if (yych != 's')
+ if (yych == 'e')
{
- goto basic_json_parser_33;
+ goto basic_json_parser_61;
}
- yych = *++m_cursor;
- if (yych != 'e')
+ goto basic_json_parser_33;
+basic_json_parser_56:
+ ++m_cursor;
{
- goto basic_json_parser_33;
+ return token_type::literal_null;
}
+basic_json_parser_58:
++m_cursor;
{
- return token_type::literal_false;
+ return token_type::literal_true;
}
-basic_json_parser_56:
- yych = *++m_cursor;
- if (yych != 'u')
+basic_json_parser_60:
+ ++m_cursor;
+ if (m_limit <= m_cursor)
{
- goto basic_json_parser_33;
+ yyfill(); // LCOV_EXCL_LINE;
}
- yych = *++m_cursor;
- if (yych != 'e')
+ yych = *m_cursor;
+ if (yych <= '@')
{
+ if (yych <= '/')
+ {
+ goto basic_json_parser_33;
+ }
+ if (yych <= '9')
+ {
+ goto basic_json_parser_63;
+ }
goto basic_json_parser_33;
}
- ++m_cursor;
- {
- return token_type::literal_true;
- }
-basic_json_parser_60:
- yych = *++m_cursor;
- if (yych != 'l')
+ else
{
+ if (yych <= 'F')
+ {
+ goto basic_json_parser_63;
+ }
+ if (yych <= '`')
+ {
+ goto basic_json_parser_33;
+ }
+ if (yych <= 'f')
+ {
+ goto basic_json_parser_63;
+ }
goto basic_json_parser_33;
}
- yych = *++m_cursor;
- if (yych != 'l')
+basic_json_parser_61:
+ ++m_cursor;
{
- goto basic_json_parser_33;
+ return token_type::literal_false;
}
+basic_json_parser_63:
++m_cursor;
+ if (m_limit <= m_cursor)
{
- return token_type::literal_null;
+ yyfill(); // LCOV_EXCL_LINE;
}
-basic_json_parser_64:
- yych = *++m_cursor;
- if (yych != 0xBF)
+ yych = *m_cursor;
+ if (yych <= '@')
{
+ if (yych <= '/')
+ {
+ goto basic_json_parser_33;
+ }
+ if (yych <= '9')
+ {
+ goto basic_json_parser_31;
+ }
goto basic_json_parser_33;
}
- ++m_cursor;
+ else
{
- return scan();
+ if (yych <= 'F')
+ {
+ goto basic_json_parser_31;
+ }
+ if (yych <= '`')
+ {
+ goto basic_json_parser_33;
+ }
+ if (yych <= 'f')
+ {
+ goto basic_json_parser_31;
+ }
+ goto basic_json_parser_33;
}
}
-
}
/// append data from the stream to the internal buffer
@@ -7626,9 +8104,9 @@ basic_json_parser_64:
return;
}
- const ssize_t offset_start = m_start - m_content;
- const ssize_t offset_marker = m_marker - m_start;
- const ssize_t offset_cursor = m_cursor - m_start;
+ const auto offset_start = m_start - m_content;
+ const auto offset_marker = m_marker - m_start;
+ const auto offset_cursor = m_cursor - m_start;
m_buffer.erase(0, static_cast<size_t>(offset_start));
std::string line;
@@ -7645,7 +8123,7 @@ basic_json_parser_64:
}
/// return string representation of last read token
- string_t get_token() const noexcept
+ string_t get_token() const
{
assert(m_start != nullptr);
return string_t(reinterpret_cast<typename string_t::const_pointer>(m_start),
@@ -7664,13 +8142,14 @@ basic_json_parser_64:
1. Escaped characters. In this case, a new character is constructed
according to the nature of the escape. Some escapes create new
- characters (e.g., @c "\\n" is replaced by @c "\n"), some are copied
- as is (e.g., @c "\\\\"). Furthermore, Unicode escapes of the shape
- @c "\\uxxxx" need special care. In this case, to_unicode takes care
+ characters (e.g., `"\\n"` is replaced by `"\n"`), some are copied
+ as is (e.g., `"\\\\"`). Furthermore, Unicode escapes of the shape
+ `"\\uxxxx"` need special care. In this case, to_unicode takes care
of the construction of the values.
2. Unescaped characters are copied as is.
- @return string value of current token without opening and closing quotes
+ @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
@@ -7780,9 +8259,9 @@ basic_json_parser_64:
@brief parse floating point number
This function (and its overloads) serves to select the most approprate
- standard floating point number parsing function (i.e., `std::strtof`,
- `std::strtod`, or `std::strtold`) based on the type supplied via the
- first parameter. Set this to @a static_cast<number_float_t>(nullptr).
+ standard floating point number parsing function based on the type
+ supplied via the first parameter. Set this to @a
+ static_cast<number_float_t*>(nullptr).
@param[in] type the @ref number_float_t in use
@@ -7801,14 +8280,42 @@ basic_json_parser_64:
return std::strtold(reinterpret_cast<typename string_t::const_pointer>(m_start), endptr);
}
- /// @copydoc str_to_float_t
- double str_to_float_t(double*, char** endptr) const
+ /*!
+ @brief parse floating point number
+
+ This function (and its overloads) serves to select the most approprate
+ standard floating point number parsing function based on the type
+ supplied via the first parameter. Set this to @a
+ static_cast<number_float_t*>(nullptr).
+
+ @param[in] type the @ref number_float_t in use
+
+ @param[in,out] endptr recieves a pointer to the first character after
+ the number
+
+ @return the floating point number
+ */
+ double str_to_float_t(double* /* type */, char** endptr) const
{
return std::strtod(reinterpret_cast<typename string_t::const_pointer>(m_start), endptr);
}
- /// @copydoc str_to_float_t
- float str_to_float_t(float*, char** endptr) const
+ /*!
+ @brief parse floating point number
+
+ This function (and its overloads) serves to select the most approprate
+ standard floating point number parsing function based on the type
+ supplied via the first parameter. Set this to @a
+ static_cast<number_float_t*>(nullptr).
+
+ @param[in] type the @ref number_float_t in use
+
+ @param[in,out] endptr recieves a pointer to the first character after
+ the number
+
+ @return the floating point number
+ */
+ float str_to_float_t(float* /* type */, char** endptr) const
{
return std::strtof(reinterpret_cast<typename string_t::const_pointer>(m_start), endptr);
}
@@ -7816,30 +8323,107 @@ basic_json_parser_64:
/*!
@brief return number value for number tokens
- This function translates the last token into a floating point number.
- The pointer m_start points to the beginning of the parsed number. We
- pass this pointer to std::strtod which sets endptr to the first
- character past the converted number. If this pointer is not the same as
- m_cursor, then either more or less characters have been used during the
- comparison. This can happen for inputs like "01" which will be treated
- like number 0 followed by number 1.
+ This function translates the last token into the most appropriate
+ number type (either integer, unsigned integer or floating point),
+ which is passed back to the caller via the result parameter.
+
+ This function parses the integer component up to the radix point or
+ exponent while collecting information about the 'floating point
+ representation', which it stores in the result parameter. If there is
+ no radix point or exponent, and the number can fit into a @ref
+ number_integer_t or @ref number_unsigned_t then it sets the result
+ parameter accordingly.
- @return the result of the number conversion or NAN if the conversion
- read past the current token. The latter case needs to be treated by the
- caller function.
+ If the number is a floating point number the number is then parsed
+ using @a std:strtod (or @a std:strtof or @a std::strtold).
- @throw std::range_error if passed value is out of range
+ @param[out] result @ref basic_json object to receive the number, or
+ NAN if the conversion read past the current token. The latter case
+ needs to be treated by the caller function.
*/
- number_float_t get_number() const
+ void get_number(basic_json& result) const
{
- // conversion
- typename string_t::value_type* endptr;
assert(m_start != nullptr);
- number_float_t float_val = str_to_float_t(static_cast<number_float_t*>(nullptr), &endptr);
- // return float_val if the whole number was translated and NAN
- // otherwise
- return (reinterpret_cast<lexer_char_t*>(endptr) == m_cursor) ? float_val : NAN;
+ const lexer::lexer_char_t* curptr = m_start;
+
+ // 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;
+
+ // 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<uint64_t>((std::numeric_limits<number_integer_t>::max)()) + 1;
+ curptr++;
+ }
+ else
+ {
+ type = value_t::number_unsigned;
+ max = static_cast<uint64_t>((std::numeric_limits<number_unsigned_t>::max)());
+ }
+
+ // count the significant figures
+ for (; curptr < m_cursor; curptr++)
+ {
+ // quickly skip tests if a digit
+ if (*curptr < '0' || *curptr > '9')
+ {
+ 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;
+ 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 - 0x30;
+
+ // test for overflow
+ if (temp < value || temp > max)
+ {
+ // overflow
+ type = value_t::number_float;
+ }
+ else
+ {
+ // no overflow - save it
+ value = temp;
+ }
+ }
+ }
+
+ // 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<number_integer_t>(value);
+ }
+ else
+ {
+ // parse with strtod
+ result.m_value.number_float = str_to_float_t(static_cast<number_float_t*>(nullptr), NULL);
+ }
+
+ // save the type
+ result.m_type = type;
}
private:
@@ -7868,7 +8452,7 @@ basic_json_parser_64:
{
public:
/// constructor for strings
- parser(const string_t& s, parser_callback_t cb = nullptr)
+ parser(const string_t& s, parser_callback_t cb = nullptr) noexcept
: callback(cb), m_lexer(s)
{
// read first token
@@ -7876,7 +8460,7 @@ basic_json_parser_64:
}
/// a parser reading from an input stream
- parser(std::istream& _is, parser_callback_t cb = nullptr)
+ parser(std::istream& _is, parser_callback_t cb = nullptr) noexcept
: callback(cb), m_lexer(&_is)
{
// read first token
@@ -8069,32 +8653,8 @@ basic_json_parser_64:
case lexer::token_type::value_number:
{
- result.m_value = m_lexer.get_number();
-
- // NAN is returned if token could not be translated
- // completely
- if (std::isnan(result.m_value.number_float))
- {
- throw std::invalid_argument(std::string("parse error - ") +
- m_lexer.get_token() + " is not a number");
- }
-
+ m_lexer.get_number(result);
get_token();
-
- // check if conversion loses precision (special case -0.0 always loses precision)
- const auto int_val = static_cast<number_integer_t>(result.m_value.number_float);
- if (result.m_value.number_float == static_cast<number_float_t>(int_val) and
- result.m_value.number_integer != json_value(-0.0f).number_integer)
- {
- // we would not lose precision -> return int
- result.m_type = value_t::number_integer;
- result.m_value = int_val;
- }
- else
- {
- // we would lose precision -> return float
- result.m_type = value_t::number_float;
- }
break;
}
@@ -8113,7 +8673,7 @@ basic_json_parser_64:
}
/// get next token from lexer
- typename lexer::token_type get_token()
+ typename lexer::token_type get_token() noexcept
{
last_token = m_lexer.scan();
return last_token;
@@ -8152,6 +8712,1232 @@ basic_json_parser_64:
/// the lexer
lexer m_lexer;
};
+
+ public:
+ /*!
+ @brief JSON Pointer
+
+ A JSON pointer defines a string syntax for identifying a specific value
+ within a JSON document. It can be used with functions `at` and
+ `operator[]`. Furthermore, JSON pointers are the base for JSON patches.
+
+ @sa [RFC 6901](https://tools.ietf.org/html/rfc6901)
+
+ @since version 2.0.0
+ */
+ class json_pointer
+ {
+ /// allow basic_json to access private members
+ friend class basic_json;
+
+ public:
+ /*!
+ @brief create JSON pointer
+
+ Create a JSON pointer according to the syntax described in
+ [Section 3 of RFC6901](https://tools.ietf.org/html/rfc6901#section-3).
+
+ @param[in] s string representing the JSON pointer; if omitted, the
+ empty string is assumed which references the whole JSON
+ value
+
+ @throw std::domain_error if reference token is nonempty and does not
+ begin with a slash (`/`); example: `"JSON pointer must be empty or
+ begin with /"`
+ @throw std::domain_error if a tilde (`~`) is not followed by `0`
+ (representing `~`) or `1` (representing `/`); example: `"escape error:
+ ~ must be followed with 0 or 1"`
+
+ @liveexample{The example shows the construction several valid JSON
+ pointers as well as the exceptional behavior.,json_pointer}
+
+ @since version 2.0.0
+ */
+ 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:
+ @code {.cpp}
+ ptr == json_pointer(ptr.to_string());
+ @endcode
+
+ @return a string representation of the JSON pointer
+
+ @liveexample{The example shows the result of `to_string`.,
+ json_pointer__to_string}
+
+ @since version 2.0.0
+ */
+ std::string to_string() const noexcept
+ {
+ std::string result;
+
+ for (const auto& reference_token : reference_tokens)
+ {
+ result += "/" + escape(reference_token);
+ }
+
+ return result;
+ }
+
+ /// @copydoc to_string()
+ operator std::string() const
+ {
+ return to_string();
+ }
+
+ private:
+ /// remove and return last reference pointer
+ std::string pop_back()
+ {
+ if (is_root())
+ {
+ throw std::domain_error("JSON pointer has no parent");
+ }
+
+ auto last = reference_tokens.back();
+ reference_tokens.pop_back();
+ return last;
+ }
+
+ /// return whether pointer points to the root document
+ bool is_root() const
+ {
+ return reference_tokens.empty();
+ }
+
+ 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
+ */
+ 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)
+ {
+ switch (result->m_type)
+ {
+ case value_t::null:
+ {
+ 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;
+ }
+
+ 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<size_type>(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");
+ }
+ }
+ }
+
+ return *result;
+ }
+
+ /*!
+ @brief return a reference to the pointed to value
+
+ @param[in] ptr a JSON value
+
+ @return reference to the JSON value pointed to by the JSON pointer
+
+ @complexity Linear in the length of the JSON pointer.
+
+ @throw std::out_of_range if the JSON pointer can not be resolved
+ @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)
+ {
+ switch (ptr->m_type)
+ {
+ case value_t::object:
+ {
+ // use unchecked object access
+ ptr = &ptr->operator[](reference_token);
+ break;
+ }
+
+ case value_t::array:
+ {
+ // 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<size_type>(std::stoi(reference_token)));
+ }
+ break;
+ }
+
+ default:
+ {
+ throw std::out_of_range("unresolved reference token '" + reference_token + "'");
+ }
+ }
+ }
+
+ return *ptr;
+ }
+
+ reference get_checked(pointer ptr) const
+ {
+ for (const auto& reference_token : reference_tokens)
+ {
+ switch (ptr->m_type)
+ {
+ case value_t::object:
+ {
+ // note: at performs range check
+ ptr = &ptr->at(reference_token);
+ break;
+ }
+
+ case value_t::array:
+ {
+ 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");
+ }
+
+ // 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'");
+ }
+
+ // note: at performs range check
+ ptr = &ptr->at(static_cast<size_type>(std::stoi(reference_token)));
+ break;
+ }
+
+ default:
+ {
+ throw std::out_of_range("unresolved reference token '" + reference_token + "'");
+ }
+ }
+ }
+
+ return *ptr;
+ }
+
+ /*!
+ @brief return a const reference to the pointed to value
+
+ @param[in] ptr a JSON value
+
+ @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)
+ {
+ switch (ptr->m_type)
+ {
+ case value_t::object:
+ {
+ // use unchecked object access
+ ptr = &ptr->operator[](reference_token);
+ break;
+ }
+
+ case value_t::array:
+ {
+ 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");
+ }
+
+ // 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'");
+ }
+
+ // use unchecked array access
+ ptr = &ptr->operator[](static_cast<size_type>(std::stoi(reference_token)));
+ break;
+ }
+
+ default:
+ {
+ throw std::out_of_range("unresolved reference token '" + reference_token + "'");
+ }
+ }
+ }
+
+ return *ptr;
+ }
+
+ const_reference get_checked(const_pointer ptr) const
+ {
+ for (const auto& reference_token : reference_tokens)
+ {
+ switch (ptr->m_type)
+ {
+ case value_t::object:
+ {
+ // note: at performs range check
+ ptr = &ptr->at(reference_token);
+ break;
+ }
+
+ case value_t::array:
+ {
+ 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");
+ }
+
+ // 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'");
+ }
+
+ // note: at performs range check
+ ptr = &ptr->at(static_cast<size_type>(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<std::string> split(std::string reference_string)
+ {
+ std::vector<std::string> result;
+
+ // 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 '/'");
+ }
+
+ // 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);
+
+ // 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
+ (reference_token[pos + 1] != '0' and
+ reference_token[pos + 1] != '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);
+ }
+
+ return result;
+ }
+
+ private:
+ /*!
+ @brief replace all occurrences of a substring by another string
+
+ @param[in,out] s the string to manipulate
+ @param[in] f the substring to replace with @a t
+ @param[out] t the string to replace @a f
+
+ @return The string @a s where all occurrences of @a f are replaced
+ with @a t.
+
+ @pre The search string @a f must not be empty.
+
+ @since version 2.0.0
+ */
+ 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
+ );
+ }
+
+ /// 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", "~");
+ }
+
+ /*!
+ @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)
+ {
+ case value_t::array:
+ {
+ if (value.m_value.array->empty())
+ {
+ // 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;
+ }
+
+ case value_t::object:
+ {
+ if (value.m_value.object->empty())
+ {
+ // flatten empty object as null
+ result[reference_string] = nullptr;
+ }
+ else
+ {
+ // 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;
+ }
+
+ 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())
+ {
+ throw std::domain_error("only objects can be unflattened");
+ }
+
+ basic_json result;
+
+ // iterate the JSON object values
+ for (const auto& element : *value.m_value.object)
+ {
+ 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;
+ }
+
+ return result;
+ }
+
+ private:
+ /// the reference tokens
+ std::vector<std::string> reference_tokens {};
+ };
+
+ //////////////////////////
+ // JSON Pointer support //
+ //////////////////////////
+
+ /// @name JSON Pointer functions
+ /// @{
+
+ /*!
+ @brief access specified element via JSON Pointer
+
+ Uses a JSON pointer to retrieve a reference to the respective JSON value.
+ No bound checking is performed. Similar to @ref operator[](const typename
+ object_t::key_type&), `null` values are created in arrays and objects if
+ necessary.
+
+ In particular:
+ - If the JSON pointer points to an object key that does not exist, it
+ is created an filled with a `null` value before a reference to it
+ is returned.
+ - If the JSON pointer points to an array index that does not exist, it
+ is created an filled with a `null` value before a reference to it
+ is returned. All indices between the current maximum and the given
+ index are also filled with `null`.
+ - The special value `-` is treated as a synonym for the index past the
+ end.
+
+ @param[in] ptr a JSON pointer
+
+ @return reference to the element pointed to by @a ptr
+
+ @complexity Constant.
+
+ @throw std::out_of_range if the JSON pointer can not be resolved
+ @throw std::domain_error if an array index begins with '0'
+ @throw std::invalid_argument if an array index was not a number
+
+ @liveexample{The behavior is shown in the example.,operatorjson_pointer}
+
+ @since version 2.0.0
+ */
+ 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.
+ No bound checking is performed. The function does not change the JSON
+ value; no `null` values are created. In particular, the the special value
+ `-` yields an exception.
+
+ @param[in] ptr JSON pointer to the desired element
+
+ @return const reference to the element pointed to by @a ptr
+
+ @complexity Constant.
+
+ @throw std::out_of_range if the JSON pointer can not be resolved
+ @throw std::domain_error if an array index begins with '0'
+ @throw std::invalid_argument if an array index was not a number
+
+ @liveexample{The behavior is shown in the example.,operatorjson_pointer_const}
+
+ @since version 2.0.0
+ */
+ 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,
+ with bounds checking.
+
+ @param[in] ptr JSON pointer to the desired element
+
+ @return reference to the element pointed to by @a ptr
+
+ @complexity Constant.
+
+ @throw std::out_of_range if the JSON pointer can not be resolved
+ @throw std::domain_error if an array index begins with '0'
+ @throw std::invalid_argument if an array index was not a number
+
+ @liveexample{The behavior is shown in the example.,at_json_pointer}
+
+ @since version 2.0.0
+ */
+ 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
+ ptr, with bounds checking.
+
+ @param[in] ptr JSON pointer to the desired element
+
+ @return reference to the element pointed to by @a ptr
+
+ @complexity Constant.
+
+ @throw std::out_of_range if the JSON pointer can not be resolved
+ @throw std::domain_error if an array index begins with '0'
+ @throw std::invalid_argument if an array index was not a number
+
+ @liveexample{The behavior is shown in the example.,at_json_pointer_const}
+
+ @since version 2.0.0
+ */
+ 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
+ 6901](https://tools.ietf.org/html/rfc6901)) and whose values are all
+ primitive. The original JSON value can be restored using the @ref
+ unflatten() function.
+
+ @return an object that maps JSON pointers to primitve values
+
+ @note Empty objects and arrays are flattened to `null` and will not be
+ reconstructed correctly by the @ref unflatten() function.
+
+ @complexity Linear in the size the JSON value.
+
+ @liveexample{The following code shows how a JSON object is flattened to an
+ object whose keys consist of JSON pointers.,flatten}
+
+ @sa @ref unflatten() for the reverse function
+
+ @since version 2.0.0
+ */
+ 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
+ flattened before using the @ref flatten() function. The JSON value must
+ meet certain constraints:
+ 1. The value must be an object.
+ 2. The keys must be JSON pointers (see
+ [RFC 6901](https://tools.ietf.org/html/rfc6901))
+ 3. The mapped values must be primitive JSON types.
+
+ @return the original JSON from a flattened version
+
+ @note Empty objects and arrays are flattened by @ref flatten() to `null`
+ values and can not unflattened to their original type. Apart from
+ this example, for a JSON value `j`, the following is always true:
+ `j == j.flatten().unflatten()`.
+
+ @complexity Linear in the size the JSON value.
+
+ @liveexample{The following code shows how a flattened JSON object is
+ unflattened into the original nested JSON object.,unflatten}
+
+ @sa @ref flatten() for the reverse function
+
+ @since version 2.0.0
+ */
+ basic_json unflatten() const
+ {
+ return json_pointer::unflatten(*this);
+ }
+
+ /// @}
+
+ //////////////////////////
+ // JSON Patch functions //
+ //////////////////////////
+
+ /// @name JSON Patch functions
+ /// @{
+
+ /*!
+ @brief applies a JSON patch
+
+ [JSON Patch](http://jsonpatch.com) defines a JSON document structure for
+ expressing a sequence of operations to apply to a JSON) document. With
+ this funcion, a JSON Patch is applied to the current JSON value by
+ executing all operations from the patch.
+
+ @param[in] json_patch JSON patch document
+ @return patched document
+
+ @note The application of a patch is atomic: Either all operations succeed
+ and the patched document is returned or an exception is thrown. In
+ any case, the original value is not changed: the patch is applied
+ to a copy of the value.
+
+ @throw std::out_of_range if a JSON pointer inside the patch could not
+ be resolved successfully in the current JSON value; example: `"key baz
+ not found"`
+ @throw invalid_argument if the JSON patch is malformed (e.g., mandatory
+ attributes are missing); example: `"operation add must have member path"`
+
+ @complexity Linear in the size of the JSON value and the length of the
+ JSON patch. As usually only a fraction of the JSON value is affected by
+ the patch, the complexity can usually be neglected.
+
+ @liveexample{The following code shows how a JSON patch is applied to a
+ value.,patch}
+
+ @sa @ref diff -- create a JSON patch by comparing two JSON values
+
+ @sa [RFC 6902 (JSON Patch)](https://tools.ietf.org/html/rfc6902)
+ @sa [RFC 6901 (JSON Pointer)](https://tools.ietf.org/html/rfc6901)
+
+ @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)
+ {
+ 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;
+ }
+
+ return patch_operations::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
+ {
+ // make sure the top element of the pointer exists
+ json_pointer top_pointer = ptr.top();
+ if (top_pointer != ptr)
+ {
+ basic_json& x = result.at(top_pointer);
+ }
+
+ // get reference to parent of JSON pointer ptr
+ const auto last_path = ptr.pop_back();
+ basic_json& parent = result[ptr];
+
+ switch (parent.m_type)
+ {
+ case value_t::null:
+ case value_t::object:
+ {
+ // use operator[] to add value
+ parent[last_path] = val;
+ break;
+ }
+
+ case value_t::array:
+ {
+ if (last_path == "-")
+ {
+ // special case: append to back
+ parent.push_back(val);
+ }
+ else
+ {
+ const auto idx = std::stoi(last_path);
+ if (static_cast<size_type>(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<difference_type>(idx), val);
+ }
+ }
+ break;
+ }
+
+ 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<size_type>(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&
+ {
+ // find value
+ auto it = val.m_value.object->find(member);
+
+ // context-sensitive error message
+ const auto error_msg = (op == "op") ? "operation" : "operation '" + op + "'";
+
+ // check if desired value is present
+ if (it == val.m_value.object->end())
+ {
+ throw std::invalid_argument(error_msg + " must have member '" + member + "'");
+ }
+
+ // 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 + "'");
+ }
+
+ // no error: return value
+ return it->second;
+ };
+
+ // type check
+ if (not val.is_object())
+ {
+ 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))
+ {
+ case patch_operations::add:
+ {
+ operation_add(ptr, get_value("add", "value", false));
+ break;
+ }
+
+ case patch_operations::remove:
+ {
+ operation_remove(ptr);
+ break;
+ }
+
+ case patch_operations::replace:
+ {
+ // the "path" location must exist - use at()
+ result.at(ptr) = get_value("replace", "value", false);
+ break;
+ }
+
+ case patch_operations::move:
+ {
+ 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;
+ }
+
+ case patch_operations::copy:
+ {
+ 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;
+ }
+
+ 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
+ }
+
+ // 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;
+ }
+
+ /*!
+ @brief creates a diff as a JSON patch
+
+ Creates a [JSON Patch](http://jsonpatch.com) so that value @a source can
+ be changed into the value @a target by calling @ref patch function.
+
+ @invariant For two JSON values @a source and @a target, the following code
+ yields always `true`:
+ @code {.cpp}
+ source.patch(diff(source, target)) == target;
+ @endcode
+
+ @note Currently, only `remove`, `add`, and `replace` operations are
+ generated.
+
+ @param[in] source JSON value to copare from
+ @param[in] target JSON value to copare against
+ @param[in] path helper value to create JSON pointers
+
+ @return a JSON patch to convert the @a source to @a target
+
+ @complexity Linear in the lengths of @a source and @a target.
+
+ @liveexample{The following code shows how a JSON patch is created as a
+ diff for two JSON values.,diff}
+
+ @sa @ref patch -- apply a JSON patch
+
+ @sa [RFC 6902 (JSON Patch)](https://tools.ietf.org/html/rfc6902)
+
+ @since version 2.0.0
+ */
+ static basic_json diff(const basic_json& source,
+ const basic_json& target,
+ std::string path = "")
+ {
+ // the patch
+ basic_json result(value_t::array);
+
+ // if the values are the same, return empty patch
+ if (source == target)
+ {
+ return result;
+ }
+
+ if (source.type() != target.type())
+ {
+ // different types: replace value
+ result.push_back(
+ {
+ {"op", "replace"},
+ {"path", path},
+ {"value", target}
+ });
+ }
+ else
+ {
+ switch (source.type())
+ {
+ case value_t::array:
+ {
+ // 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
+
+ // remove my remaining elements
+ const auto end_index = static_cast<difference_type>(result.size());
+ while (i < source.size())
+ {
+ // 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(
+ {
+ {"op", "add"},
+ {"path", path + "/" + std::to_string(i)},
+ {"value", target[i]}
+ });
+ ++i;
+ }
+
+ break;
+ }
+
+ case value_t::object:
+ {
+ // first pass: traverse this object's elements
+ for (auto it = source.begin(); it != source.end(); ++it)
+ {
+ // 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
+ {
+ // 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())
+ {
+ // 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;
+ }
+
+ default:
+ {
+ // both primitive type: replace value
+ result.push_back(
+ {
+ {"op", "replace"},
+ {"path", path},
+ {"value", target}
+ });
+ break;
+ }
+ }
+ }
+
+ return result;
+ }
+
+ /// @}
};
@@ -8162,8 +9948,8 @@ basic_json_parser_64:
/*!
@brief default JSON class
-This type is the default specialization of the @ref basic_json class which uses
-the standard template types.
+This type is the default specialization of the @ref basic_json class which
+uses the standard template types.
@since version 1.0.0
*/
@@ -8171,9 +9957,9 @@ using json = basic_json<>;
}
-/////////////////////////
-// nonmember functions //
-/////////////////////////
+///////////////////////
+// nonmember support //
+///////////////////////
// specialization of std::swap, and std::hash
namespace std
@@ -8214,9 +10000,9 @@ struct hash<nlohmann::json>
/*!
@brief user-defined string literal for JSON values
-This operator implements a user-defined string literal for JSON objects. It can
-be used by adding \p "_json" to a string literal and returns a JSON object if
-no parse error occurred.
+This operator implements a user-defined string literal for JSON objects. It
+can be used by adding \p "_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
@return a JSON object
@@ -8228,6 +10014,16 @@ inline nlohmann::json operator "" _json(const char* s, std::size_t)
return nlohmann::json::parse(reinterpret_cast<const nlohmann::json::string_t::value_type*>(s));
}
+/*!
+@brief user-defined string literal for JSON pointer
+
+@since version 2.0.0
+*/
+inline nlohmann::json::json_pointer operator "" _json_pointer(const char* s, std::size_t)
+{
+ return nlohmann::json::json_pointer(s);
+}
+
// restore GCC/clang diagnostic settings
#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__)
#pragma GCC diagnostic pop