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:45 +0300
committerGitHub Actions <action@github.com>2020-06-28 14:43:45 +0300
commit87a5a56e6acd268cc8018c0e9dd6ae23fed276f9 (patch)
tree85fb659061759975d237a2ffadc5d6eac95a8e0f
parent83d5cb38342f030a533ba1ec963b716411cb353e (diff)
Upstream release v2.0.2v2.0.2
-rw-r--r--README.md2
-rw-r--r--include/nlohmann/json.hpp2109
2 files changed, 1255 insertions, 856 deletions
diff --git a/README.md b/README.md
index 886dc1b..97cc275 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 v2.0.1)
+ GIT_TAG v2.0.2)
FetchContent_GetProperties(json)
if(NOT json_POPULATED)
diff --git a/include/nlohmann/json.hpp b/include/nlohmann/json.hpp
index 35bdd29..878fb89 100644
--- a/include/nlohmann/json.hpp
+++ b/include/nlohmann/json.hpp
@@ -1,7 +1,7 @@
/*
__ _____ _____ _____
__| | __| | | | JSON for Modern C++
-| | |__ | | | | | | version 2.0.1
+| | |__ | | | | | | version 2.0.2
|_____|_____|_____|_|___| https://github.com/nlohmann/json
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
@@ -32,11 +32,10 @@ SOFTWARE.
#include <algorithm>
#include <array>
#include <cassert>
-#include <cerrno>
#include <ciso646>
#include <cmath>
#include <cstddef>
-#include <cstdio>
+#include <cstdint>
#include <cstdlib>
#include <functional>
#include <initializer_list>
@@ -44,8 +43,10 @@ SOFTWARE.
#include <iostream>
#include <iterator>
#include <limits>
+#include <locale>
#include <map>
#include <memory>
+#include <numeric>
#include <sstream>
#include <stdexcept>
#include <string>
@@ -53,6 +54,19 @@ SOFTWARE.
#include <utility>
#include <vector>
+// exclude unsupported compilers
+#if defined(__clang__)
+ #define CLANG_VERSION (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__)
+ #if CLANG_VERSION < 30400
+ #error "unsupported Clang version - see https://github.com/nlohmann/json#supported-compilers"
+ #endif
+#elif defined(__GNUC__)
+ #define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
+ #if GCC_VERSION < 40900
+ #error "unsupported GCC version - see https://github.com/nlohmann/json#supported-compilers"
+ #endif
+#endif
+
// disable float-equal warnings on GCC/clang
#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__)
#pragma GCC diagnostic push
@@ -76,7 +90,13 @@ namespace
{
/*!
@brief Helper to determine whether there's a key_type for T.
+
+Thus helper is used to tell associative containers apart from other containers
+such as sequence containers. For instance, `std::map` passes the test as it
+contains a `mapped_type`, whereas `std::vector` fails the test.
+
@sa http://stackoverflow.com/a/7728728/266378
+@since version 1.0.0
*/
template<typename T>
struct has_mapped_type
@@ -90,11 +110,18 @@ struct has_mapped_type
/*!
@brief helper class to create locales with decimal point
+
+This struct is used a default locale during the JSON serialization. JSON
+requires the decimal point to be `.`, so this function overloads the
+`do_decimal_point()` function to return `.`. This function is called by
+float-to-string conversions to retrieve the decimal separator between integer
+and fractional parts.
+
@sa https://github.com/nlohmann/json/issues/51#issuecomment-86869315
+@since version 2.0.0
*/
-class DecimalSeparator : public std::numpunct<char>
+struct DecimalSeparator : std::numpunct<char>
{
- protected:
char do_decimal_point() const
{
return '.';
@@ -163,6 +190,13 @@ default)
JSON values can be used like STL containers and provide reverse iterator
access.
+@invariant The member variables @a m_value and @a m_type have the following
+relationship:
+- If `m_type == value_t::object`, then `m_value.object != nullptr`.
+- If `m_type == value_t::array`, then `m_value.array != nullptr`.
+- If `m_type == value_t::string`, then `m_value.string != nullptr`.
+The invariants are checked by member function assert_invariant().
+
@internal
@note ObjectType trick from http://stackoverflow.com/a/9860911
@endinternal
@@ -188,13 +222,8 @@ class basic_json
{
private:
/// workaround type for MSVC
- using basic_json_t = basic_json<ObjectType,
- ArrayType,
- StringType,
- BooleanType,
- NumberIntegerType,
- NumberUnsignedType,
- NumberFloatType,
+ using basic_json_t = basic_json<ObjectType, ArrayType, StringType,
+ BooleanType, NumberIntegerType, NumberUnsignedType, NumberFloatType,
AllocatorType>;
public:
@@ -207,6 +236,8 @@ class basic_json
/////////////////////
/// @name container types
+ /// The canonic container types to use @ref basic_json like any other STL
+ /// container.
/// @{
/// the type of elements in a basic_json container
@@ -256,6 +287,8 @@ class basic_json
///////////////////////////
/// @name JSON value data types
+ /// The data types to store a JSON value. These types are derived from
+ /// the template arguments passed to class @ref basic_json.
/// @{
/*!
@@ -358,7 +391,7 @@ class basic_json
@tparam ArrayType container type to store arrays (e.g., `std::vector` or
`std::list`)
- @tparam AllocatorType allocator to use for arrays (e.g., `std::allocator`)
+ @tparam AllocatorType allocator to use for arrays (e.g., `std::allocator`)
#### Default type
@@ -595,15 +628,14 @@ class basic_json
> 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.
+ 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
@@ -691,7 +723,19 @@ class basic_json
This enumeration collects the different JSON types. It is internally used
to distinguish the stored values, and the functions @ref is_null(), @ref
is_object(), @ref is_array(), @ref is_string(), @ref is_boolean(), @ref
- is_number(), and @ref is_discarded() rely on it.
+ is_number() (with @ref is_number_integer(), @ref is_number_unsigned(), and
+ @ref is_number_float()), @ref is_discarded(), @ref is_primitive(), and
+ @ref is_structured() rely on it.
+
+ @note There are three enumeration entries (number_integer,
+ number_unsigned, and number_float), because the library distinguishes
+ these three types for numbers: @ref number_unsigned_t is used for unsigned
+ integers, @ref number_integer_t is used for signed integers, and @ref
+ number_float_t is used for floating-point numbers or to approximate
+ integers which do not fit in the limits of their respective type.
+
+ @sa @ref basic_json(const value_t value_type) -- create a JSON value with
+ the default value for a given type
@since version 1.0.0
*/
@@ -702,7 +746,7 @@ class basic_json
array, ///< array (ordered collection of values)
string, ///< string value
boolean, ///< boolean value
- number_integer, ///< number value (integer)
+ number_integer, ///< number value (signed integer)
number_unsigned, ///< number value (unsigned integer)
number_float, ///< number value (floating-point)
discarded ///< discarded by the the parser callback function
@@ -722,6 +766,7 @@ class basic_json
};
std::unique_ptr<T, decltype(deleter)> object(alloc.allocate(1), deleter);
alloc.construct(object.get(), std::forward<Args>(args)...);
+ assert(object.get() != nullptr);
return object.release();
}
@@ -732,7 +777,24 @@ class basic_json
/*!
@brief a JSON value
- The actual storage for a JSON value of the @ref basic_json class.
+ The actual storage for a JSON value of the @ref basic_json class. This
+ union combines the different storage types for the JSON value types
+ defined in @ref value_t.
+
+ JSON type | value_t type | used type
+ --------- | --------------- | ------------------------
+ object | object | pointer to @ref object_t
+ array | array | pointer to @ref array_t
+ string | string | pointer to @ref string_t
+ boolean | boolean | @ref boolean_t
+ number | number_integer | @ref number_integer_t
+ number | number_unsigned | @ref number_unsigned_t
+ number | number_float | @ref number_float_t
+ null | null | *no value is stored*
+
+ @note Variable-length types (objects, arrays, and strings) are stored as
+ pointers. The size of the union should not exceed 64 bits if the default
+ value types are used.
@since version 1.0.0
*/
@@ -836,6 +898,21 @@ class basic_json
}
};
+ /*!
+ @brief checks the class invariants
+
+ This function asserts the class invariants. It needs to be called at the
+ end of every constructor to make sure that created objects respect the
+ invariant. Furthermore, it has to be called each time the type of a JSON
+ value is changed, because the invariant expresses a relationship between
+ @a m_type and @a m_value.
+ */
+ void assert_invariant() const
+ {
+ assert(m_type != value_t::object or m_value.object != nullptr);
+ assert(m_type != value_t::array or m_value.array != nullptr);
+ assert(m_type != value_t::string or m_value.string != nullptr);
+ }
public:
//////////////////////////
@@ -848,6 +925,8 @@ class basic_json
This enumeration lists the parser events that can trigger calling a
callback function of type @ref parser_callback_t during parsing.
+ @image html callback_events.png "Example when certain parse events are triggered"
+
@since version 1.0.0
*/
enum class parse_event_t : uint8_t
@@ -870,12 +949,13 @@ class basic_json
@brief per-element parser callback type
With a parser callback function, the result of parsing a JSON text can be
- 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.
+ influenced. When passed to @ref parse(std::istream&, const
+ parser_callback_t) or @ref parse(const string_t&, const 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.
We distinguish six scenarios (determined by the event type) in which the
callback function can be called. The following table describes the values
@@ -890,6 +970,8 @@ class basic_json
parse_event_t::array_end | the parser read `]` and finished processing a JSON array | depth of the parent of the JSON array | the parsed JSON array
parse_event_t::value | the parser finished reading a JSON value | depth of the value | the parsed JSON value
+ @image html callback_events.png "Example when certain parse events are triggered"
+
Discarding a value (i.e., returning `false`) has different effects
depending on the context in which function was called:
@@ -915,7 +997,9 @@ class basic_json
@since version 1.0.0
*/
- using parser_callback_t = std::function<bool(int depth, parse_event_t event, basic_json& parsed)>;
+ using parser_callback_t = std::function<bool(int depth,
+ parse_event_t event,
+ basic_json& parsed)>;
//////////////////
@@ -923,6 +1007,8 @@ class basic_json
//////////////////
/// @name constructors and destructors
+ /// Constructors of class @ref basic_json, copy/move constructor, copy
+ /// assignment, static functions creating objects, and the destructor.
/// @{
/*!
@@ -966,7 +1052,9 @@ class basic_json
*/
basic_json(const value_t value_type)
: m_type(value_type), m_value(value_type)
- {}
+ {
+ assert_invariant();
+ }
/*!
@brief create a null object (implicitly)
@@ -974,6 +1062,9 @@ class basic_json
Create a `null` JSON value. This is the implicit version of the `null`
value constructor as it takes no parameters.
+ @note The class invariant is satisfied, because it poses no requirements
+ for null values.
+
@complexity Constant.
@exceptionsafety No-throw guarantee: this constructor never throws
@@ -1018,7 +1109,9 @@ class basic_json
*/
basic_json(std::nullptr_t) noexcept
: basic_json(value_t::null)
- {}
+ {
+ assert_invariant();
+ }
/*!
@brief create an object (explicit)
@@ -1041,7 +1134,9 @@ class basic_json
*/
basic_json(const object_t& val)
: m_type(value_t::object), m_value(val)
- {}
+ {
+ assert_invariant();
+ }
/*!
@brief create an object (implicit)
@@ -1080,6 +1175,7 @@ class basic_json
using std::begin;
using std::end;
m_value.object = create<object_t>(begin(val), end(val));
+ assert_invariant();
}
/*!
@@ -1103,7 +1199,9 @@ class basic_json
*/
basic_json(const array_t& val)
: m_type(value_t::array), m_value(val)
- {}
+ {
+ assert_invariant();
+ }
/*!
@brief create an array (implicit)
@@ -1147,6 +1245,7 @@ class basic_json
using std::begin;
using std::end;
m_value.array = create<array_t>(begin(val), end(val));
+ assert_invariant();
}
/*!
@@ -1172,7 +1271,9 @@ class basic_json
*/
basic_json(const string_t& val)
: m_type(value_t::string), m_value(val)
- {}
+ {
+ assert_invariant();
+ }
/*!
@brief create a string (explicit)
@@ -1196,7 +1297,9 @@ class basic_json
*/
basic_json(const typename string_t::value_type* val)
: basic_json(string_t(val))
- {}
+ {
+ assert_invariant();
+ }
/*!
@brief create a string (implicit)
@@ -1227,7 +1330,9 @@ class basic_json
= 0>
basic_json(const CompatibleStringType& val)
: basic_json(string_t(val))
- {}
+ {
+ assert_invariant();
+ }
/*!
@brief create a boolean (explicit)
@@ -1245,7 +1350,9 @@ class basic_json
*/
basic_json(boolean_t val) noexcept
: m_type(value_t::boolean), m_value(val)
- {}
+ {
+ assert_invariant();
+ }
/*!
@brief create an integer number (explicit)
@@ -1278,7 +1385,9 @@ class basic_json
= 0>
basic_json(const number_integer_t val) noexcept
: m_type(value_t::number_integer), m_value(val)
- {}
+ {
+ assert_invariant();
+ }
/*!
@brief create an integer number from an enum type (explicit)
@@ -1308,7 +1417,9 @@ class basic_json
basic_json(const int val) noexcept
: m_type(value_t::number_integer),
m_value(static_cast<number_integer_t>(val))
- {}
+ {
+ assert_invariant();
+ }
/*!
@brief create an integer number (implicit)
@@ -1345,15 +1456,17 @@ class basic_json
basic_json(const CompatibleNumberIntegerType val) noexcept
: m_type(value_t::number_integer),
m_value(static_cast<number_integer_t>(val))
- {}
+ {
+ assert_invariant();
+ }
/*!
@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.
+ @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
@@ -1372,7 +1485,9 @@ class basic_json
= 0>
basic_json(const number_unsigned_t val) noexcept
: m_type(value_t::number_unsigned), m_value(val)
- {}
+ {
+ assert_invariant();
+ }
/*!
@brief create an unsigned number (implicit)
@@ -1404,7 +1519,9 @@ class basic_json
basic_json(const CompatibleNumberUnsignedType val) noexcept
: m_type(value_t::number_unsigned),
m_value(static_cast<number_unsigned_t>(val))
- {}
+ {
+ assert_invariant();
+ }
/*!
@brief create a floating-point number (explicit)
@@ -1417,8 +1534,8 @@ class basic_json
disallows NaN values:
> 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.
+ In case the parameter @a val is not a number, a JSON null value is created
+ instead.
@complexity Constant.
@@ -1439,6 +1556,8 @@ class basic_json
m_type = value_t::null;
m_value = json_value();
}
+
+ assert_invariant();
}
/*!
@@ -1479,7 +1598,9 @@ class basic_json
>
basic_json(const CompatibleNumberFloatType val) noexcept
: basic_json(number_float_t(val))
- {}
+ {
+ assert_invariant();
+ }
/*!
@brief create a container (array or object) from an initializer list
@@ -1491,21 +1612,21 @@ class basic_json
1. If the list is empty, an empty JSON object value `{}` is created.
2. If the list consists of pairs whose first element is a string, a JSON
- object value is created where the first elements of the pairs are treated
- as keys and the second elements are as values.
+ object value is created where the first elements of the pairs are
+ treated as keys and the second elements are as values.
3. In all other cases, an array is created.
The rules aim to create the best fit between a C++ initializer list and
JSON values. The rationale is as follows:
1. The empty initializer list is written as `{}` which is exactly an empty
- JSON object.
+ JSON object.
2. C++ has now way of describing mapped types other than to list a list of
- pairs. As JSON requires that keys must be of type string, rule 2 is the
- weakest constraint one can pose on initializer lists to interpret them as
- an object.
+ pairs. As JSON requires that keys must be of type string, rule 2 is the
+ weakest constraint one can pose on initializer lists to interpret them
+ as an object.
3. In all other cases, the initializer list could not be interpreted as
- JSON object type, so interpreting it as JSON array type is safe.
+ JSON object type, so interpreting it as JSON array type is safe.
With the rules described above, the following JSON values cannot be
expressed by an initializer list:
@@ -1554,22 +1675,13 @@ class basic_json
bool type_deduction = true,
value_t manual_type = value_t::array)
{
- // the initializer list could describe an object
- bool is_an_object = true;
-
// check if each element is an array with two elements whose first
// element is a string
- for (const auto& element : init)
+ bool is_an_object = std::all_of(init.begin(), init.end(),
+ [](const basic_json & element)
{
- if (not element.is_array() or element.size() != 2
- or not element[0].is_string())
- {
- // we found an element that makes it impossible to use the
- // initializer list as object
- is_an_object = false;
- break;
- }
- }
+ return element.is_array() and element.size() == 2 and element[0].is_string();
+ });
// adjust type if type deduction is not wanted
if (not type_deduction)
@@ -1593,12 +1705,10 @@ class basic_json
m_type = value_t::object;
m_value = value_t::object;
- assert(m_value.object != nullptr);
-
- for (auto& element : init)
+ std::for_each(init.begin(), init.end(), [this](const basic_json & element)
{
m_value.object->emplace(*(element[0].m_value.string), element[1]);
- }
+ });
}
else
{
@@ -1606,6 +1716,8 @@ class basic_json
m_type = value_t::array;
m_value.array = create<array_t>(init);
}
+
+ assert_invariant();
}
/*!
@@ -1710,6 +1822,7 @@ class basic_json
: m_type(value_t::array)
{
m_value.array = create<array_t>(cnt, val);
+ assert_invariant();
}
/*!
@@ -1730,6 +1843,8 @@ class basic_json
@param[in] first begin of the range to copy from (included)
@param[in] last end of the range to copy from (excluded)
+ @pre Iterators @a first and @a last must be initialized.
+
@throw std::domain_error if iterators are not compatible; that is, do not
belong to the same JSON value; example: `"iterators are not compatible"`
@throw std::out_of_range if iterators are for a primitive type (number,
@@ -1752,14 +1867,20 @@ class basic_json
std::is_same<InputIT, typename basic_json_t::const_iterator>::value
, int>::type
= 0>
- basic_json(InputIT first, InputIT last) : m_type(first.m_object->m_type)
+ basic_json(InputIT first, InputIT last)
{
+ assert(first.m_object != nullptr);
+ assert(last.m_object != nullptr);
+
// make sure iterator fits the current value
if (first.m_object != last.m_object)
{
throw std::domain_error("iterators are not compatible");
}
+ // copy type from first iterator
+ m_type = first.m_object->m_type;
+
// check if iterator range is complete for primitive values
switch (m_type)
{
@@ -1786,35 +1907,30 @@ class basic_json
{
case value_t::number_integer:
{
- assert(first.m_object != nullptr);
m_value.number_integer = first.m_object->m_value.number_integer;
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);
m_value.number_float = first.m_object->m_value.number_float;
break;
}
case value_t::boolean:
{
- assert(first.m_object != nullptr);
m_value.boolean = first.m_object->m_value.boolean;
break;
}
case value_t::string:
{
- assert(first.m_object != nullptr);
m_value = *first.m_object->m_value.string;
break;
}
@@ -1833,10 +1949,11 @@ class basic_json
default:
{
- assert(first.m_object != nullptr);
throw std::domain_error("cannot use construct with iterators from " + first.m_object->type_name());
}
}
+
+ assert_invariant();
}
/*!
@@ -1859,9 +1976,10 @@ class basic_json
@since version 2.0.0
*/
- explicit basic_json(std::istream& i, parser_callback_t cb = nullptr)
+ explicit basic_json(std::istream& i, const parser_callback_t cb = nullptr)
{
*this = parser(i, cb).parse();
+ assert_invariant();
}
///////////////////////////////////////
@@ -1893,25 +2011,25 @@ class basic_json
basic_json(const basic_json& other)
: m_type(other.m_type)
{
+ // check of passed value is valid
+ other.assert_invariant();
+
switch (m_type)
{
case value_t::object:
{
- assert(other.m_value.object != nullptr);
m_value = *other.m_value.object;
break;
}
case value_t::array:
{
- assert(other.m_value.array != nullptr);
m_value = *other.m_value.array;
break;
}
case value_t::string:
{
- assert(other.m_value.string != nullptr);
m_value = *other.m_value.string;
break;
}
@@ -1945,6 +2063,8 @@ class basic_json
break;
}
}
+
+ assert_invariant();
}
/*!
@@ -1969,9 +2089,14 @@ class basic_json
: m_type(std::move(other.m_type)),
m_value(std::move(other.m_value))
{
+ // check that passed value is valid
+ other.assert_invariant();
+
// invalidate payload
other.m_type = value_t::null;
other.m_value = {};
+
+ assert_invariant();
}
/*!
@@ -2004,9 +2129,14 @@ class basic_json
std::is_nothrow_move_assignable<json_value>::value
)
{
+ // check that passed value is valid
+ other.assert_invariant();
+
using std::swap;
swap(m_type, other.m_type);
swap(m_value, other.m_value);
+
+ assert_invariant();
return *this;
}
@@ -2027,6 +2157,8 @@ class basic_json
*/
~basic_json()
{
+ assert_invariant();
+
switch (m_type)
{
case value_t::object:
@@ -2069,19 +2201,20 @@ class basic_json
///////////////////////
/// @name object inspection
+ /// Functions to inspect the type of a JSON value.
/// @{
/*!
@brief serialization
Serialization function for JSON values. The function tries to mimic
- Python's @p json.dumps() function, and currently supports its @p indent
+ Python's `json.dumps()` function, and currently supports its @a indent
parameter.
- @param[in] indent if indent is nonnegative, then array elements and object
+ @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
- representation
+ `0` will only insert newlines. `-1` (the default) selects the most compact
+ representation.
@return string containing the serialization of the JSON value
@@ -2100,6 +2233,12 @@ class basic_json
// fix locale problems
ss.imbue(std::locale(std::locale(), new DecimalSeparator));
+ // 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
+ ss.precision(std::numeric_limits<double>::digits10);
+
if (indent >= 0)
{
dump(ss, true, static_cast<unsigned int>(indent));
@@ -2484,7 +2623,6 @@ class basic_json
{
if (is_object())
{
- assert(m_value.object != nullptr);
return T(m_value.object->begin(), m_value.object->end());
}
else
@@ -2498,7 +2636,6 @@ class basic_json
{
if (is_object())
{
- assert(m_value.object != nullptr);
return *(m_value.object);
}
else
@@ -2521,7 +2658,6 @@ class basic_json
if (is_array())
{
T to_vector;
- assert(m_value.array != nullptr);
std::transform(m_value.array->begin(), m_value.array->end(),
std::inserter(to_vector, to_vector.end()), [](basic_json i)
{
@@ -2546,7 +2682,6 @@ class basic_json
if (is_array())
{
std::vector<T> to_vector;
- assert(m_value.array != nullptr);
to_vector.reserve(m_value.array->size());
std::transform(m_value.array->begin(), m_value.array->end(),
std::inserter(to_vector, to_vector.end()), [](basic_json i)
@@ -2571,7 +2706,6 @@ class basic_json
{
if (is_array())
{
- assert(m_value.array != nullptr);
return T(m_value.array->begin(), m_value.array->end());
}
else
@@ -2585,7 +2719,6 @@ class basic_json
{
if (is_array())
{
- assert(m_value.array != nullptr);
return *(m_value.array);
}
else
@@ -2603,7 +2736,6 @@ class basic_json
{
if (is_string())
{
- assert(m_value.string != nullptr);
return *m_value.string;
}
else
@@ -2749,8 +2881,10 @@ class basic_json
template<typename ReferenceType, typename ThisType>
static ReferenceType get_ref_impl(ThisType& obj)
{
- // delegate the call to get_ptr<>()
+ // helper type
using PointerType = typename std::add_pointer<ReferenceType>::type;
+
+ // delegate the call to get_ptr<>()
auto ptr = obj.template get_ptr<PointerType>();
if (ptr != nullptr)
@@ -2767,6 +2901,7 @@ class basic_json
public:
/// @name value access
+ /// Direct access to the stored value of a JSON value.
/// @{
/*!
@@ -2817,7 +2952,8 @@ class basic_json
Explicit pointer access to the internally stored JSON value. No copies are
made.
- @warning The pointer becomes invalid if the underlying JSON object changes.
+ @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,
@@ -2872,7 +3008,8 @@ class basic_json
@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,
- @ref number_unsigned_t, or @ref number_float_t.
+ @ref number_unsigned_t, or @ref number_float_t. Enforced by a static
+ assertion.
@return pointer to the internally stored JSON value if the requested
pointer type @a PointerType fits to the JSON value; `nullptr` otherwise
@@ -2892,6 +3029,21 @@ class basic_json
, int>::type = 0>
PointerType get_ptr() noexcept
{
+ // get the type of the PointerType (remove pointer and const)
+ using pointee_t = typename std::remove_const<typename
+ std::remove_pointer<typename
+ std::remove_const<PointerType>::type>::type>::type;
+ // make sure the type matches the allowed types
+ static_assert(
+ std::is_same<object_t, pointee_t>::value
+ or std::is_same<array_t, pointee_t>::value
+ or std::is_same<string_t, pointee_t>::value
+ or std::is_same<boolean_t, pointee_t>::value
+ or std::is_same<number_integer_t, pointee_t>::value
+ or std::is_same<number_unsigned_t, pointee_t>::value
+ or std::is_same<number_float_t, pointee_t>::value
+ , "incompatible pointer type");
+
// delegate the call to get_impl_ptr<>()
return get_impl_ptr(static_cast<PointerType>(nullptr));
}
@@ -2907,6 +3059,21 @@ class basic_json
, int>::type = 0>
constexpr const PointerType get_ptr() const noexcept
{
+ // get the type of the PointerType (remove pointer and const)
+ using pointee_t = typename std::remove_const<typename
+ std::remove_pointer<typename
+ std::remove_const<PointerType>::type>::type>::type;
+ // make sure the type matches the allowed types
+ static_assert(
+ std::is_same<object_t, pointee_t>::value
+ or std::is_same<array_t, pointee_t>::value
+ or std::is_same<string_t, pointee_t>::value
+ or std::is_same<boolean_t, pointee_t>::value
+ or std::is_same<number_integer_t, pointee_t>::value
+ or std::is_same<number_unsigned_t, pointee_t>::value
+ or std::is_same<number_float_t, pointee_t>::value
+ , "incompatible pointer type");
+
// delegate the call to get_impl_ptr<>() const
return get_impl_ptr(static_cast<const PointerType>(nullptr));
}
@@ -2922,7 +3089,7 @@ class basic_json
@tparam ReferenceType reference type; must be a reference to @ref array_t,
@ref object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, or
- @ref number_float_t.
+ @ref number_float_t. Enforced by static assertion.
@return reference to the internally stored JSON value if the requested
reference type @a ReferenceType fits to the JSON value; throws
@@ -3012,6 +3179,7 @@ class basic_json
////////////////////
/// @name element access
+ /// Access to the JSON value.
/// @{
/*!
@@ -3043,7 +3211,6 @@ class basic_json
{
try
{
- assert(m_value.array != nullptr);
return m_value.array->at(idx);
}
catch (std::out_of_range&)
@@ -3087,7 +3254,6 @@ class basic_json
{
try
{
- assert(m_value.array != nullptr);
return m_value.array->at(idx);
}
catch (std::out_of_range&)
@@ -3135,7 +3301,6 @@ class basic_json
{
try
{
- assert(m_value.object != nullptr);
return m_value.object->at(key);
}
catch (std::out_of_range&)
@@ -3183,7 +3348,6 @@ class basic_json
{
try
{
- assert(m_value.object != nullptr);
return m_value.object->at(key);
}
catch (std::out_of_range&)
@@ -3230,16 +3394,18 @@ class basic_json
{
m_type = value_t::array;
m_value.array = create<array_t>();
+ assert_invariant();
}
// 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)
+ // fill up array with null values if given idx is outside range
+ if (idx >= m_value.array->size())
{
- m_value.array->push_back(basic_json());
+ m_value.array->insert(m_value.array->end(),
+ idx - m_value.array->size() + 1,
+ basic_json());
}
return m_value.array->operator[](idx);
@@ -3274,7 +3440,6 @@ class basic_json
// const operator[] only works for arrays
if (is_array())
{
- assert(m_value.array != nullptr);
return m_value.array->operator[](idx);
}
else
@@ -3317,12 +3482,12 @@ class basic_json
{
m_type = value_t::object;
m_value.object = create<object_t>();
+ assert_invariant();
}
// operator[] only works for objects
if (is_object())
{
- assert(m_value.object != nullptr);
return m_value.object->operator[](key);
}
else
@@ -3363,7 +3528,6 @@ class basic_json
// const operator[] only works for objects
if (is_object())
{
- assert(m_value.object != nullptr);
assert(m_value.object->find(key) != m_value.object->end());
return m_value.object->find(key)->second;
}
@@ -3476,12 +3640,12 @@ class basic_json
{
m_type = value_t::object;
m_value = value_t::object;
+ assert_invariant();
}
// at only works for objects
if (is_object())
{
- assert(m_value.object != nullptr);
return m_value.object->operator[](key);
}
else
@@ -3523,7 +3687,6 @@ class basic_json
// at only works for objects
if (is_object())
{
- assert(m_value.object != nullptr);
assert(m_value.object->find(key) != m_value.object->end());
return m_value.object->find(key)->second;
}
@@ -3536,8 +3699,8 @@ class basic_json
/*!
@brief access specified object element with default value
- Returns either a copy of an object's element at the specified key @a key or
- a given default value if no element with key @a key exists.
+ Returns either a copy of an object's element at the specified key @a key
+ or a given default value if no element with key @a key exists.
The function is basically equivalent to executing
@code {.cpp}
@@ -3609,7 +3772,7 @@ class basic_json
/*!
@brief overload for a default value of type const char*
- @copydoc basic_json::value()
+ @copydoc basic_json::value(const typename object_t::key_type&, ValueType) const
*/
string_t value(const typename object_t::key_type& key, const char* default_value) const
{
@@ -3617,6 +3780,81 @@ class basic_json
}
/*!
+ @brief access specified object element via JSON Pointer with default value
+
+ Returns either a copy of an object's element at the specified key @a key
+ or a given default value if no element with key @a key exists.
+
+ The function is basically equivalent to executing
+ @code {.cpp}
+ try {
+ return at(ptr);
+ } catch(std::out_of_range) {
+ return default_value;
+ }
+ @endcode
+
+ @note Unlike @ref at(const json_pointer&), this function does not throw
+ if the given key @a key was not found.
+
+ @param[in] ptr a JSON pointer to the element to access
+ @param[in] default_value the value to return if @a ptr found no value
+
+ @tparam ValueType type compatible to JSON values, for instance `int` for
+ JSON integer numbers, `bool` for JSON booleans, or `std::vector` types for
+ JSON arrays. Note the type of the expected value at @a key and the default
+ value @a default_value must be compatible.
+
+ @return copy of the element at key @a key or @a default_value if @a key
+ is not found
+
+ @throw std::domain_error if JSON is not an object; example: `"cannot use
+ value() with null"`
+
+ @complexity Logarithmic in the size of the container.
+
+ @liveexample{The example below shows how object elements can be queried
+ with a default value.,basic_json__value_ptr}
+
+ @sa @ref operator[](const json_pointer&) for unchecked access by reference
+
+ @since version 2.0.2
+ */
+ template <class ValueType, typename
+ std::enable_if<
+ std::is_convertible<basic_json_t, ValueType>::value
+ , int>::type = 0>
+ ValueType value(const json_pointer& ptr, ValueType default_value) const
+ {
+ // at only works for objects
+ if (is_object())
+ {
+ // if pointer resolves a value, return it or use default value
+ try
+ {
+ return ptr.get_checked(this);
+ }
+ catch (std::out_of_range&)
+ {
+ return default_value;
+ }
+ }
+ else
+ {
+ throw std::domain_error("cannot use value() with " + type_name());
+ }
+ }
+
+ /*!
+ @brief overload for a default value of type const char*
+ @copydoc basic_json::value(const json_pointer&, ValueType) const
+ */
+ string_t value(const json_pointer& ptr, const char* default_value) const
+ {
+ return value(ptr, string_t(default_value));
+ }
+
+ /*!
@brief access the first element
Returns a reference to the first element in the container. For a JSON
@@ -3775,24 +4013,25 @@ class basic_json
if (is_string())
{
- delete m_value.string;
+ AllocatorType<string_t> alloc;
+ alloc.destroy(m_value.string);
+ alloc.deallocate(m_value.string, 1);
m_value.string = nullptr;
}
m_type = value_t::null;
+ assert_invariant();
break;
}
case value_t::object:
{
- assert(m_value.object != nullptr);
result.m_it.object_iterator = m_value.object->erase(pos.m_it.object_iterator);
break;
}
case value_t::array:
{
- assert(m_value.array != nullptr);
result.m_it.array_iterator = m_value.array->erase(pos.m_it.array_iterator);
break;
}
@@ -3883,17 +4122,19 @@ class basic_json
if (is_string())
{
- delete m_value.string;
+ AllocatorType<string_t> alloc;
+ alloc.destroy(m_value.string);
+ alloc.deallocate(m_value.string, 1);
m_value.string = nullptr;
}
m_type = value_t::null;
+ assert_invariant();
break;
}
case value_t::object:
{
- assert(m_value.object != nullptr);
result.m_it.object_iterator = m_value.object->erase(first.m_it.object_iterator,
last.m_it.object_iterator);
break;
@@ -3901,7 +4142,6 @@ class basic_json
case value_t::array:
{
- assert(m_value.array != nullptr);
result.m_it.array_iterator = m_value.array->erase(first.m_it.array_iterator,
last.m_it.array_iterator);
break;
@@ -3950,7 +4190,6 @@ class basic_json
// this erase only works for objects
if (is_object())
{
- assert(m_value.object != nullptr);
return m_value.object->erase(key);
}
else
@@ -3993,7 +4232,6 @@ class basic_json
throw std::out_of_range("array index " + std::to_string(idx) + " is out of range");
}
- assert(m_value.array != nullptr);
m_value.array->erase(m_value.array->begin() + static_cast<difference_type>(idx));
}
else
@@ -4036,7 +4274,6 @@ class basic_json
if (is_object())
{
- assert(m_value.object != nullptr);
result.m_it.object_iterator = m_value.object->find(key);
}
@@ -4053,7 +4290,6 @@ class basic_json
if (is_object())
{
- assert(m_value.object != nullptr);
result.m_it.object_iterator = m_value.object->find(key);
}
@@ -4081,7 +4317,6 @@ class basic_json
size_type count(typename object_t::key_type key) const
{
// return 0 for all nonobject types
- assert(not is_object() or m_value.object != nullptr);
return is_object() ? m_value.object->count(key) : 0;
}
@@ -4423,6 +4658,10 @@ class basic_json
object | result of function `object_t::empty()`
array | result of function `array_t::empty()`
+ @note This function does not return whether a string stored as JSON value
+ is empty - it returns whether the JSON container itself is empty which is
+ false in the case of a string.
+
@complexity Constant, as long as @ref array_t and @ref object_t satisfy
the Container concept; that is, their `empty()` functions have constant
complexity.
@@ -4452,13 +4691,13 @@ class basic_json
case value_t::array:
{
- assert(m_value.array != nullptr);
+ // delegate call to array_t::empty()
return m_value.array->empty();
}
case value_t::object:
{
- assert(m_value.object != nullptr);
+ // delegate call to object_t::empty()
return m_value.object->empty();
}
@@ -4486,6 +4725,10 @@ class basic_json
object | result of function object_t::size()
array | result of function array_t::size()
+ @note This function does not return the length of a string stored as JSON
+ value - it returns the number of elements in the JSON value which is 1 in
+ the case of a string.
+
@complexity Constant, as long as @ref array_t and @ref object_t satisfy
the Container concept; that is, their size() functions have constant
complexity.
@@ -4516,13 +4759,13 @@ class basic_json
case value_t::array:
{
- assert(m_value.array != nullptr);
+ // delegate call to array_t::size()
return m_value.array->size();
}
case value_t::object:
{
- assert(m_value.object != nullptr);
+ // delegate call to object_t::size()
return m_value.object->size();
}
@@ -4576,13 +4819,13 @@ class basic_json
{
case value_t::array:
{
- assert(m_value.array != nullptr);
+ // delegate call to array_t::max_size()
return m_value.array->max_size();
}
case value_t::object:
{
- assert(m_value.object != nullptr);
+ // delegate call to object_t::max_size()
return m_value.object->max_size();
}
@@ -4659,21 +4902,18 @@ class basic_json
case value_t::string:
{
- assert(m_value.string != nullptr);
m_value.string->clear();
break;
}
case value_t::array:
{
- assert(m_value.array != nullptr);
m_value.array->clear();
break;
}
case value_t::object:
{
- assert(m_value.object != nullptr);
m_value.object->clear();
break;
}
@@ -4718,10 +4958,10 @@ class basic_json
{
m_type = value_t::array;
m_value = value_t::array;
+ assert_invariant();
}
// add element to array (move semantics)
- assert(m_value.array != nullptr);
m_value.array->push_back(std::move(val));
// invalidate object
val.m_type = value_t::null;
@@ -4754,10 +4994,10 @@ class basic_json
{
m_type = value_t::array;
m_value = value_t::array;
+ assert_invariant();
}
// add element to array
- assert(m_value.array != nullptr);
m_value.array->push_back(val);
}
@@ -4804,10 +5044,10 @@ class basic_json
{
m_type = value_t::object;
m_value = value_t::object;
+ assert_invariant();
}
// add element to array
- assert(m_value.object != nullptr);
m_value.object->insert(val);
}
@@ -4904,7 +5144,6 @@ class basic_json
// insert to array and return iterator
iterator result(this);
- assert(m_value.array != nullptr);
result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, val);
return result;
}
@@ -4960,7 +5199,6 @@ class basic_json
// insert to array and return iterator
iterator result(this);
- assert(m_value.array != nullptr);
result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, cnt, val);
return result;
}
@@ -5027,7 +5265,6 @@ class basic_json
// insert to array and return iterator
iterator result(this);
- assert(m_value.array != nullptr);
result.m_it.array_iterator = m_value.array->insert(
pos.m_it.array_iterator,
first.m_it.array_iterator,
@@ -5075,7 +5312,6 @@ class basic_json
// insert to array and return iterator
iterator result(this);
- assert(m_value.array != nullptr);
result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, ilist);
return result;
}
@@ -5106,6 +5342,7 @@ class basic_json
{
std::swap(m_type, other.m_type);
std::swap(m_value, other.m_value);
+ assert_invariant();
}
/*!
@@ -5133,7 +5370,6 @@ class basic_json
// swap only works for arrays
if (is_array())
{
- assert(m_value.array != nullptr);
std::swap(*(m_value.array), other);
}
else
@@ -5167,7 +5403,6 @@ class basic_json
// swap only works for objects
if (is_object())
{
- assert(m_value.object != nullptr);
std::swap(*(m_value.object), other);
}
else
@@ -5201,7 +5436,6 @@ class basic_json
// swap only works for strings
if (is_string())
{
- assert(m_value.string != nullptr);
std::swap(*(m_value.string), other);
}
else
@@ -5288,14 +5522,10 @@ class basic_json
{
case value_t::array:
{
- assert(lhs.m_value.array != nullptr);
- assert(rhs.m_value.array != nullptr);
return *lhs.m_value.array == *rhs.m_value.array;
}
case value_t::object:
{
- assert(lhs.m_value.object != nullptr);
- assert(rhs.m_value.object != nullptr);
return *lhs.m_value.object == *rhs.m_value.object;
}
case value_t::null:
@@ -5304,8 +5534,6 @@ class basic_json
}
case value_t::string:
{
- assert(lhs.m_value.string != nullptr);
- assert(rhs.m_value.string != nullptr);
return *lhs.m_value.string == *rhs.m_value.string;
}
case value_t::boolean:
@@ -5478,14 +5706,10 @@ class basic_json
{
case value_t::array:
{
- assert(lhs.m_value.array != nullptr);
- assert(rhs.m_value.array != nullptr);
return *lhs.m_value.array < *rhs.m_value.array;
}
case value_t::object:
{
- assert(lhs.m_value.object != nullptr);
- assert(rhs.m_value.object != nullptr);
return *lhs.m_value.object < *rhs.m_value.object;
}
case value_t::null:
@@ -5494,8 +5718,6 @@ class basic_json
}
case value_t::string:
{
- assert(lhs.m_value.string != nullptr);
- assert(rhs.m_value.string != nullptr);
return *lhs.m_value.string < *rhs.m_value.string;
}
case value_t::boolean:
@@ -5637,6 +5859,10 @@ class basic_json
`std::setw(4)` on @a o sets the indentation level to `4` and the
serialization result is the same as calling `dump(4)`.
+ @note During serializaion, the locale and the precision of the output
+ stream @a o are changed. The original values are restored when the
+ function returns.
+
@param[in,out] o stream to serialize to
@param[in] j JSON value to serialize
@@ -5657,14 +5883,23 @@ class basic_json
// reset width to 0 for subsequent calls to this stream
o.width(0);
+
// fix locale problems
- auto old_locale = o.imbue(std::locale(std::locale(), new DecimalSeparator));
+ const auto old_locale = o.imbue(std::locale(std::locale(), new DecimalSeparator));
+ // set precision
+
+ // 6, 15 or 16 digits of precision allows round-trip IEEE 754
+ // string->float->string, string->double->string or string->long
+ // double->string; to be safe, we read this value from
+ // std::numeric_limits<number_float_t>::digits10
+ const auto old_precision = o.precision(std::numeric_limits<double>::digits10);
// do the actual serialization
j.dump(o, pretty_print, static_cast<unsigned int>(indentation));
- // reset locale
+ // reset locale and precision
o.imbue(old_locale);
+ o.precision(old_precision);
return o;
}
@@ -5706,12 +5941,13 @@ class basic_json
@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
+ @sa @ref parse(std::istream&, const parser_callback_t) for a version that
+ reads from an input stream
@since version 1.0.0
*/
- static basic_json parse(const string_t& s, parser_callback_t cb = nullptr)
+ static basic_json parse(const string_t& s,
+ const parser_callback_t cb = nullptr)
{
return parser(s, cb).parse();
}
@@ -5735,20 +5971,22 @@ class basic_json
@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&, const parser_callback_t) for a version
+ that reads from a string
@since version 1.0.0
*/
- static basic_json parse(std::istream& i, parser_callback_t cb = nullptr)
+ static basic_json parse(std::istream& i,
+ const parser_callback_t cb = nullptr)
{
return parser(i, cb).parse();
}
/*!
- @copydoc parse(std::istream&, parser_callback_t)
+ @copydoc parse(std::istream&, const parser_callback_t)
*/
- static basic_json parse(std::istream&& i, parser_callback_t cb = nullptr)
+ static basic_json parse(std::istream&& i,
+ const parser_callback_t cb = nullptr)
{
return parser(i, cb).parse();
}
@@ -5771,8 +6009,8 @@ class basic_json
@liveexample{The example below shows how a JSON value is constructed by
reading a serialization from a stream.,operator_deserialize}
- @sa parse(std::istream&, parser_callback_t) for a variant with a parser
- callback function to filter values while parsing
+ @sa parse(std::istream&, const parser_callback_t) for a variant with a
+ parser callback function to filter values while parsing
@since version 1.0.0
*/
@@ -5800,8 +6038,19 @@ class basic_json
// convenience functions //
///////////////////////////
- /// return the type as string
- string_t type_name() const noexcept
+ /*!
+ @brief return the type as string
+
+ Returns the type name as string to be used in error messages - usually to
+ indicate that a function was called on a wrong JSON type.
+
+ @return basically a string representation of a the @ref m_type member
+
+ @complexity Constant.
+
+ @since version 1.0.0
+ */
+ std::string type_name() const
{
switch (m_type)
{
@@ -5832,9 +6081,8 @@ class basic_json
*/
static std::size_t extra_space(const string_t& s) noexcept
{
- std::size_t result = 0;
-
- for (const auto& c : s)
+ return std::accumulate(s.begin(), s.end(), size_t{},
+ [](size_t res, typename string_t::value_type c)
{
switch (c)
{
@@ -5847,8 +6095,7 @@ class basic_json
case '\t':
{
// from c (1 byte) to \x (2 bytes)
- result += 1;
- break;
+ return res + 1;
}
default:
@@ -5856,14 +6103,15 @@ class basic_json
if (c >= 0x00 and c <= 0x1f)
{
// from c (1 byte) to \uxxxx (6 bytes)
- result += 5;
+ return res + 5;
+ }
+ else
+ {
+ return res;
}
- break;
}
}
- }
-
- return result;
+ });
}
/*!
@@ -5957,16 +6205,15 @@ class basic_json
{
// convert a number 0..15 to its hex representation
// (0..f)
- const auto hexify = [](const int v) -> char
+ static const char hexify[16] =
{
- return (v < 10)
- ? ('0' + static_cast<char>(v))
- : ('a' + static_cast<char>((v - 10) & 0x1f));
+ '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
};
// print character c as \uxxxx
for (const char m :
- { 'u', '0', '0', hexify(c >> 4), hexify(c & 0x0f)
+ { 'u', '0', '0', hexify[c >> 4], hexify[c & 0x0f]
})
{
result[++pos] = m;
@@ -6016,8 +6263,6 @@ class basic_json
{
case value_t::object:
{
- assert(m_value.object != nullptr);
-
if (m_value.object->empty())
{
o << "{}";
@@ -6058,8 +6303,6 @@ class basic_json
case value_t::array:
{
- assert(m_value.array != nullptr);
-
if (m_value.array->empty())
{
o << "[]";
@@ -6098,7 +6341,6 @@ class basic_json
case value_t::string:
{
- assert(m_value.string != nullptr);
o << string_t("\"") << escape_string(*m_value.string) << "\"";
return;
}
@@ -6130,13 +6372,7 @@ class basic_json
}
else
{
- // 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
- o << std::setprecision(std::numeric_limits<double>::digits10)
- << m_value.number_float;
+ o << m_value.number_float;
}
return;
}
@@ -6353,6 +6589,12 @@ class basic_json
This class implements a const iterator for the @ref basic_json class. From
this class, the @ref iterator class is derived.
+ @note An iterator is called *initialized* when a pointer to a JSON value
+ has been set (e.g., by a constructor or a copy assignment). If the
+ iterator is default-constructed, it is *uninitialized* and most
+ methods are undefined. The library uses assertions to detect calls
+ on uninitialized iterators.
+
@requirement The class satisfies the following concept requirements:
- [RandomAccessIterator](http://en.cppreference.com/w/cpp/concept/RandomAccessIterator):
The iterator that can be moved to point (forward and backward) to any
@@ -6380,7 +6622,12 @@ class basic_json
/// default constructor
const_iterator() = default;
- /// constructor for a given JSON instance
+ /*!
+ @brief constructor for a given JSON instance
+ @param[in] object pointer to a JSON object for this iterator
+ @pre object != nullptr
+ @post The iterator is initialized; i.e. `m_object != nullptr`.
+ */
explicit const_iterator(pointer object) noexcept
: m_object(object)
{
@@ -6408,40 +6655,53 @@ class basic_json
}
}
- /// copy constructor given a nonconst iterator
+ /*!
+ @brief copy constructor given a non-const iterator
+ @param[in] other iterator to copy from
+ @note It is not checked whether @a other is initialized.
+ */
explicit const_iterator(const iterator& other) noexcept
: m_object(other.m_object)
{
- assert(m_object != nullptr);
-
- switch (m_object->m_type)
+ if (m_object != nullptr)
{
- case basic_json::value_t::object:
+ switch (m_object->m_type)
{
- m_it.object_iterator = other.m_it.object_iterator;
- break;
- }
+ case basic_json::value_t::object:
+ {
+ m_it.object_iterator = other.m_it.object_iterator;
+ break;
+ }
- case basic_json::value_t::array:
- {
- m_it.array_iterator = other.m_it.array_iterator;
- break;
- }
+ case basic_json::value_t::array:
+ {
+ m_it.array_iterator = other.m_it.array_iterator;
+ break;
+ }
- default:
- {
- m_it.primitive_iterator = other.m_it.primitive_iterator;
- break;
+ default:
+ {
+ m_it.primitive_iterator = other.m_it.primitive_iterator;
+ break;
+ }
}
}
}
- /// copy constructor
+ /*!
+ @brief copy constructor
+ @param[in] other iterator to copy from
+ @note It is not checked whether @a other is initialized.
+ */
const_iterator(const const_iterator& other) noexcept
: m_object(other.m_object), m_it(other.m_it)
{}
- /// copy assignment
+ /*!
+ @brief copy assignment
+ @param[in,out] other iterator to copy from
+ @note It is not checked whether @a other is initialized.
+ */
const_iterator& operator=(const_iterator other) noexcept(
std::is_nothrow_move_constructible<pointer>::value and
std::is_nothrow_move_assignable<pointer>::value and
@@ -6455,7 +6715,10 @@ class basic_json
}
private:
- /// set the iterator to the first value
+ /*!
+ @brief set the iterator to the first value
+ @pre The iterator is initialized; i.e. `m_object != nullptr`.
+ */
void set_begin() noexcept
{
assert(m_object != nullptr);
@@ -6464,14 +6727,12 @@ class basic_json
{
case basic_json::value_t::object:
{
- assert(m_object->m_value.object != nullptr);
m_it.object_iterator = m_object->m_value.object->begin();
break;
}
case basic_json::value_t::array:
{
- assert(m_object->m_value.array != nullptr);
m_it.array_iterator = m_object->m_value.array->begin();
break;
}
@@ -6491,7 +6752,10 @@ class basic_json
}
}
- /// set the iterator past the last value
+ /*!
+ @brief set the iterator past the last value
+ @pre The iterator is initialized; i.e. `m_object != nullptr`.
+ */
void set_end() noexcept
{
assert(m_object != nullptr);
@@ -6500,14 +6764,12 @@ class basic_json
{
case basic_json::value_t::object:
{
- assert(m_object->m_value.object != nullptr);
m_it.object_iterator = m_object->m_value.object->end();
break;
}
case basic_json::value_t::array:
{
- assert(m_object->m_value.array != nullptr);
m_it.array_iterator = m_object->m_value.array->end();
break;
}
@@ -6521,7 +6783,10 @@ class basic_json
}
public:
- /// return a reference to the value pointed to by the iterator
+ /*!
+ @brief return a reference to the value pointed to by the iterator
+ @pre The iterator is initialized; i.e. `m_object != nullptr`.
+ */
reference operator*() const
{
assert(m_object != nullptr);
@@ -6530,14 +6795,12 @@ class basic_json
{
case basic_json::value_t::object:
{
- assert(m_object->m_value.object);
assert(m_it.object_iterator != m_object->m_value.object->end());
return m_it.object_iterator->second;
}
case basic_json::value_t::array:
{
- assert(m_object->m_value.array);
assert(m_it.array_iterator != m_object->m_value.array->end());
return *m_it.array_iterator;
}
@@ -6561,7 +6824,10 @@ class basic_json
}
}
- /// dereference the iterator
+ /*!
+ @brief dereference the iterator
+ @pre The iterator is initialized; i.e. `m_object != nullptr`.
+ */
pointer operator->() const
{
assert(m_object != nullptr);
@@ -6570,14 +6836,12 @@ class basic_json
{
case basic_json::value_t::object:
{
- assert(m_object->m_value.object);
assert(m_it.object_iterator != m_object->m_value.object->end());
return &(m_it.object_iterator->second);
}
case basic_json::value_t::array:
{
- assert(m_object->m_value.array);
assert(m_it.array_iterator != m_object->m_value.array->end());
return &*m_it.array_iterator;
}
@@ -6596,7 +6860,10 @@ class basic_json
}
}
- /// post-increment (it++)
+ /*!
+ @brief post-increment (it++)
+ @pre The iterator is initialized; i.e. `m_object != nullptr`.
+ */
const_iterator operator++(int)
{
auto result = *this;
@@ -6604,7 +6871,10 @@ class basic_json
return result;
}
- /// pre-increment (++it)
+ /*!
+ @brief pre-increment (++it)
+ @pre The iterator is initialized; i.e. `m_object != nullptr`.
+ */
const_iterator& operator++()
{
assert(m_object != nullptr);
@@ -6613,13 +6883,13 @@ class basic_json
{
case basic_json::value_t::object:
{
- ++m_it.object_iterator;
+ std::advance(m_it.object_iterator, 1);
break;
}
case basic_json::value_t::array:
{
- ++m_it.array_iterator;
+ std::advance(m_it.array_iterator, 1);
break;
}
@@ -6633,7 +6903,10 @@ class basic_json
return *this;
}
- /// post-decrement (it--)
+ /*!
+ @brief post-decrement (it--)
+ @pre The iterator is initialized; i.e. `m_object != nullptr`.
+ */
const_iterator operator--(int)
{
auto result = *this;
@@ -6641,7 +6914,10 @@ class basic_json
return result;
}
- /// pre-decrement (--it)
+ /*!
+ @brief pre-decrement (--it)
+ @pre The iterator is initialized; i.e. `m_object != nullptr`.
+ */
const_iterator& operator--()
{
assert(m_object != nullptr);
@@ -6650,13 +6926,13 @@ class basic_json
{
case basic_json::value_t::object:
{
- --m_it.object_iterator;
+ std::advance(m_it.object_iterator, -1);
break;
}
case basic_json::value_t::array:
{
- --m_it.array_iterator;
+ std::advance(m_it.array_iterator, -1);
break;
}
@@ -6670,7 +6946,10 @@ class basic_json
return *this;
}
- /// comparison: equal
+ /*!
+ @brief comparison: equal
+ @pre The iterator is initialized; i.e. `m_object != nullptr`.
+ */
bool operator==(const const_iterator& other) const
{
// if objects are not the same, the comparison is undefined
@@ -6700,13 +6979,19 @@ class basic_json
}
}
- /// comparison: not equal
+ /*!
+ @brief comparison: not equal
+ @pre The iterator is initialized; i.e. `m_object != nullptr`.
+ */
bool operator!=(const const_iterator& other) const
{
return not operator==(other);
}
- /// comparison: smaller
+ /*!
+ @brief comparison: smaller
+ @pre The iterator is initialized; i.e. `m_object != nullptr`.
+ */
bool operator<(const const_iterator& other) const
{
// if objects are not the same, the comparison is undefined
@@ -6736,25 +7021,37 @@ class basic_json
}
}
- /// comparison: less than or equal
+ /*!
+ @brief comparison: less than or equal
+ @pre The iterator is initialized; i.e. `m_object != nullptr`.
+ */
bool operator<=(const const_iterator& other) const
{
return not other.operator < (*this);
}
- /// comparison: greater than
+ /*!
+ @brief comparison: greater than
+ @pre The iterator is initialized; i.e. `m_object != nullptr`.
+ */
bool operator>(const const_iterator& other) const
{
return not operator<=(other);
}
- /// comparison: greater than or equal
+ /*!
+ @brief comparison: greater than or equal
+ @pre The iterator is initialized; i.e. `m_object != nullptr`.
+ */
bool operator>=(const const_iterator& other) const
{
return not operator<(other);
}
- /// add to iterator
+ /*!
+ @brief add to iterator
+ @pre The iterator is initialized; i.e. `m_object != nullptr`.
+ */
const_iterator& operator+=(difference_type i)
{
assert(m_object != nullptr);
@@ -6768,7 +7065,7 @@ class basic_json
case basic_json::value_t::array:
{
- m_it.array_iterator += i;
+ std::advance(m_it.array_iterator, i);
break;
}
@@ -6782,13 +7079,19 @@ class basic_json
return *this;
}
- /// subtract from iterator
+ /*!
+ @brief subtract from iterator
+ @pre The iterator is initialized; i.e. `m_object != nullptr`.
+ */
const_iterator& operator-=(difference_type i)
{
return operator+=(-i);
}
- /// add to iterator
+ /*!
+ @brief add to iterator
+ @pre The iterator is initialized; i.e. `m_object != nullptr`.
+ */
const_iterator operator+(difference_type i)
{
auto result = *this;
@@ -6796,7 +7099,10 @@ class basic_json
return result;
}
- /// subtract from iterator
+ /*!
+ @brief subtract from iterator
+ @pre The iterator is initialized; i.e. `m_object != nullptr`.
+ */
const_iterator operator-(difference_type i)
{
auto result = *this;
@@ -6804,7 +7110,10 @@ class basic_json
return result;
}
- /// return difference
+ /*!
+ @brief return difference
+ @pre The iterator is initialized; i.e. `m_object != nullptr`.
+ */
difference_type operator-(const const_iterator& other) const
{
assert(m_object != nullptr);
@@ -6828,7 +7137,10 @@ class basic_json
}
}
- /// access to successor
+ /*!
+ @brief access to successor
+ @pre The iterator is initialized; i.e. `m_object != nullptr`.
+ */
reference operator[](difference_type n) const
{
assert(m_object != nullptr);
@@ -6842,7 +7154,7 @@ class basic_json
case basic_json::value_t::array:
{
- return *(m_it.array_iterator + n);
+ return *std::next(m_it.array_iterator, n);
}
case basic_json::value_t::null:
@@ -6864,7 +7176,10 @@ class basic_json
}
}
- /// return the key of an object iterator
+ /*!
+ @brief return the key of an object iterator
+ @pre The iterator is initialized; i.e. `m_object != nullptr`.
+ */
typename object_t::key_type key() const
{
assert(m_object != nullptr);
@@ -6879,7 +7194,10 @@ class basic_json
}
}
- /// return the value of an iterator
+ /*!
+ @brief return the value of an iterator
+ @pre The iterator is initialized; i.e. `m_object != nullptr`.
+ */
reference value() const
{
return operator*();
@@ -7181,7 +7499,7 @@ class basic_json
explicit lexer(const string_t& s) noexcept
: m_stream(nullptr), m_buffer(s)
{
- m_content = reinterpret_cast<const lexer_char_t*>(s.c_str());
+ m_content = reinterpret_cast<const lexer_char_t*>(m_buffer.c_str());
assert(m_content != nullptr);
m_start = m_cursor = m_content;
m_limit = m_content + s.size();
@@ -7192,7 +7510,7 @@ class basic_json
: m_stream(s), m_buffer()
{
assert(m_stream != nullptr);
- getline(*m_stream, m_buffer);
+ std::getline(*m_stream, m_buffer);
m_content = reinterpret_cast<const lexer_char_t*>(m_buffer.c_str());
assert(m_content != nullptr);
m_start = m_cursor = m_content;
@@ -7207,24 +7525,32 @@ class basic_json
lexer operator=(const lexer&) = delete;
/*!
- @brief create a string from a Unicode code point
+ @brief create a string from one or two Unicode code points
+
+ There are two cases: (1) @a codepoint1 is in the Basic Multilingual
+ Plane (U+0000 through U+FFFF) and @a codepoint2 is 0, or (2)
+ @a codepoint1 and @a codepoint2 are a UTF-16 surrogate pair to
+ represent a code point above U+FFFF.
@param[in] codepoint1 the code point (can be high surrogate)
@param[in] codepoint2 the code point (can be low surrogate or 0)
- @return string representation of the code point
+ @return string representation of the code point; the length of the
+ result string is between 1 and 4 characters.
@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""`
+ @complexity Constant.
+
@see <http://en.wikipedia.org/wiki/UTF-8#Sample_code>
*/
static string_t to_unicode(const std::size_t codepoint1,
const std::size_t codepoint2 = 0)
{
- // calculate the codepoint from the given code points
+ // calculate the code point from the given code points
std::size_t codepoint = codepoint1;
// check if codepoint1 is a high surrogate
@@ -7286,7 +7612,7 @@ class basic_json
}
/// return name of values of type token_type (only used for errors)
- static std::string token_type_name(token_type t)
+ static std::string token_type_name(const token_type t)
{
switch (t)
{
@@ -7335,403 +7661,416 @@ class basic_json
function consists of a large block of code with `goto` jumps.
@return the class of the next token read from the buffer
+
+ @complexity Linear in the length of the input.\n
+
+ Proposition: The loop below will always terminate for finite input.\n
+
+ Proof (by contradiction): Assume a finite input. To loop forever, the
+ loop must never hit code with a `break` statement. The only code
+ snippets without a `break` statement are the continue statements for
+ whitespace and byte-order-marks. To loop forever, the input must be an
+ infinite sequence of whitespace or byte-order-marks. This contradicts
+ the assumption of finite input, q.e.d.
*/
token_type scan() noexcept
{
- // pointer for backtracking information
- m_marker = nullptr;
+ while (true)
+ {
+ // pointer for backtracking information
+ m_marker = nullptr;
- // remember the begin of the token
- m_start = m_cursor;
- assert(m_start != nullptr);
+ // remember the begin of the token
+ m_start = m_cursor;
+ assert(m_start != nullptr);
- {
- lexer_char_t yych;
- unsigned int yyaccept = 0;
- static const unsigned char yybm[] =
- {
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 32, 32, 0, 0, 32, 0, 0,
- 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, 128, 128, 128, 128, 128, 128,
- 128, 128, 128, 128, 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 (yybm[0 + yych] & 32)
- {
- goto basic_json_parser_6;
- }
- if (yych <= '\\')
- {
- if (yych <= '-')
- {
- if (yych <= '"')
- {
- if (yych <= 0x00)
- {
- goto basic_json_parser_2;
- }
- if (yych <= '!')
- {
- goto basic_json_parser_4;
- }
- goto basic_json_parser_9;
- }
- else
- {
- if (yych <= '+')
- {
- goto basic_json_parser_4;
- }
- if (yych <= ',')
- {
- goto basic_json_parser_10;
- }
- goto basic_json_parser_12;
- }
+ {
+ lexer_char_t yych;
+ unsigned int yyaccept = 0;
+ static const unsigned char yybm[] =
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 32, 32, 0, 0, 32, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 160, 128, 0, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 192, 192, 192, 192, 192, 192, 192, 192,
+ 192, 192, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 0, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128,
+ };
+ if ((m_limit - m_cursor) < 5)
+ {
+ yyfill(); // LCOV_EXCL_LINE;
}
- else
+ yych = *m_cursor;
+ if (yybm[0 + yych] & 32)
{
- if (yych <= '9')
- {
- if (yych <= '/')
- {
- goto basic_json_parser_4;
- }
- if (yych <= '0')
- {
- goto basic_json_parser_13;
- }
- goto basic_json_parser_15;
- }
- else
- {
- if (yych <= ':')
- {
- goto basic_json_parser_17;
- }
- if (yych == '[')
- {
- goto basic_json_parser_19;
- }
- goto basic_json_parser_4;
- }
+ goto basic_json_parser_6;
}
- }
- else
- {
- if (yych <= 't')
+ if (yych <= '\\')
{
- if (yych <= 'f')
+ if (yych <= '-')
{
- if (yych <= ']')
+ if (yych <= '"')
{
- goto basic_json_parser_21;
+ if (yych <= 0x00)
+ {
+ goto basic_json_parser_2;
+ }
+ if (yych <= '!')
+ {
+ goto basic_json_parser_4;
+ }
+ goto basic_json_parser_9;
}
- if (yych <= 'e')
+ else
{
- goto basic_json_parser_4;
+ if (yych <= '+')
+ {
+ goto basic_json_parser_4;
+ }
+ if (yych <= ',')
+ {
+ goto basic_json_parser_10;
+ }
+ goto basic_json_parser_12;
}
- goto basic_json_parser_23;
}
else
{
- if (yych == 'n')
+ if (yych <= '9')
{
- goto basic_json_parser_24;
+ if (yych <= '/')
+ {
+ goto basic_json_parser_4;
+ }
+ if (yych <= '0')
+ {
+ goto basic_json_parser_13;
+ }
+ goto basic_json_parser_15;
}
- if (yych <= 's')
+ else
{
+ if (yych <= ':')
+ {
+ goto basic_json_parser_17;
+ }
+ if (yych == '[')
+ {
+ goto basic_json_parser_19;
+ }
goto basic_json_parser_4;
}
- goto basic_json_parser_25;
}
}
else
{
- if (yych <= '|')
+ if (yych <= 't')
{
- if (yych == '{')
+ if (yych <= 'f')
{
- goto basic_json_parser_26;
+ if (yych <= ']')
+ {
+ goto basic_json_parser_21;
+ }
+ if (yych <= 'e')
+ {
+ goto basic_json_parser_4;
+ }
+ goto basic_json_parser_23;
+ }
+ else
+ {
+ if (yych == 'n')
+ {
+ goto basic_json_parser_24;
+ }
+ if (yych <= 's')
+ {
+ goto basic_json_parser_4;
+ }
+ goto basic_json_parser_25;
}
- goto basic_json_parser_4;
}
else
{
- if (yych <= '}')
+ if (yych <= '|')
{
- goto basic_json_parser_28;
+ if (yych == '{')
+ {
+ goto basic_json_parser_26;
+ }
+ goto basic_json_parser_4;
}
- if (yych == 0xEF)
+ else
{
- goto basic_json_parser_30;
+ if (yych <= '}')
+ {
+ goto basic_json_parser_28;
+ }
+ if (yych == 0xEF)
+ {
+ goto basic_json_parser_30;
+ }
+ goto basic_json_parser_4;
}
- goto basic_json_parser_4;
}
}
- }
basic_json_parser_2:
- ++m_cursor;
- {
- return token_type::end_of_input;
- }
+ ++m_cursor;
+ {
+ last_token_type = token_type::end_of_input;
+ break;
+ }
basic_json_parser_4:
- ++m_cursor;
+ ++m_cursor;
basic_json_parser_5:
- {
- return token_type::parse_error;
- }
+ {
+ last_token_type = token_type::parse_error;
+ break;
+ }
basic_json_parser_6:
- ++m_cursor;
- if (m_limit <= m_cursor)
- {
- yyfill(); // LCOV_EXCL_LINE;
- }
- yych = *m_cursor;
- if (yybm[0 + yych] & 32)
- {
- goto basic_json_parser_6;
- }
- {
- return scan();
- }
+ ++m_cursor;
+ if (m_limit <= m_cursor)
+ {
+ yyfill(); // LCOV_EXCL_LINE;
+ }
+ yych = *m_cursor;
+ if (yybm[0 + yych] & 32)
+ {
+ goto basic_json_parser_6;
+ }
+ {
+ continue;
+ }
basic_json_parser_9:
- yyaccept = 0;
- yych = *(m_marker = ++m_cursor);
- if (yych <= 0x0F)
- {
- goto basic_json_parser_5;
- }
- goto basic_json_parser_32;
+ yyaccept = 0;
+ yych = *(m_marker = ++m_cursor);
+ if (yych <= 0x1F)
+ {
+ goto basic_json_parser_5;
+ }
+ goto basic_json_parser_32;
basic_json_parser_10:
- ++m_cursor;
- {
- return token_type::value_separator;
- }
+ ++m_cursor;
+ {
+ last_token_type = token_type::value_separator;
+ break;
+ }
basic_json_parser_12:
- yych = *++m_cursor;
- if (yych <= '/')
- {
+ yych = *++m_cursor;
+ if (yych <= '/')
+ {
+ goto basic_json_parser_5;
+ }
+ if (yych <= '0')
+ {
+ goto basic_json_parser_13;
+ }
+ if (yych <= '9')
+ {
+ goto basic_json_parser_15;
+ }
goto basic_json_parser_5;
- }
- if (yych <= '0')
- {
- goto basic_json_parser_13;
- }
- if (yych <= '9')
- {
- goto basic_json_parser_15;
- }
- goto basic_json_parser_5;
basic_json_parser_13:
- yyaccept = 1;
- yych = *(m_marker = ++m_cursor);
- if (yych <= 'D')
- {
- if (yych == '.')
+ yyaccept = 1;
+ yych = *(m_marker = ++m_cursor);
+ if (yych <= 'D')
{
- goto basic_json_parser_37;
+ if (yych == '.')
+ {
+ goto basic_json_parser_37;
+ }
}
- }
- else
- {
- if (yych <= 'E')
+ else
{
- goto basic_json_parser_38;
+ if (yych <= 'E')
+ {
+ goto basic_json_parser_38;
+ }
+ if (yych == 'e')
+ {
+ goto basic_json_parser_38;
+ }
}
- if (yych == 'e')
+basic_json_parser_14:
{
- goto basic_json_parser_38;
+ last_token_type = token_type::value_number;
+ break;
}
- }
-basic_json_parser_14:
- {
- return token_type::value_number;
- }
basic_json_parser_15:
- yyaccept = 1;
- m_marker = ++m_cursor;
- if ((m_limit - m_cursor) < 3)
- {
- yyfill(); // LCOV_EXCL_LINE;
- }
- yych = *m_cursor;
- if (yybm[0 + yych] & 64)
- {
- goto basic_json_parser_15;
- }
- if (yych <= 'D')
- {
- if (yych == '.')
+ yyaccept = 1;
+ m_marker = ++m_cursor;
+ if ((m_limit - m_cursor) < 3)
{
- goto basic_json_parser_37;
+ yyfill(); // LCOV_EXCL_LINE;
}
- goto basic_json_parser_14;
- }
- else
- {
- if (yych <= 'E')
+ yych = *m_cursor;
+ if (yybm[0 + yych] & 64)
{
- goto basic_json_parser_38;
+ goto basic_json_parser_15;
}
- if (yych == 'e')
+ if (yych <= 'D')
+ {
+ if (yych == '.')
+ {
+ goto basic_json_parser_37;
+ }
+ goto basic_json_parser_14;
+ }
+ else
{
- goto basic_json_parser_38;
+ if (yych <= 'E')
+ {
+ goto basic_json_parser_38;
+ }
+ if (yych == 'e')
+ {
+ goto basic_json_parser_38;
+ }
+ goto basic_json_parser_14;
}
- goto basic_json_parser_14;
- }
basic_json_parser_17:
- ++m_cursor;
- {
- return token_type::name_separator;
- }
+ ++m_cursor;
+ {
+ last_token_type = token_type::name_separator;
+ break;
+ }
basic_json_parser_19:
- ++m_cursor;
- {
- return token_type::begin_array;
- }
+ ++m_cursor;
+ {
+ last_token_type = token_type::begin_array;
+ break;
+ }
basic_json_parser_21:
- ++m_cursor;
- {
- return token_type::end_array;
- }
+ ++m_cursor;
+ {
+ last_token_type = token_type::end_array;
+ break;
+ }
basic_json_parser_23:
- yyaccept = 0;
- yych = *(m_marker = ++m_cursor);
- if (yych == 'a')
- {
- goto basic_json_parser_39;
- }
- goto basic_json_parser_5;
+ yyaccept = 0;
+ yych = *(m_marker = ++m_cursor);
+ if (yych == 'a')
+ {
+ goto basic_json_parser_39;
+ }
+ goto basic_json_parser_5;
basic_json_parser_24:
- yyaccept = 0;
- yych = *(m_marker = ++m_cursor);
- if (yych == 'u')
- {
- goto basic_json_parser_40;
- }
- goto basic_json_parser_5;
+ yyaccept = 0;
+ yych = *(m_marker = ++m_cursor);
+ if (yych == 'u')
+ {
+ goto basic_json_parser_40;
+ }
+ goto basic_json_parser_5;
basic_json_parser_25:
- yyaccept = 0;
- yych = *(m_marker = ++m_cursor);
- if (yych == 'r')
- {
- goto basic_json_parser_41;
- }
- goto basic_json_parser_5;
+ 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;
- }
+ ++m_cursor;
+ {
+ last_token_type = token_type::begin_object;
+ break;
+ }
basic_json_parser_28:
- ++m_cursor;
- {
- return token_type::end_object;
- }
+ ++m_cursor;
+ {
+ last_token_type = token_type::end_object;
+ break;
+ }
basic_json_parser_30:
- yyaccept = 0;
- yych = *(m_marker = ++m_cursor);
- if (yych == 0xBB)
- {
- goto basic_json_parser_42;
- }
- goto basic_json_parser_5;
+ 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)
- {
- yyfill(); // LCOV_EXCL_LINE;
- }
- yych = *m_cursor;
+ ++m_cursor;
+ if (m_limit <= m_cursor)
+ {
+ yyfill(); // LCOV_EXCL_LINE;
+ }
+ yych = *m_cursor;
basic_json_parser_32:
- if (yybm[0 + yych] & 128)
- {
- goto basic_json_parser_31;
- }
- if (yych <= 0x0F)
- {
- goto basic_json_parser_33;
- }
- if (yych <= '"')
- {
- goto basic_json_parser_34;
- }
- goto basic_json_parser_36;
+ if (yybm[0 + yych] & 128)
+ {
+ goto basic_json_parser_31;
+ }
+ if (yych <= 0x1F)
+ {
+ goto basic_json_parser_33;
+ }
+ if (yych <= '"')
+ {
+ goto basic_json_parser_34;
+ }
+ goto basic_json_parser_36;
basic_json_parser_33:
- m_cursor = m_marker;
- if (yyaccept == 0)
- {
- goto basic_json_parser_5;
- }
- else
- {
- goto basic_json_parser_14;
- }
+ m_cursor = m_marker;
+ if (yyaccept == 0)
+ {
+ goto basic_json_parser_5;
+ }
+ else
+ {
+ goto basic_json_parser_14;
+ }
basic_json_parser_34:
- ++m_cursor;
- {
- return token_type::value_string;
- }
+ ++m_cursor;
+ {
+ last_token_type = token_type::value_string;
+ break;
+ }
basic_json_parser_36:
- ++m_cursor;
- if (m_limit <= m_cursor)
- {
- yyfill(); // LCOV_EXCL_LINE;
- }
- yych = *m_cursor;
- if (yych <= 'e')
- {
- if (yych <= '/')
+ ++m_cursor;
+ if (m_limit <= m_cursor)
{
- if (yych == '"')
- {
- goto basic_json_parser_31;
- }
- if (yych <= '.')
- {
- goto basic_json_parser_33;
- }
- goto basic_json_parser_31;
+ yyfill(); // LCOV_EXCL_LINE;
}
- else
+ yych = *m_cursor;
+ if (yych <= 'e')
{
- if (yych <= '\\')
+ if (yych <= '/')
{
- if (yych <= '[')
+ if (yych == '"')
+ {
+ goto basic_json_parser_31;
+ }
+ if (yych <= '.')
{
goto basic_json_parser_33;
}
@@ -7739,33 +8078,33 @@ basic_json_parser_36:
}
else
{
- if (yych == 'b')
+ if (yych <= '\\')
{
+ if (yych <= '[')
+ {
+ goto basic_json_parser_33;
+ }
goto basic_json_parser_31;
}
- goto basic_json_parser_33;
- }
- }
- }
- else
- {
- if (yych <= 'q')
- {
- if (yych <= 'f')
- {
- goto basic_json_parser_31;
- }
- if (yych == 'n')
- {
- goto basic_json_parser_31;
+ else
+ {
+ if (yych == 'b')
+ {
+ goto basic_json_parser_31;
+ }
+ goto basic_json_parser_33;
+ }
}
- goto basic_json_parser_33;
}
else
{
- if (yych <= 's')
+ if (yych <= 'q')
{
- if (yych <= 'r')
+ if (yych <= 'f')
+ {
+ goto basic_json_parser_31;
+ }
+ if (yych == 'n')
{
goto basic_json_parser_31;
}
@@ -7773,331 +8112,347 @@ basic_json_parser_36:
}
else
{
- if (yych <= 't')
+ if (yych <= 's')
{
- goto basic_json_parser_31;
+ if (yych <= 'r')
+ {
+ goto basic_json_parser_31;
+ }
+ goto basic_json_parser_33;
}
- if (yych <= 'u')
+ else
{
- goto basic_json_parser_43;
+ if (yych <= 't')
+ {
+ goto basic_json_parser_31;
+ }
+ if (yych <= 'u')
+ {
+ goto basic_json_parser_43;
+ }
+ goto basic_json_parser_33;
}
- goto basic_json_parser_33;
}
}
- }
basic_json_parser_37:
- yych = *++m_cursor;
- if (yych <= '/')
- {
- goto basic_json_parser_33;
- }
- if (yych <= '9')
- {
- goto basic_json_parser_44;
- }
- goto basic_json_parser_33;
-basic_json_parser_38:
- yych = *++m_cursor;
- if (yych <= ',')
- {
- if (yych == '+')
+ yych = *++m_cursor;
+ if (yych <= '/')
{
- goto basic_json_parser_46;
+ goto basic_json_parser_33;
+ }
+ if (yych <= '9')
+ {
+ goto basic_json_parser_44;
}
goto basic_json_parser_33;
- }
- else
- {
- if (yych <= '-')
+basic_json_parser_38:
+ yych = *++m_cursor;
+ if (yych <= ',')
{
- goto basic_json_parser_46;
+ if (yych == '+')
+ {
+ goto basic_json_parser_46;
+ }
+ goto basic_json_parser_33;
}
- if (yych <= '/')
+ else
{
+ if (yych <= '-')
+ {
+ goto basic_json_parser_46;
+ }
+ if (yych <= '/')
+ {
+ goto basic_json_parser_33;
+ }
+ if (yych <= '9')
+ {
+ goto basic_json_parser_47;
+ }
goto basic_json_parser_33;
}
- if (yych <= '9')
+basic_json_parser_39:
+ yych = *++m_cursor;
+ if (yych == 'l')
{
- goto basic_json_parser_47;
+ goto basic_json_parser_49;
}
goto basic_json_parser_33;
- }
-basic_json_parser_39:
- yych = *++m_cursor;
- if (yych == 'l')
- {
- goto basic_json_parser_49;
- }
- goto basic_json_parser_33;
basic_json_parser_40:
- yych = *++m_cursor;
- if (yych == 'l')
- {
- goto basic_json_parser_50;
- }
- goto basic_json_parser_33;
+ yych = *++m_cursor;
+ if (yych == 'l')
+ {
+ goto basic_json_parser_50;
+ }
+ goto basic_json_parser_33;
basic_json_parser_41:
- yych = *++m_cursor;
- if (yych == 'u')
- {
- goto basic_json_parser_51;
- }
- goto basic_json_parser_33;
+ yych = *++m_cursor;
+ if (yych == 'u')
+ {
+ goto basic_json_parser_51;
+ }
+ goto basic_json_parser_33;
basic_json_parser_42:
- yych = *++m_cursor;
- if (yych == 0xBF)
- {
- goto basic_json_parser_52;
- }
- goto basic_json_parser_33;
+ 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)
- {
- yyfill(); // LCOV_EXCL_LINE;
- }
- yych = *m_cursor;
- if (yych <= '@')
- {
- if (yych <= '/')
+ ++m_cursor;
+ if (m_limit <= m_cursor)
{
+ yyfill(); // LCOV_EXCL_LINE;
+ }
+ yych = *m_cursor;
+ if (yych <= '@')
+ {
+ if (yych <= '/')
+ {
+ goto basic_json_parser_33;
+ }
+ if (yych <= '9')
+ {
+ goto basic_json_parser_54;
+ }
goto basic_json_parser_33;
}
- if (yych <= '9')
+ else
{
- goto basic_json_parser_54;
+ if (yych <= 'F')
+ {
+ goto basic_json_parser_54;
+ }
+ if (yych <= '`')
+ {
+ goto basic_json_parser_33;
+ }
+ if (yych <= 'f')
+ {
+ goto basic_json_parser_54;
+ }
+ goto basic_json_parser_33;
}
- goto basic_json_parser_33;
- }
- else
- {
- if (yych <= 'F')
+basic_json_parser_44:
+ yyaccept = 1;
+ m_marker = ++m_cursor;
+ if ((m_limit - m_cursor) < 3)
{
- goto basic_json_parser_54;
+ yyfill(); // LCOV_EXCL_LINE;
}
- if (yych <= '`')
+ yych = *m_cursor;
+ if (yych <= 'D')
+ {
+ if (yych <= '/')
+ {
+ goto basic_json_parser_14;
+ }
+ if (yych <= '9')
+ {
+ goto basic_json_parser_44;
+ }
+ goto basic_json_parser_14;
+ }
+ else
+ {
+ if (yych <= 'E')
+ {
+ goto basic_json_parser_38;
+ }
+ if (yych == 'e')
+ {
+ goto basic_json_parser_38;
+ }
+ goto basic_json_parser_14;
+ }
+basic_json_parser_46:
+ yych = *++m_cursor;
+ if (yych <= '/')
{
goto basic_json_parser_33;
}
- if (yych <= 'f')
+ if (yych >= ':')
{
- goto basic_json_parser_54;
+ goto basic_json_parser_33;
}
- goto basic_json_parser_33;
- }
-basic_json_parser_44:
- yyaccept = 1;
- m_marker = ++m_cursor;
- if ((m_limit - m_cursor) < 3)
- {
- yyfill(); // LCOV_EXCL_LINE;
- }
- yych = *m_cursor;
- if (yych <= 'D')
- {
+basic_json_parser_47:
+ ++m_cursor;
+ if (m_limit <= m_cursor)
+ {
+ yyfill(); // LCOV_EXCL_LINE;
+ }
+ yych = *m_cursor;
if (yych <= '/')
{
goto basic_json_parser_14;
}
if (yych <= '9')
{
- goto basic_json_parser_44;
+ goto basic_json_parser_47;
}
goto basic_json_parser_14;
- }
- else
- {
- if (yych <= 'E')
+basic_json_parser_49:
+ yych = *++m_cursor;
+ if (yych == 's')
{
- goto basic_json_parser_38;
+ goto basic_json_parser_55;
}
- if (yych == 'e')
+ goto basic_json_parser_33;
+basic_json_parser_50:
+ yych = *++m_cursor;
+ if (yych == 'l')
{
- goto basic_json_parser_38;
+ goto basic_json_parser_56;
}
- goto basic_json_parser_14;
- }
-basic_json_parser_46:
- yych = *++m_cursor;
- if (yych <= '/')
- {
goto basic_json_parser_33;
- }
- if (yych >= ':')
- {
- goto basic_json_parser_33;
- }
-basic_json_parser_47:
- ++m_cursor;
- if (m_limit <= m_cursor)
- {
- yyfill(); // LCOV_EXCL_LINE;
- }
- yych = *m_cursor;
- if (yych <= '/')
- {
- goto basic_json_parser_14;
- }
- if (yych <= '9')
- {
- goto basic_json_parser_47;
- }
- goto basic_json_parser_14;
-basic_json_parser_49:
- yych = *++m_cursor;
- if (yych == 's')
- {
- goto basic_json_parser_55;
- }
- goto basic_json_parser_33;
-basic_json_parser_50:
- yych = *++m_cursor;
- if (yych == 'l')
- {
- goto basic_json_parser_56;
- }
- goto basic_json_parser_33;
basic_json_parser_51:
- yych = *++m_cursor;
- if (yych == 'e')
- {
- goto basic_json_parser_58;
- }
- goto basic_json_parser_33;
+ 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 <= '@')
- {
- if (yych <= '/')
+ ++m_cursor;
{
- goto basic_json_parser_33;
+ continue;
}
- if (yych <= '9')
+basic_json_parser_54:
+ ++m_cursor;
+ if (m_limit <= m_cursor)
{
- goto basic_json_parser_60;
+ yyfill(); // LCOV_EXCL_LINE;
}
- goto basic_json_parser_33;
- }
- else
- {
- if (yych <= 'F')
+ yych = *m_cursor;
+ if (yych <= '@')
{
- goto basic_json_parser_60;
+ if (yych <= '/')
+ {
+ goto basic_json_parser_33;
+ }
+ if (yych <= '9')
+ {
+ goto basic_json_parser_60;
+ }
+ goto basic_json_parser_33;
}
- if (yych <= '`')
+ else
{
+ if (yych <= 'F')
+ {
+ goto basic_json_parser_60;
+ }
+ if (yych <= '`')
+ {
+ goto basic_json_parser_33;
+ }
+ if (yych <= 'f')
+ {
+ goto basic_json_parser_60;
+ }
goto basic_json_parser_33;
}
- if (yych <= 'f')
+basic_json_parser_55:
+ yych = *++m_cursor;
+ if (yych == 'e')
{
- goto basic_json_parser_60;
+ goto basic_json_parser_61;
}
goto basic_json_parser_33;
- }
-basic_json_parser_55:
- yych = *++m_cursor;
- if (yych == 'e')
- {
- goto basic_json_parser_61;
- }
- goto basic_json_parser_33;
basic_json_parser_56:
- ++m_cursor;
- {
- return token_type::literal_null;
- }
-basic_json_parser_58:
- ++m_cursor;
- {
- return token_type::literal_true;
- }
-basic_json_parser_60:
- ++m_cursor;
- if (m_limit <= m_cursor)
- {
- yyfill(); // LCOV_EXCL_LINE;
- }
- yych = *m_cursor;
- if (yych <= '@')
- {
- if (yych <= '/')
+ ++m_cursor;
{
- goto basic_json_parser_33;
+ last_token_type = token_type::literal_null;
+ break;
}
- if (yych <= '9')
+basic_json_parser_58:
+ ++m_cursor;
{
- goto basic_json_parser_63;
+ last_token_type = token_type::literal_true;
+ break;
}
- goto basic_json_parser_33;
- }
- else
- {
- if (yych <= 'F')
+basic_json_parser_60:
+ ++m_cursor;
+ if (m_limit <= m_cursor)
{
- goto basic_json_parser_63;
+ yyfill(); // LCOV_EXCL_LINE;
}
- if (yych <= '`')
+ 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;
}
- if (yych <= 'f')
- {
- goto basic_json_parser_63;
- }
- goto basic_json_parser_33;
- }
-basic_json_parser_61:
- ++m_cursor;
- {
- return token_type::literal_false;
- }
-basic_json_parser_63:
- ++m_cursor;
- if (m_limit <= m_cursor)
- {
- yyfill(); // LCOV_EXCL_LINE;
- }
- yych = *m_cursor;
- if (yych <= '@')
- {
- if (yych <= '/')
+ 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;
}
- if (yych <= '9')
+basic_json_parser_61:
+ ++m_cursor;
{
- goto basic_json_parser_31;
+ last_token_type = token_type::literal_false;
+ break;
}
- goto basic_json_parser_33;
- }
- else
- {
- if (yych <= 'F')
+basic_json_parser_63:
+ ++m_cursor;
+ if (m_limit <= m_cursor)
{
- goto basic_json_parser_31;
+ yyfill(); // LCOV_EXCL_LINE;
}
- if (yych <= '`')
+ 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;
}
- if (yych <= 'f')
+ else
{
- goto basic_json_parser_31;
+ 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;
}
- goto basic_json_parser_33;
}
+
}
+ return last_token_type;
}
/// append data from the stream to the internal buffer
@@ -8127,7 +8482,7 @@ basic_json_parser_63:
}
/// return string representation of last read token
- string_t get_token() const
+ string_t get_token_string() const
{
assert(m_start != nullptr);
return string_t(reinterpret_cast<typename string_t::const_pointer>(m_start),
@@ -8152,12 +8507,49 @@ basic_json_parser_63:
of the construction of the values.
2. Unescaped characters are copied as is.
+ @pre `m_cursor - m_start >= 2`, meaning the length of the last token
+ is at least 2 bytes which is trivially true for any string (which
+ consists of at least two quotes).
+
+ " c1 c2 c3 ... "
+ ^ ^
+ m_start m_cursor
+
+ @complexity Linear in the length of the string.\n
+
+ Lemma: The loop body will always terminate.\n
+
+ Proof (by contradiction): Assume the loop body does not terminate. As
+ the loop body does not contain another loop, one of the called
+ functions must never return. The called functions are `std::strtoul`
+ and to_unicode. Neither function can loop forever, so the loop body
+ will never loop forever which contradicts the assumption that the loop
+ body does not terminate, q.e.d.\n
+
+ Lemma: The loop condition for the for loop is eventually false.\n
+
+ Proof (by contradiction): Assume the loop does not terminate. Due to
+ the above lemma, this can only be due to a tautological loop
+ condition; that is, the loop condition i < m_cursor - 1 must always be
+ true. Let x be the change of i for any loop iteration. Then
+ m_start + 1 + x < m_cursor - 1 must hold to loop indefinitely. This
+ can be rephrased to m_cursor - m_start - 2 > x. With the
+ precondition, we x <= 0, meaning that the loop condition holds
+ indefinitly if i is always decreased. However, observe that the value
+ of i is strictly increasing with each iteration, as it is incremented
+ by 1 in the iteration expression and never decremented inside the loop
+ body. Hence, the loop condition will eventually be false which
+ contradicts the assumption that the loop condition is a tautology,
+ q.e.d.
+
@return string value of current token without opening and closing
quotes
@throw std::out_of_range if to_unicode fails
*/
string_t get_string() const
{
+ assert(m_cursor - m_start >= 2);
+
string_t result;
result.reserve(static_cast<size_t>(m_cursor - m_start - 2));
@@ -8273,11 +8665,6 @@ basic_json_parser_63:
the number
@return the floating point number
-
- @bug This function uses `std::strtof`, `std::strtod`, or `std::strtold`
- which use the current C locale to determine which character is used as
- decimal point character. This may yield to parse errors if the locale
- does not used `.`.
*/
long double str_to_float_t(long double* /* type */, char** endptr) const
{
@@ -8395,7 +8782,7 @@ basic_json_parser_63:
if (type != value_t::number_float)
{
// multiply last value by ten and add the new digit
- auto temp = value * 10 + *curptr - 0x30;
+ auto temp = value * 10 + *curptr - '0';
// test for overflow
if (temp < value || temp > max)
@@ -8445,6 +8832,8 @@ basic_json_parser_63:
const lexer_char_t* m_cursor = nullptr;
/// pointer to the end of the buffer
const lexer_char_t* m_limit = nullptr;
+ /// the last token type
+ token_type last_token_type = token_type::end_of_input;
};
/*!
@@ -8456,7 +8845,7 @@ basic_json_parser_63:
{
public:
/// constructor for strings
- parser(const string_t& s, parser_callback_t cb = nullptr) noexcept
+ parser(const string_t& s, const parser_callback_t cb = nullptr) noexcept
: callback(cb), m_lexer(s)
{
// read first token
@@ -8464,7 +8853,7 @@ basic_json_parser_63:
}
/// a parser reading from an input stream
- parser(std::istream& _is, parser_callback_t cb = nullptr) noexcept
+ parser(std::istream& _is, const parser_callback_t cb = nullptr) noexcept
: callback(cb), m_lexer(&_is)
{
// read first token
@@ -8475,12 +8864,13 @@ basic_json_parser_63:
basic_json parse()
{
basic_json result = parse_internal(true);
+ result.assert_invariant();
expect(lexer::token_type::end_of_input);
// return parser result and replace it with null in case the
// top-level value was discarded by the callback function
- return result.is_discarded() ? basic_json() : result;
+ return result.is_discarded() ? basic_json() : std::move(result);
}
private:
@@ -8497,7 +8887,7 @@ basic_json_parser_63:
{
// explicitly set result to object to cope with {}
result.m_type = value_t::object;
- result.m_value = json_value(value_t::object);
+ result.m_value = value_t::object;
}
// read next token
@@ -8575,7 +8965,7 @@ basic_json_parser_63:
{
// explicitly set result to object to cope with []
result.m_type = value_t::array;
- result.m_value = json_value(value_t::array);
+ result.m_value = value_t::array;
}
// read next token
@@ -8688,7 +9078,8 @@ basic_json_parser_63:
if (t != last_token)
{
std::string error_msg = "parse error - unexpected ";
- error_msg += (last_token == lexer::token_type::parse_error ? ("'" + m_lexer.get_token() + "'") :
+ error_msg += (last_token == lexer::token_type::parse_error ? ("'" + m_lexer.get_token_string() +
+ "'") :
lexer::token_type_name(last_token));
error_msg += "; expected " + lexer::token_type_name(t);
throw std::invalid_argument(error_msg);
@@ -8700,7 +9091,8 @@ basic_json_parser_63:
if (t == last_token)
{
std::string error_msg = "parse error - unexpected ";
- error_msg += (last_token == lexer::token_type::parse_error ? ("'" + m_lexer.get_token() + "'") :
+ error_msg += (last_token == lexer::token_type::parse_error ? ("'" + m_lexer.get_token_string() +
+ "'") :
lexer::token_type_name(last_token));
throw std::invalid_argument(error_msg);
}
@@ -8710,7 +9102,7 @@ basic_json_parser_63:
/// current level of recursion
int depth = 0;
/// callback function
- parser_callback_t callback;
+ const parser_callback_t callback = nullptr;
/// the type of the last read token
typename lexer::token_type last_token = lexer::token_type::uninitialized;
/// the lexer
@@ -8778,14 +9170,12 @@ basic_json_parser_63:
*/
std::string to_string() const noexcept
{
- std::string result;
-
- for (const auto& reference_token : reference_tokens)
+ return std::accumulate(reference_tokens.begin(),
+ reference_tokens.end(), std::string{},
+ [](const std::string & a, const std::string & b)
{
- result += "/" + escape(reference_token);
- }
-
- return result;
+ return a + "/" + escape(b);
+ });
}
/// @copydoc to_string()
@@ -8828,6 +9218,8 @@ basic_json_parser_63:
/*!
@brief create and return a reference to the pointed to value
+
+ @complexity Linear in the number of reference tokens.
*/
reference get_and_create(reference j) const
{
@@ -9149,7 +9541,7 @@ basic_json_parser_63:
@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
+ @param[in] t the string to replace @a f
@return The string @a s where all occurrences of @a f are replaced
with @a t.
@@ -10005,7 +10397,7 @@ 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
+can be used by adding `"_json"` to a string literal and returns a JSON object
if no parse error occurred.
@param[in] s a string representation of a JSON object
@@ -10021,6 +10413,13 @@ inline nlohmann::json operator "" _json(const char* s, std::size_t)
/*!
@brief user-defined string literal for JSON pointer
+This operator implements a user-defined string literal for JSON Pointers. It
+can be used by adding `"_json"` to a string literal and returns a JSON pointer
+object if no parse error occurred.
+
+@param[in] s a string representation of a JSON Pointer
+@return a JSON pointer object
+
@since version 2.0.0
*/
inline nlohmann::json::json_pointer operator "" _json_pointer(const char* s, std::size_t)