summaryrefslogtreecommitdiff
path: root/ext/json/json.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'ext/json/json.hpp')
-rw-r--r--ext/json/json.hpp3278
1 files changed, 2559 insertions, 719 deletions
diff --git a/ext/json/json.hpp b/ext/json/json.hpp
index 878fb899..9d48e7a6 100644
--- a/ext/json/json.hpp
+++ b/ext/json/json.hpp
@@ -1,11 +1,11 @@
/*
__ _____ _____ _____
__| | __| | | | JSON for Modern C++
-| | |__ | | | | | | version 2.0.2
+| | |__ | | | | | | version 2.0.10
|_____|_____|_____|_|___| https://github.com/nlohmann/json
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
-Copyright (c) 2013-2016 Niels Lohmann <http://nlohmann.me>.
+Copyright (c) 2013-2017 Niels Lohmann <http://nlohmann.me>.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@@ -29,30 +29,32 @@ SOFTWARE.
#ifndef NLOHMANN_JSON_HPP
#define NLOHMANN_JSON_HPP
-#include <algorithm>
-#include <array>
-#include <cassert>
-#include <ciso646>
-#include <cmath>
-#include <cstddef>
-#include <cstdint>
-#include <cstdlib>
-#include <functional>
-#include <initializer_list>
-#include <iomanip>
-#include <iostream>
-#include <iterator>
-#include <limits>
-#include <locale>
-#include <map>
-#include <memory>
-#include <numeric>
-#include <sstream>
-#include <stdexcept>
-#include <string>
-#include <type_traits>
-#include <utility>
-#include <vector>
+#include <algorithm> // all_of, for_each, transform
+#include <array> // array
+#include <cassert> // assert
+#include <cctype> // isdigit
+#include <ciso646> // and, not, or
+#include <cmath> // isfinite, ldexp, signbit
+#include <cstddef> // nullptr_t, ptrdiff_t, size_t
+#include <cstdint> // int64_t, uint64_t
+#include <cstdlib> // strtod, strtof, strtold, strtoul
+#include <cstring> // strlen
+#include <functional> // function, hash, less
+#include <initializer_list> // initializer_list
+#include <iomanip> // setw
+#include <iostream> // istream, ostream
+#include <iterator> // advance, begin, bidirectional_iterator_tag, distance, end, inserter, iterator, iterator_traits, next, random_access_iterator_tag, reverse_iterator
+#include <limits> // numeric_limits
+#include <locale> // locale
+#include <map> // map
+#include <memory> // addressof, allocator, allocator_traits, unique_ptr
+#include <numeric> // accumulate
+#include <sstream> // stringstream
+#include <stdexcept> // domain_error, invalid_argument, out_of_range
+#include <string> // getline, stoi, string, to_string
+#include <type_traits> // add_pointer, enable_if, is_arithmetic, is_base_of, is_const, is_constructible, is_convertible, is_floating_point, is_integral, is_nothrow_move_assignable, std::is_nothrow_move_constructible, std::is_pointer, std::is_reference, std::is_same, remove_const, remove_pointer, remove_reference
+#include <utility> // declval, forward, make_pair, move, pair, swap
+#include <vector> // vector
// exclude unsupported compilers
#if defined(__clang__)
@@ -73,6 +75,21 @@ SOFTWARE.
#pragma GCC diagnostic ignored "-Wfloat-equal"
#endif
+// disable documentation warnings on clang
+#if defined(__clang__)
+ #pragma GCC diagnostic push
+ #pragma GCC diagnostic ignored "-Wdocumentation"
+#endif
+
+// allow for portable deprecation warnings
+#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__)
+ #define JSON_DEPRECATED __attribute__((deprecated))
+#elif defined(_MSC_VER)
+ #define JSON_DEPRECATED __declspec(deprecated)
+#else
+ #define JSON_DEPRECATED
+#endif
+
/*!
@brief namespace for Niels Lohmann
@see https://github.com/nlohmann
@@ -96,36 +113,19 @@ such as sequence containers. For instance, `std::map` passes the test as it
contains a `mapped_type`, whereas `std::vector` fails the test.
@sa http://stackoverflow.com/a/7728728/266378
-@since version 1.0.0
+@since version 1.0.0, overworked in version 2.0.6
*/
template<typename T>
struct has_mapped_type
{
private:
- template<typename C> static char test(typename C::mapped_type*);
- template<typename C> static char (&test(...))[2];
- public:
- static constexpr bool value = sizeof(test<T>(0)) == 1;
-};
+ template <typename U, typename = typename U::mapped_type>
+ static int detect(U&&);
-/*!
-@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
-*/
-struct DecimalSeparator : std::numpunct<char>
-{
- char do_decimal_point() const
- {
- return '.';
- }
+ static void detect(...);
+ public:
+ static constexpr bool value =
+ std::is_integral<decltype(detect(std::declval<T>()))>::value;
};
}
@@ -228,6 +228,7 @@ class basic_json
public:
// forward declarations
+ template<typename U> class iter_impl;
template<typename Base> class json_reverse_iterator;
class json_pointer;
@@ -262,9 +263,9 @@ class basic_json
using const_pointer = typename std::allocator_traits<allocator_type>::const_pointer;
/// an iterator for a basic_json container
- class iterator;
+ using iterator = iter_impl<basic_json>;
/// a const iterator for a basic_json container
- class const_iterator;
+ using const_iterator = iter_impl<const basic_json>;
/// a reverse iterator for a basic_json container
using reverse_iterator = json_reverse_iterator<typename basic_json::iterator>;
/// a const reverse iterator for a basic_json container
@@ -872,8 +873,17 @@ class basic_json
break;
}
+ case value_t::null:
+ {
+ break;
+ }
+
default:
{
+ if (t == value_t::null)
+ {
+ throw std::domain_error("961c151d2e87f2686a955a9be24d316f1362bf21 2.0.10"); // LCOV_EXCL_LINE
+ }
break;
}
}
@@ -950,7 +960,7 @@ class basic_json
With a parser callback function, the result of parsing a JSON text can be
influenced. When passed to @ref parse(std::istream&, const
- parser_callback_t) or @ref parse(const string_t&, const parser_callback_t),
+ parser_callback_t) or @ref parse(const CharT, 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
@@ -993,7 +1003,7 @@ class basic_json
skipped completely or replaced by an empty discarded object.
@sa @ref parse(std::istream&, parser_callback_t) or
- @ref parse(const string_t&, parser_callback_t) for examples
+ @ref parse(const CharT, const parser_callback_t) for examples
@since version 1.0.0
*/
@@ -1057,40 +1067,10 @@ class basic_json
}
/*!
- @brief create a null object (implicitly)
-
- 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
- exceptions.
-
- @requirement This function helps `basic_json` satisfying the
- [Container](http://en.cppreference.com/w/cpp/concept/Container)
- requirements:
- - The complexity is constant.
- - As postcondition, it holds: `basic_json().empty() == true`.
-
- @liveexample{The following code shows the constructor for a `null` JSON
- value.,basic_json}
-
- @sa @ref basic_json(std::nullptr_t) -- create a `null` value
-
- @since version 1.0.0
- */
- basic_json() = default;
-
- /*!
- @brief create a null object (explicitly)
+ @brief create a null object
- Create a `null` JSON value. This is the explicitly version of the `null`
- value constructor as it takes a null pointer as parameter. It allows to
- create `null` values by explicitly assigning a `nullptr` to a JSON value.
+ Create a `null` JSON value. It either takes a null pointer as parameter
+ (explicitly creating `null`) or no parameter (implicitly creating `null`).
The passed null pointer itself is not read -- it is only used to choose
the right constructor.
@@ -1099,15 +1079,12 @@ class basic_json
@exceptionsafety No-throw guarantee: this constructor never throws
exceptions.
- @liveexample{The following code shows the constructor with null pointer
- parameter.,basic_json__nullptr_t}
-
- @sa @ref basic_json() -- default constructor (implicitly creating a `null`
- value)
+ @liveexample{The following code shows the constructor with and without a
+ null pointer parameter.,basic_json__nullptr_t}
@since version 1.0.0
*/
- basic_json(std::nullptr_t) noexcept
+ basic_json(std::nullptr_t = nullptr) noexcept
: basic_json(value_t::null)
{
assert_invariant();
@@ -1164,11 +1141,9 @@ class basic_json
@since version 1.0.0
*/
- template <class CompatibleObjectType, typename
- std::enable_if<
- std::is_constructible<typename object_t::key_type, typename CompatibleObjectType::key_type>::value and
- std::is_constructible<basic_json, typename CompatibleObjectType::mapped_type>::value, int>::type
- = 0>
+ template<class CompatibleObjectType, typename std::enable_if<
+ std::is_constructible<typename object_t::key_type, typename CompatibleObjectType::key_type>::value and
+ std::is_constructible<basic_json, typename CompatibleObjectType::mapped_type>::value, int>::type = 0>
basic_json(const CompatibleObjectType& val)
: m_type(value_t::object)
{
@@ -1229,16 +1204,14 @@ class basic_json
@since version 1.0.0
*/
- template <class CompatibleArrayType, typename
- std::enable_if<
- not std::is_same<CompatibleArrayType, typename basic_json_t::iterator>::value and
- not std::is_same<CompatibleArrayType, typename basic_json_t::const_iterator>::value and
- not std::is_same<CompatibleArrayType, typename basic_json_t::reverse_iterator>::value and
- not std::is_same<CompatibleArrayType, typename basic_json_t::const_reverse_iterator>::value and
- not std::is_same<CompatibleArrayType, typename array_t::iterator>::value and
- not std::is_same<CompatibleArrayType, typename array_t::const_iterator>::value and
- std::is_constructible<basic_json, typename CompatibleArrayType::value_type>::value, int>::type
- = 0>
+ template<class CompatibleArrayType, typename std::enable_if<
+ not std::is_same<CompatibleArrayType, typename basic_json_t::iterator>::value and
+ not std::is_same<CompatibleArrayType, typename basic_json_t::const_iterator>::value and
+ not std::is_same<CompatibleArrayType, typename basic_json_t::reverse_iterator>::value and
+ not std::is_same<CompatibleArrayType, typename basic_json_t::const_reverse_iterator>::value and
+ not std::is_same<CompatibleArrayType, typename array_t::iterator>::value and
+ not std::is_same<CompatibleArrayType, typename array_t::const_iterator>::value and
+ std::is_constructible<basic_json, typename CompatibleArrayType::value_type>::value, int>::type = 0>
basic_json(const CompatibleArrayType& val)
: m_type(value_t::array)
{
@@ -1324,10 +1297,8 @@ class basic_json
@since version 1.0.0
*/
- template <class CompatibleStringType, typename
- std::enable_if<
- std::is_constructible<string_t, CompatibleStringType>::value, int>::type
- = 0>
+ template<class CompatibleStringType, typename std::enable_if<
+ std::is_constructible<string_t, CompatibleStringType>::value, int>::type = 0>
basic_json(const CompatibleStringType& val)
: basic_json(string_t(val))
{
@@ -1377,12 +1348,9 @@ class basic_json
@since version 1.0.0
*/
- template<typename T,
- typename std::enable_if<
- not (std::is_same<T, int>::value)
- and std::is_same<T, number_integer_t>::value
- , int>::type
- = 0>
+ template<typename T, typename std::enable_if<
+ not (std::is_same<T, int>::value) and
+ std::is_same<T, number_integer_t>::value, int>::type = 0>
basic_json(const number_integer_t val) noexcept
: m_type(value_t::number_integer), m_value(val)
{
@@ -1446,13 +1414,11 @@ class basic_json
@since version 1.0.0
*/
- template<typename CompatibleNumberIntegerType, typename
- std::enable_if<
+ template<typename CompatibleNumberIntegerType, typename std::enable_if<
std::is_constructible<number_integer_t, CompatibleNumberIntegerType>::value and
std::numeric_limits<CompatibleNumberIntegerType>::is_integer and
std::numeric_limits<CompatibleNumberIntegerType>::is_signed,
- CompatibleNumberIntegerType>::type
- = 0>
+ CompatibleNumberIntegerType>::type = 0>
basic_json(const CompatibleNumberIntegerType val) noexcept
: m_type(value_t::number_integer),
m_value(static_cast<number_integer_t>(val))
@@ -1477,12 +1443,9 @@ class basic_json
@since version 2.0.0
*/
- template<typename T,
- typename std::enable_if<
- not (std::is_same<T, int>::value)
- and std::is_same<T, number_unsigned_t>::value
- , int>::type
- = 0>
+ template<typename T, typename std::enable_if<
+ not (std::is_same<T, int>::value) and
+ std::is_same<T, number_unsigned_t>::value, int>::type = 0>
basic_json(const number_unsigned_t val) noexcept
: m_type(value_t::number_unsigned), m_value(val)
{
@@ -1509,13 +1472,11 @@ class basic_json
@since version 2.0.0
*/
- template <typename CompatibleNumberUnsignedType, typename
- std::enable_if <
- std::is_constructible<number_unsigned_t, CompatibleNumberUnsignedType>::value and
- std::numeric_limits<CompatibleNumberUnsignedType>::is_integer and
- not std::numeric_limits<CompatibleNumberUnsignedType>::is_signed,
- CompatibleNumberUnsignedType>::type
- = 0>
+ template<typename CompatibleNumberUnsignedType, typename std::enable_if <
+ std::is_constructible<number_unsigned_t, CompatibleNumberUnsignedType>::value and
+ std::numeric_limits<CompatibleNumberUnsignedType>::is_integer and
+ not std::numeric_limits<CompatibleNumberUnsignedType>::is_signed,
+ CompatibleNumberUnsignedType>::type = 0>
basic_json(const CompatibleNumberUnsignedType val) noexcept
: m_type(value_t::number_unsigned),
m_value(static_cast<number_unsigned_t>(val))
@@ -1591,11 +1552,9 @@ class basic_json
@since version 1.0.0
*/
- template<typename CompatibleNumberFloatType, typename = typename
- std::enable_if<
+ template<typename CompatibleNumberFloatType, typename = typename std::enable_if<
std::is_constructible<number_float_t, CompatibleNumberFloatType>::value and
- std::is_floating_point<CompatibleNumberFloatType>::value>::type
- >
+ std::is_floating_point<CompatibleNumberFloatType>::value>::type>
basic_json(const CompatibleNumberFloatType val) noexcept
: basic_json(number_float_t(val))
{
@@ -1843,7 +1802,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.
+ @pre Iterators @a first and @a last must be initialized. **This
+ precondition is enforced with an assertion.**
@throw std::domain_error if iterators are not compatible; that is, do not
belong to the same JSON value; example: `"iterators are not compatible"`
@@ -1861,12 +1821,9 @@ class basic_json
@since version 1.0.0
*/
- template <class InputIT, typename
- std::enable_if<
- std::is_same<InputIT, typename basic_json_t::iterator>::value or
- std::is_same<InputIT, typename basic_json_t::const_iterator>::value
- , int>::type
- = 0>
+ template<class InputIT, typename std::enable_if<
+ std::is_same<InputIT, typename basic_json_t::iterator>::value or
+ std::is_same<InputIT, typename basic_json_t::const_iterator>::value, int>::type = 0>
basic_json(InputIT first, InputIT last)
{
assert(first.m_object != nullptr);
@@ -1970,12 +1927,21 @@ class basic_json
@note A UTF-8 byte order mark is silently ignored.
+ @deprecated This constructor is deprecated and will be removed in version
+ 3.0.0 to unify the interface of the library. Deserialization will be
+ done by stream operators or by calling one of the `parse` functions,
+ e.g. @ref parse(std::istream&, const parser_callback_t). That is, calls
+ like `json j(i);` for an input stream @a i need to be replaced by
+ `json j = json::parse(i);`. See the example below.
+
@liveexample{The example below demonstrates constructing a JSON value from
a `std::stringstream` with and without callback
function.,basic_json__istream}
- @since version 2.0.0
+ @since version 2.0.0, deprecated in version 2.0.3, to be removed in
+ version 3.0.0
*/
+ JSON_DEPRECATED
explicit basic_json(std::istream& i, const parser_callback_t cb = nullptr)
{
*this = parser(i, cb).parse();
@@ -2231,7 +2197,7 @@ class basic_json
{
std::stringstream ss;
// fix locale problems
- ss.imbue(std::locale(std::locale(), new DecimalSeparator));
+ ss.imbue(std::locale::classic());
// 6, 15 or 16 digits of precision allows round-trip IEEE 754
// string->float->string, string->double->string or string->long
@@ -2614,11 +2580,9 @@ class basic_json
//////////////////
/// get an object (explicit)
- template <class T, typename
- std::enable_if<
- std::is_convertible<typename object_t::key_type, typename T::key_type>::value and
- std::is_convertible<basic_json_t, typename T::mapped_type>::value
- , int>::type = 0>
+ template<class T, typename std::enable_if<
+ std::is_convertible<typename object_t::key_type, typename T::key_type>::value and
+ std::is_convertible<basic_json_t, typename T::mapped_type>::value, int>::type = 0>
T get_impl(T*) const
{
if (is_object())
@@ -2645,14 +2609,12 @@ class basic_json
}
/// get an array (explicit)
- template <class T, typename
- std::enable_if<
- std::is_convertible<basic_json_t, typename T::value_type>::value and
- not std::is_same<basic_json_t, typename T::value_type>::value and
- not std::is_arithmetic<T>::value and
- not std::is_convertible<std::string, T>::value and
- not has_mapped_type<T>::value
- , int>::type = 0>
+ template<class T, typename std::enable_if<
+ std::is_convertible<basic_json_t, typename T::value_type>::value and
+ not std::is_same<basic_json_t, typename T::value_type>::value and
+ not std::is_arithmetic<T>::value and
+ not std::is_convertible<std::string, T>::value and
+ not has_mapped_type<T>::value, int>::type = 0>
T get_impl(T*) const
{
if (is_array())
@@ -2672,11 +2634,9 @@ class basic_json
}
/// get an array (explicit)
- template <class T, typename
- std::enable_if<
- std::is_convertible<basic_json_t, T>::value and
- not std::is_same<basic_json_t, T>::value
- , int>::type = 0>
+ template<class T, typename std::enable_if<
+ std::is_convertible<basic_json_t, T>::value and
+ not std::is_same<basic_json_t, T>::value, int>::type = 0>
std::vector<T> get_impl(std::vector<T>*) const
{
if (is_array())
@@ -2697,11 +2657,9 @@ class basic_json
}
/// get an array (explicit)
- template <class T, typename
- std::enable_if<
- std::is_same<basic_json, typename T::value_type>::value and
- not has_mapped_type<T>::value
- , int>::type = 0>
+ template<class T, typename std::enable_if<
+ std::is_same<basic_json, typename T::value_type>::value and
+ not has_mapped_type<T>::value, int>::type = 0>
T get_impl(T*) const
{
if (is_array())
@@ -2728,10 +2686,8 @@ class basic_json
}
/// get a string (explicit)
- template <typename T, typename
- std::enable_if<
- std::is_convertible<string_t, T>::value
- , int>::type = 0>
+ template<typename T, typename std::enable_if<
+ std::is_convertible<string_t, T>::value, int>::type = 0>
T get_impl(T*) const
{
if (is_string())
@@ -2745,10 +2701,8 @@ class basic_json
}
/// get a number (explicit)
- template<typename T, typename
- std::enable_if<
- std::is_arithmetic<T>::value
- , int>::type = 0>
+ template<typename T, typename std::enable_if<
+ std::is_arithmetic<T>::value, int>::type = 0>
T get_impl(T*) const
{
switch (m_type)
@@ -2937,10 +2891,8 @@ class basic_json
@since version 1.0.0
*/
- template<typename ValueType, typename
- std::enable_if<
- not std::is_pointer<ValueType>::value
- , int>::type = 0>
+ template<typename ValueType, typename std::enable_if<
+ not std::is_pointer<ValueType>::value, int>::type = 0>
ValueType get() const
{
return get_impl(static_cast<ValueType*>(nullptr));
@@ -2973,10 +2925,8 @@ class basic_json
@since version 1.0.0
*/
- template<typename PointerType, typename
- std::enable_if<
- std::is_pointer<PointerType>::value
- , int>::type = 0>
+ template<typename PointerType, typename std::enable_if<
+ std::is_pointer<PointerType>::value, int>::type = 0>
PointerType get() noexcept
{
// delegate the call to get_ptr
@@ -2987,10 +2937,8 @@ class basic_json
@brief get a pointer value (explicit)
@copydoc get()
*/
- template<typename PointerType, typename
- std::enable_if<
- std::is_pointer<PointerType>::value
- , int>::type = 0>
+ template<typename PointerType, typename std::enable_if<
+ std::is_pointer<PointerType>::value, int>::type = 0>
constexpr const PointerType get() const noexcept
{
// delegate the call to get_ptr
@@ -3023,10 +2971,8 @@ class basic_json
@since version 1.0.0
*/
- template<typename PointerType, typename
- std::enable_if<
- std::is_pointer<PointerType>::value
- , int>::type = 0>
+ template<typename PointerType, typename std::enable_if<
+ std::is_pointer<PointerType>::value, int>::type = 0>
PointerType get_ptr() noexcept
{
// get the type of the PointerType (remove pointer and const)
@@ -3052,11 +2998,9 @@ class basic_json
@brief get a pointer value (implicit)
@copydoc get_ptr()
*/
- template<typename PointerType, typename
- std::enable_if<
- std::is_pointer<PointerType>::value
- and std::is_const<typename std::remove_pointer<PointerType>::type>::value
- , int>::type = 0>
+ template<typename PointerType, typename std::enable_if<
+ std::is_pointer<PointerType>::value and
+ std::is_const<typename std::remove_pointer<PointerType>::type>::value, int>::type = 0>
constexpr const PointerType get_ptr() const noexcept
{
// get the type of the PointerType (remove pointer and const)
@@ -3104,10 +3048,8 @@ class basic_json
@since version 1.1.0
*/
- template<typename ReferenceType, typename
- std::enable_if<
- std::is_reference<ReferenceType>::value
- , int>::type = 0>
+ template<typename ReferenceType, typename std::enable_if<
+ std::is_reference<ReferenceType>::value, int>::type = 0>
ReferenceType get_ref()
{
// delegate call to get_ref_impl
@@ -3118,11 +3060,9 @@ class basic_json
@brief get a reference value (implicit)
@copydoc get_ref()
*/
- template<typename ReferenceType, typename
- std::enable_if<
- std::is_reference<ReferenceType>::value
- and std::is_const<typename std::remove_reference<ReferenceType>::type>::value
- , int>::type = 0>
+ template<typename ReferenceType, typename std::enable_if<
+ std::is_reference<ReferenceType>::value and
+ std::is_const<typename std::remove_reference<ReferenceType>::type>::value, int>::type = 0>
ReferenceType get_ref() const
{
// delegate call to get_ref_impl
@@ -3157,10 +3097,9 @@ class basic_json
@since version 1.0.0
*/
- template < typename ValueType, typename
- std::enable_if <
- not std::is_pointer<ValueType>::value
- and not std::is_same<ValueType, typename string_t::value_type>::value
+ template < typename ValueType, typename std::enable_if <
+ not std::is_pointer<ValueType>::value and
+ not std::is_same<ValueType, typename string_t::value_type>::value
#ifndef _MSC_VER // Fix for issue #167 operator<< abiguity under VS2015
and not std::is_same<ValueType, std::initializer_list<typename string_t::value_type>>::value
#endif
@@ -3509,6 +3448,9 @@ class basic_json
@return const reference to the element at key @a key
+ @pre The element with key @a key must exist. **This precondition is
+ enforced with an assertion.**
+
@throw std::domain_error if JSON is not an object; example: `"cannot use
operator[] with null"`
@@ -3667,6 +3609,9 @@ class basic_json
@return const reference to the element at key @a key
+ @pre The element with key @a key must exist. **This precondition is
+ enforced with an assertion.**
+
@throw std::domain_error if JSON is not an object; example: `"cannot use
operator[] with null"`
@@ -3744,10 +3689,8 @@ class basic_json
@since version 1.0.0
*/
- template <class ValueType, typename
- std::enable_if<
- std::is_convertible<basic_json_t, ValueType>::value
- , int>::type = 0>
+ template<class ValueType, typename std::enable_if<
+ std::is_convertible<basic_json_t, ValueType>::value, int>::type = 0>
ValueType value(const typename object_t::key_type& key, ValueType default_value) const
{
// at only works for objects
@@ -3820,10 +3763,8 @@ class basic_json
@since version 2.0.2
*/
- template <class ValueType, typename
- std::enable_if<
- std::is_convertible<basic_json_t, ValueType>::value
- , int>::type = 0>
+ 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
@@ -3861,13 +3802,14 @@ class basic_json
container `c`, the expression `c.front()` is equivalent to `*c.begin()`.
@return In case of a structured type (array or object), a reference to the
- first element is returned. In cast of number, string, or boolean values, a
+ first element is returned. In case of number, string, or boolean values, a
reference to the value is returned.
@complexity Constant.
@pre The JSON value must not be `null` (would throw `std::out_of_range`)
- or an empty array or object (undefined behavior, guarded by assertions).
+ or an empty array or object (undefined behavior, **guarded by
+ assertions**).
@post The JSON value remains unchanged.
@throw std::out_of_range when called on `null` value
@@ -3903,13 +3845,14 @@ class basic_json
@endcode
@return In case of a structured type (array or object), a reference to the
- last element is returned. In cast of number, string, or boolean values, a
+ last element is returned. In case of number, string, or boolean values, a
reference to the value is returned.
@complexity Constant.
@pre The JSON value must not be `null` (would throw `std::out_of_range`)
- or an empty array or object (undefined behavior, guarded by assertions).
+ or an empty array or object (undefined behavior, **guarded by
+ assertions**).
@post The JSON value remains unchanged.
@throw std::out_of_range when called on `null` value.
@@ -3951,7 +3894,7 @@ class basic_json
@return Iterator following the last removed element. If the iterator @a
pos refers to the last element, the `end()` iterator is returned.
- @tparam InteratorType an @ref iterator or @ref const_iterator
+ @tparam IteratorType an @ref iterator or @ref const_iterator
@post Invalidates iterators and references at or after the point of the
erase, including the `end()` iterator.
@@ -3973,7 +3916,7 @@ class basic_json
@liveexample{The example shows the result of `erase()` for different JSON
types.,erase__IteratorType}
- @sa @ref erase(InteratorType, InteratorType) -- removes the elements in
+ @sa @ref erase(IteratorType, IteratorType) -- removes the elements in
the given range
@sa @ref erase(const typename object_t::key_type&) -- removes the element
from an object at the given key
@@ -3982,13 +3925,11 @@ class basic_json
@since version 1.0.0
*/
- template <class InteratorType, typename
- std::enable_if<
- std::is_same<InteratorType, typename basic_json_t::iterator>::value or
- std::is_same<InteratorType, typename basic_json_t::const_iterator>::value
- , int>::type
- = 0>
- InteratorType erase(InteratorType pos)
+ template<class IteratorType, typename std::enable_if<
+ std::is_same<IteratorType, typename basic_json_t::iterator>::value or
+ std::is_same<IteratorType, typename basic_json_t::const_iterator>::value, int>::type
+ = 0>
+ IteratorType erase(IteratorType pos)
{
// make sure iterator fits the current value
if (this != pos.m_object)
@@ -3996,7 +3937,7 @@ class basic_json
throw std::domain_error("iterator does not fit current value");
}
- InteratorType result = end();
+ IteratorType result = end();
switch (m_type)
{
@@ -4060,7 +4001,7 @@ class basic_json
@return Iterator following the last removed element. If the iterator @a
second refers to the last element, the `end()` iterator is returned.
- @tparam InteratorType an @ref iterator or @ref const_iterator
+ @tparam IteratorType an @ref iterator or @ref const_iterator
@post Invalidates iterators and references at or after the point of the
erase, including the `end()` iterator.
@@ -4083,7 +4024,7 @@ class basic_json
@liveexample{The example shows the result of `erase()` for different JSON
types.,erase__IteratorType_IteratorType}
- @sa @ref erase(InteratorType) -- removes the element at a given position
+ @sa @ref erase(IteratorType) -- removes the element at a given position
@sa @ref erase(const typename object_t::key_type&) -- removes the element
from an object at the given key
@sa @ref erase(const size_type) -- removes the element from an array at
@@ -4091,13 +4032,11 @@ class basic_json
@since version 1.0.0
*/
- template <class InteratorType, typename
- std::enable_if<
- std::is_same<InteratorType, typename basic_json_t::iterator>::value or
- std::is_same<InteratorType, typename basic_json_t::const_iterator>::value
- , int>::type
- = 0>
- InteratorType erase(InteratorType first, InteratorType last)
+ template<class IteratorType, typename std::enable_if<
+ std::is_same<IteratorType, typename basic_json_t::iterator>::value or
+ std::is_same<IteratorType, typename basic_json_t::const_iterator>::value, int>::type
+ = 0>
+ IteratorType erase(IteratorType first, IteratorType last)
{
// make sure iterator fits the current value
if (this != first.m_object or this != last.m_object)
@@ -4105,7 +4044,7 @@ class basic_json
throw std::domain_error("iterators do not fit current value");
}
- InteratorType result = end();
+ IteratorType result = end();
switch (m_type)
{
@@ -4177,8 +4116,8 @@ class basic_json
@liveexample{The example shows the effect of `erase()`.,erase__key_type}
- @sa @ref erase(InteratorType) -- removes the element at a given position
- @sa @ref erase(InteratorType, InteratorType) -- removes the elements in
+ @sa @ref erase(IteratorType) -- removes the element at a given position
+ @sa @ref erase(IteratorType, IteratorType) -- removes the elements in
the given range
@sa @ref erase(const size_type) -- removes the element from an array at
the given index
@@ -4214,8 +4153,8 @@ class basic_json
@liveexample{The example shows the effect of `erase()`.,erase__size_type}
- @sa @ref erase(InteratorType) -- removes the element at a given position
- @sa @ref erase(InteratorType, InteratorType) -- removes the elements in
+ @sa @ref erase(IteratorType) -- removes the element at a given position
+ @sa @ref erase(IteratorType, IteratorType) -- removes the elements in
the given range
@sa @ref erase(const typename object_t::key_type&) -- removes the element
from an object at the given key
@@ -4257,10 +4196,14 @@ class basic_json
element is not found or the JSON value is not an object, end() is
returned.
+ @note This method always returns @ref end() when executed on a JSON type
+ that is not an object.
+
@param[in] key key value of the element to search for
@return Iterator to an element with key equivalent to @a key. If no such
- element is found, past-the-end (see end()) iterator is returned.
+ element is found or the JSON value is not an object, past-the-end (see
+ @ref end()) iterator is returned.
@complexity Logarithmic in the size of the JSON object.
@@ -4303,6 +4246,9 @@ class basic_json
default `std::map` type, the return value will always be `0` (@a key was
not found) or `1` (@a key was found).
+ @note This method always returns `0` when executed on a JSON type that is
+ not an object.
+
@param[in] key key value of the element to count
@return Number of elements with key @a key. If the JSON value is not an
@@ -4862,9 +4808,6 @@ class basic_json
object | `{}`
array | `[]`
- @note Floating-point numbers are set to `0.0` which will be serialized to
- `0`. The vale type remains @ref number_float_t.
-
@complexity Linear in the size of the JSON value.
@liveexample{The example below shows the effect of `clear()` to different
@@ -5110,6 +5053,102 @@ class basic_json
}
/*!
+ @brief add an object to an array
+
+ Creates a JSON value from the passed parameters @a args to the end of the
+ JSON value. If the function is called on a JSON null value, an empty array
+ is created before appending the value created from @a args.
+
+ @param[in] args arguments to forward to a constructor of @ref basic_json
+ @tparam Args compatible types to create a @ref basic_json object
+
+ @throw std::domain_error when called on a type other than JSON array or
+ null; example: `"cannot use emplace_back() with number"`
+
+ @complexity Amortized constant.
+
+ @liveexample{The example shows how `push_back()` can be used to add
+ elements to a JSON array. Note how the `null` value was silently converted
+ to a JSON array.,emplace_back}
+
+ @since version 2.0.8
+ */
+ template<class... Args>
+ void emplace_back(Args&& ... args)
+ {
+ // emplace_back only works for null objects or arrays
+ if (not(is_null() or is_array()))
+ {
+ throw std::domain_error("cannot use emplace_back() with " + type_name());
+ }
+
+ // transform null object into an array
+ if (is_null())
+ {
+ m_type = value_t::array;
+ m_value = value_t::array;
+ assert_invariant();
+ }
+
+ // add element to array (perfect forwarding)
+ m_value.array->emplace_back(std::forward<Args>(args)...);
+ }
+
+ /*!
+ @brief add an object to an object if key does not exist
+
+ Inserts a new element into a JSON object constructed in-place with the given
+ @a args if there is no element with the key in the container. If the
+ function is called on a JSON null value, an empty object is created before
+ appending the value created from @a args.
+
+ @param[in] args arguments to forward to a constructor of @ref basic_json
+ @tparam Args compatible types to create a @ref basic_json object
+
+ @return a pair consisting of an iterator to the inserted element, or the
+ already-existing element if no insertion happened, and a bool
+ denoting whether the insertion took place.
+
+ @throw std::domain_error when called on a type other than JSON object or
+ null; example: `"cannot use emplace() with number"`
+
+ @complexity Logarithmic in the size of the container, O(log(`size()`)).
+
+ @liveexample{The example shows how `emplace()` can be used to add elements
+ to a JSON object. Note how the `null` value was silently converted to a
+ JSON object. Further note how no value is added if there was already one
+ value stored with the same key.,emplace}
+
+ @since version 2.0.8
+ */
+ template<class... Args>
+ std::pair<iterator, bool> emplace(Args&& ... args)
+ {
+ // emplace only works for null objects or arrays
+ if (not(is_null() or is_object()))
+ {
+ throw std::domain_error("cannot use emplace() with " + type_name());
+ }
+
+ // transform null object into an object
+ if (is_null())
+ {
+ m_type = value_t::object;
+ m_value = value_t::object;
+ assert_invariant();
+ }
+
+ // add element to array (perfect forwarding)
+ auto res = m_value.object->emplace(std::forward<Args>(args)...);
+ // create result iterator and set iterator to the result of emplace
+ auto it = begin();
+ it.m_it.object_iterator = res.first;
+
+ // return pair of iterator and boolean
+ return {it, res.second};
+ }
+
+ /*!
@brief inserts element
Inserts element @a val before iterator @a pos.
@@ -5885,7 +5924,7 @@ class basic_json
o.width(0);
// fix locale problems
- const auto old_locale = o.imbue(std::locale(std::locale(), new DecimalSeparator));
+ const auto old_locale = o.imbue(std::locale::classic());
// set precision
// 6, 15 or 16 digits of precision allows round-trip IEEE 754
@@ -5923,9 +5962,45 @@ class basic_json
/// @{
/*!
- @brief deserialize from string
+ @brief deserialize from an array
+
+ This function reads from an array of 1-byte values.
- @param[in] s string to read a serialized JSON value from
+ @pre Each element of the container has a size of 1 byte. Violating this
+ precondition yields undefined behavior. **This precondition is enforced
+ with a static assertion.**
+
+ @param[in] array array to read from
+ @param[in] cb a parser callback function of type @ref parser_callback_t
+ which is used to control the deserialization by filtering unwanted values
+ (optional)
+
+ @return result of the deserialization
+
+ @complexity Linear in the length of the input. The parser is a predictive
+ LL(1) parser. The complexity can be higher if the parser callback function
+ @a cb has a super-linear complexity.
+
+ @note A UTF-8 byte order mark is silently ignored.
+
+ @liveexample{The example below demonstrates the `parse()` function reading
+ from an array.,parse__array__parser_callback_t}
+
+ @since version 2.0.3
+ */
+ template<class T, std::size_t N>
+ static basic_json parse(T (&array)[N],
+ const parser_callback_t cb = nullptr)
+ {
+ // delegate the call to the iterator-range parse overload
+ return parse(std::begin(array), std::end(array), cb);
+ }
+
+ /*!
+ @brief deserialize from string literal
+
+ @tparam CharT character/literal type with size of 1 byte
+ @param[in] s string literal to read a serialized JSON value from
@param[in] cb a parser callback function of type @ref parser_callback_t
which is used to control the deserialization by filtering unwanted values
(optional)
@@ -5937,6 +6012,8 @@ class basic_json
@a cb has a super-linear complexity.
@note A UTF-8 byte order mark is silently ignored.
+ @note String containers like `std::string` or @ref string_t can be parsed
+ with @ref parse(const ContiguousContainer&, const parser_callback_t)
@liveexample{The example below demonstrates the `parse()` function with
and without callback function.,parse__string__parser_callback_t}
@@ -5944,12 +6021,16 @@ class basic_json
@sa @ref parse(std::istream&, const parser_callback_t) for a version that
reads from an input stream
- @since version 1.0.0
+ @since version 1.0.0 (originally for @ref string_t)
*/
- static basic_json parse(const string_t& s,
+ template<typename CharT, typename std::enable_if<
+ std::is_pointer<CharT>::value and
+ std::is_integral<typename std::remove_pointer<CharT>::type>::value and
+ sizeof(typename std::remove_pointer<CharT>::type) == 1, int>::type = 0>
+ static basic_json parse(const CharT s,
const parser_callback_t cb = nullptr)
{
- return parser(s, cb).parse();
+ return parser(reinterpret_cast<const char*>(s), cb).parse();
}
/*!
@@ -5971,7 +6052,7 @@ 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&, const parser_callback_t) for a version
+ @sa @ref parse(const CharT, const parser_callback_t) for a version
that reads from a string
@since version 1.0.0
@@ -5992,6 +6073,130 @@ class basic_json
}
/*!
+ @brief deserialize from an iterator range with contiguous storage
+
+ This function reads from an iterator range of a container with contiguous
+ storage of 1-byte values. Compatible container types include
+ `std::vector`, `std::string`, `std::array`, `std::valarray`, and
+ `std::initializer_list`. Furthermore, C-style arrays can be used with
+ `std::begin()`/`std::end()`. User-defined containers can be used as long
+ as they implement random-access iterators and a contiguous storage.
+
+ @pre The iterator range is contiguous. Violating this precondition yields
+ undefined behavior. **This precondition is enforced with an assertion.**
+ @pre Each element in the range has a size of 1 byte. Violating this
+ precondition yields undefined behavior. **This precondition is enforced
+ with a static assertion.**
+
+ @warning There is no way to enforce all preconditions at compile-time. If
+ the function is called with noncompliant iterators and with
+ assertions switched off, the behavior is undefined and will most
+ likely yield segmentation violation.
+
+ @tparam IteratorType iterator of container with contiguous storage
+ @param[in] first begin of the range to parse (included)
+ @param[in] last end of the range to parse (excluded)
+ @param[in] cb a parser callback function of type @ref parser_callback_t
+ which is used to control the deserialization by filtering unwanted values
+ (optional)
+
+ @return result of the deserialization
+
+ @complexity Linear in the length of the input. The parser is a predictive
+ LL(1) parser. The complexity can be higher if the parser callback function
+ @a cb has a super-linear complexity.
+
+ @note A UTF-8 byte order mark is silently ignored.
+
+ @liveexample{The example below demonstrates the `parse()` function reading
+ from an iterator range.,parse__iteratortype__parser_callback_t}
+
+ @since version 2.0.3
+ */
+ template<class IteratorType, typename std::enable_if<
+ std::is_base_of<
+ std::random_access_iterator_tag,
+ typename std::iterator_traits<IteratorType>::iterator_category>::value, int>::type = 0>
+ static basic_json parse(IteratorType first, IteratorType last,
+ const parser_callback_t cb = nullptr)
+ {
+ // assertion to check that the iterator range is indeed contiguous,
+ // see http://stackoverflow.com/a/35008842/266378 for more discussion
+ assert(std::accumulate(first, last, std::make_pair<bool, int>(true, 0),
+ [&first](std::pair<bool, int> res, decltype(*first) val)
+ {
+ res.first &= (val == *(std::next(std::addressof(*first), res.second++)));
+ return res;
+ }).first);
+
+ // assertion to check that each element is 1 byte long
+ static_assert(sizeof(typename std::iterator_traits<IteratorType>::value_type) == 1,
+ "each element in the iterator range must have the size of 1 byte");
+
+ // if iterator range is empty, create a parser with an empty string
+ // to generate "unexpected EOF" error message
+ if (std::distance(first, last) <= 0)
+ {
+ return parser("").parse();
+ }
+
+ return parser(first, last, cb).parse();
+ }
+
+ /*!
+ @brief deserialize from a container with contiguous storage
+
+ This function reads from a container with contiguous storage of 1-byte
+ values. Compatible container types include `std::vector`, `std::string`,
+ `std::array`, and `std::initializer_list`. User-defined containers can be
+ used as long as they implement random-access iterators and a contiguous
+ storage.
+
+ @pre The container storage is contiguous. Violating this precondition
+ yields undefined behavior. **This precondition is enforced with an
+ assertion.**
+ @pre Each element of the container has a size of 1 byte. Violating this
+ precondition yields undefined behavior. **This precondition is enforced
+ with a static assertion.**
+
+ @warning There is no way to enforce all preconditions at compile-time. If
+ the function is called with a noncompliant container and with
+ assertions switched off, the behavior is undefined and will most
+ likely yield segmentation violation.
+
+ @tparam ContiguousContainer container type with contiguous storage
+ @param[in] c container to read from
+ @param[in] cb a parser callback function of type @ref parser_callback_t
+ which is used to control the deserialization by filtering unwanted values
+ (optional)
+
+ @return result of the deserialization
+
+ @complexity Linear in the length of the input. The parser is a predictive
+ LL(1) parser. The complexity can be higher if the parser callback function
+ @a cb has a super-linear complexity.
+
+ @note A UTF-8 byte order mark is silently ignored.
+
+ @liveexample{The example below demonstrates the `parse()` function reading
+ from a contiguous container.,parse__contiguouscontainer__parser_callback_t}
+
+ @since version 2.0.3
+ */
+ template<class ContiguousContainer, typename std::enable_if<
+ not std::is_pointer<ContiguousContainer>::value and
+ std::is_base_of<
+ std::random_access_iterator_tag,
+ typename std::iterator_traits<decltype(std::begin(std::declval<ContiguousContainer const>()))>::iterator_category>::value
+ , int>::type = 0>
+ static basic_json parse(const ContiguousContainer& c,
+ const parser_callback_t cb = nullptr)
+ {
+ // delegate the call to the iterator-range parse overload
+ return parse(std::begin(c), std::end(c), cb);
+ }
+
+ /*!
@brief deserialize from stream
Deserializes an input stream to a JSON value.
@@ -6032,6 +6237,1496 @@ class basic_json
/// @}
+ //////////////////////////////////////////
+ // binary serialization/deserialization //
+ //////////////////////////////////////////
+
+ /// @name binary serialization/deserialization support
+ /// @{
+
+ private:
+ template<typename T>
+ static void add_to_vector(std::vector<uint8_t>& vec, size_t bytes, const T number)
+ {
+ assert(bytes == 1 or bytes == 2 or bytes == 4 or bytes == 8);
+
+ switch (bytes)
+ {
+ case 8:
+ {
+ vec.push_back(static_cast<uint8_t>((number >> 070) & 0xff));
+ vec.push_back(static_cast<uint8_t>((number >> 060) & 0xff));
+ vec.push_back(static_cast<uint8_t>((number >> 050) & 0xff));
+ vec.push_back(static_cast<uint8_t>((number >> 040) & 0xff));
+ // intentional fall-through
+ }
+
+ case 4:
+ {
+ vec.push_back(static_cast<uint8_t>((number >> 030) & 0xff));
+ vec.push_back(static_cast<uint8_t>((number >> 020) & 0xff));
+ // intentional fall-through
+ }
+
+ case 2:
+ {
+ vec.push_back(static_cast<uint8_t>((number >> 010) & 0xff));
+ // intentional fall-through
+ }
+
+ case 1:
+ {
+ vec.push_back(static_cast<uint8_t>(number & 0xff));
+ break;
+ }
+ }
+ }
+
+ /*!
+ @brief take sufficient bytes from a vector to fill an integer variable
+
+ In the context of binary serialization formats, we need to read several
+ bytes from a byte vector and combine them to multi-byte integral data
+ types.
+
+ @param[in] vec byte vector to read from
+ @param[in] current_index the position in the vector after which to read
+
+ @return the next sizeof(T) bytes from @a vec, in reverse order as T
+
+ @tparam T the integral return type
+
+ @throw std::out_of_range if there are less than sizeof(T)+1 bytes in the
+ vector @a vec to read
+
+ In the for loop, the bytes from the vector are copied in reverse order into
+ the return value. In the figures below, let sizeof(T)=4 and `i` be the loop
+ variable.
+
+ Precondition:
+
+ vec: | | | a | b | c | d | T: | | | | |
+ ^ ^ ^ ^
+ current_index i ptr sizeof(T)
+
+ Postcondition:
+
+ vec: | | | a | b | c | d | T: | d | c | b | a |
+ ^ ^ ^
+ | i ptr
+ current_index
+
+ @sa Code adapted from <http://stackoverflow.com/a/41031865/266378>.
+ */
+ template<typename T>
+ static T get_from_vector(const std::vector<uint8_t>& vec, const size_t current_index)
+ {
+ if (current_index + sizeof(T) + 1 > vec.size())
+ {
+ throw std::out_of_range("cannot read " + std::to_string(sizeof(T)) + " bytes from vector");
+ }
+
+ T result;
+ uint8_t* ptr = reinterpret_cast<uint8_t*>(&result);
+ for (size_t i = 0; i < sizeof(T); ++i)
+ {
+ *ptr++ = vec[current_index + sizeof(T) - i];
+ }
+ return result;
+ }
+
+ /*!
+ @brief create a MessagePack serialization of a given JSON value
+
+ This is a straightforward implementation of the MessagePack specification.
+
+ @param[in] j JSON value to serialize
+ @param[in,out] v byte vector to write the serialization to
+
+ @sa https://github.com/msgpack/msgpack/blob/master/spec.md
+ */
+ static void to_msgpack_internal(const basic_json& j, std::vector<uint8_t>& v)
+ {
+ switch (j.type())
+ {
+ case value_t::null:
+ {
+ // nil
+ v.push_back(0xc0);
+ break;
+ }
+
+ case value_t::boolean:
+ {
+ // true and false
+ v.push_back(j.m_value.boolean ? 0xc3 : 0xc2);
+ break;
+ }
+
+ case value_t::number_integer:
+ {
+ if (j.m_value.number_integer >= 0)
+ {
+ // MessagePack does not differentiate between positive
+ // signed integers and unsigned integers. Therefore, we used
+ // the code from the value_t::number_unsigned case here.
+ if (j.m_value.number_unsigned < 128)
+ {
+ // positive fixnum
+ add_to_vector(v, 1, j.m_value.number_unsigned);
+ }
+ else if (j.m_value.number_unsigned <= UINT8_MAX)
+ {
+ // uint 8
+ v.push_back(0xcc);
+ add_to_vector(v, 1, j.m_value.number_unsigned);
+ }
+ else if (j.m_value.number_unsigned <= UINT16_MAX)
+ {
+ // uint 16
+ v.push_back(0xcd);
+ add_to_vector(v, 2, j.m_value.number_unsigned);
+ }
+ else if (j.m_value.number_unsigned <= UINT32_MAX)
+ {
+ // uint 32
+ v.push_back(0xce);
+ add_to_vector(v, 4, j.m_value.number_unsigned);
+ }
+ else if (j.m_value.number_unsigned <= UINT64_MAX)
+ {
+ // uint 64
+ v.push_back(0xcf);
+ add_to_vector(v, 8, j.m_value.number_unsigned);
+ }
+ }
+ else
+ {
+ if (j.m_value.number_integer >= -32)
+ {
+ // negative fixnum
+ add_to_vector(v, 1, j.m_value.number_integer);
+ }
+ else if (j.m_value.number_integer >= INT8_MIN and j.m_value.number_integer <= INT8_MAX)
+ {
+ // int 8
+ v.push_back(0xd0);
+ add_to_vector(v, 1, j.m_value.number_integer);
+ }
+ else if (j.m_value.number_integer >= INT16_MIN and j.m_value.number_integer <= INT16_MAX)
+ {
+ // int 16
+ v.push_back(0xd1);
+ add_to_vector(v, 2, j.m_value.number_integer);
+ }
+ else if (j.m_value.number_integer >= INT32_MIN and j.m_value.number_integer <= INT32_MAX)
+ {
+ // int 32
+ v.push_back(0xd2);
+ add_to_vector(v, 4, j.m_value.number_integer);
+ }
+ else if (j.m_value.number_integer >= INT64_MIN and j.m_value.number_integer <= INT64_MAX)
+ {
+ // int 64
+ v.push_back(0xd3);
+ add_to_vector(v, 8, j.m_value.number_integer);
+ }
+ }
+ break;
+ }
+
+ case value_t::number_unsigned:
+ {
+ if (j.m_value.number_unsigned < 128)
+ {
+ // positive fixnum
+ add_to_vector(v, 1, j.m_value.number_unsigned);
+ }
+ else if (j.m_value.number_unsigned <= UINT8_MAX)
+ {
+ // uint 8
+ v.push_back(0xcc);
+ add_to_vector(v, 1, j.m_value.number_unsigned);
+ }
+ else if (j.m_value.number_unsigned <= UINT16_MAX)
+ {
+ // uint 16
+ v.push_back(0xcd);
+ add_to_vector(v, 2, j.m_value.number_unsigned);
+ }
+ else if (j.m_value.number_unsigned <= UINT32_MAX)
+ {
+ // uint 32
+ v.push_back(0xce);
+ add_to_vector(v, 4, j.m_value.number_unsigned);
+ }
+ else if (j.m_value.number_unsigned <= UINT64_MAX)
+ {
+ // uint 64
+ v.push_back(0xcf);
+ add_to_vector(v, 8, j.m_value.number_unsigned);
+ }
+ break;
+ }
+
+ case value_t::number_float:
+ {
+ // float 64
+ v.push_back(0xcb);
+ const uint8_t* helper = reinterpret_cast<const uint8_t*>(&(j.m_value.number_float));
+ for (size_t i = 0; i < 8; ++i)
+ {
+ v.push_back(helper[7 - i]);
+ }
+ break;
+ }
+
+ case value_t::string:
+ {
+ const auto N = j.m_value.string->size();
+ if (N <= 31)
+ {
+ // fixstr
+ v.push_back(static_cast<uint8_t>(0xa0 | N));
+ }
+ else if (N <= 255)
+ {
+ // str 8
+ v.push_back(0xd9);
+ add_to_vector(v, 1, N);
+ }
+ else if (N <= 65535)
+ {
+ // str 16
+ v.push_back(0xda);
+ add_to_vector(v, 2, N);
+ }
+ else if (N <= 4294967295)
+ {
+ // str 32
+ v.push_back(0xdb);
+ add_to_vector(v, 4, N);
+ }
+
+ // append string
+ std::copy(j.m_value.string->begin(), j.m_value.string->end(),
+ std::back_inserter(v));
+ break;
+ }
+
+ case value_t::array:
+ {
+ const auto N = j.m_value.array->size();
+ if (N <= 15)
+ {
+ // fixarray
+ v.push_back(static_cast<uint8_t>(0x90 | N));
+ }
+ else if (N <= 0xffff)
+ {
+ // array 16
+ v.push_back(0xdc);
+ add_to_vector(v, 2, N);
+ }
+ else if (N <= 0xffffffff)
+ {
+ // array 32
+ v.push_back(0xdd);
+ add_to_vector(v, 4, N);
+ }
+
+ // append each element
+ for (const auto& el : *j.m_value.array)
+ {
+ to_msgpack_internal(el, v);
+ }
+ break;
+ }
+
+ case value_t::object:
+ {
+ const auto N = j.m_value.object->size();
+ if (N <= 15)
+ {
+ // fixmap
+ v.push_back(static_cast<uint8_t>(0x80 | (N & 0xf)));
+ }
+ else if (N <= 65535)
+ {
+ // map 16
+ v.push_back(0xde);
+ add_to_vector(v, 2, N);
+ }
+ else if (N <= 4294967295)
+ {
+ // map 32
+ v.push_back(0xdf);
+ add_to_vector(v, 4, N);
+ }
+
+ // append each element
+ for (const auto& el : *j.m_value.object)
+ {
+ to_msgpack_internal(el.first, v);
+ to_msgpack_internal(el.second, v);
+ }
+ break;
+ }
+
+ default:
+ {
+ break;
+ }
+ }
+ }
+
+ /*!
+ @brief create a CBOR serialization of a given JSON value
+
+ This is a straightforward implementation of the CBOR specification.
+
+ @param[in] j JSON value to serialize
+ @param[in,out] v byte vector to write the serialization to
+
+ @sa https://tools.ietf.org/html/rfc7049
+ */
+ static void to_cbor_internal(const basic_json& j, std::vector<uint8_t>& v)
+ {
+ switch (j.type())
+ {
+ case value_t::null:
+ {
+ v.push_back(0xf6);
+ break;
+ }
+
+ case value_t::boolean:
+ {
+ v.push_back(j.m_value.boolean ? 0xf5 : 0xf4);
+ break;
+ }
+
+ case value_t::number_integer:
+ {
+ if (j.m_value.number_integer >= 0)
+ {
+ // CBOR does not differentiate between positive signed
+ // integers and unsigned integers. Therefore, we used the
+ // code from the value_t::number_unsigned case here.
+ if (j.m_value.number_integer <= 0x17)
+ {
+ add_to_vector(v, 1, j.m_value.number_integer);
+ }
+ else if (j.m_value.number_integer <= UINT8_MAX)
+ {
+ v.push_back(0x18);
+ // one-byte uint8_t
+ add_to_vector(v, 1, j.m_value.number_integer);
+ }
+ else if (j.m_value.number_integer <= UINT16_MAX)
+ {
+ v.push_back(0x19);
+ // two-byte uint16_t
+ add_to_vector(v, 2, j.m_value.number_integer);
+ }
+ else if (j.m_value.number_integer <= UINT32_MAX)
+ {
+ v.push_back(0x1a);
+ // four-byte uint32_t
+ add_to_vector(v, 4, j.m_value.number_integer);
+ }
+ else
+ {
+ v.push_back(0x1b);
+ // eight-byte uint64_t
+ add_to_vector(v, 8, j.m_value.number_integer);
+ }
+ }
+ else
+ {
+ // The conversions below encode the sign in the first byte,
+ // and the value is converted to a positive number.
+ const auto positive_number = -1 - j.m_value.number_integer;
+ if (j.m_value.number_integer >= -24)
+ {
+ v.push_back(static_cast<uint8_t>(0x20 + positive_number));
+ }
+ else if (positive_number <= UINT8_MAX)
+ {
+ // int 8
+ v.push_back(0x38);
+ add_to_vector(v, 1, positive_number);
+ }
+ else if (positive_number <= UINT16_MAX)
+ {
+ // int 16
+ v.push_back(0x39);
+ add_to_vector(v, 2, positive_number);
+ }
+ else if (positive_number <= UINT32_MAX)
+ {
+ // int 32
+ v.push_back(0x3a);
+ add_to_vector(v, 4, positive_number);
+ }
+ else
+ {
+ // int 64
+ v.push_back(0x3b);
+ add_to_vector(v, 8, positive_number);
+ }
+ }
+ break;
+ }
+
+ case value_t::number_unsigned:
+ {
+ if (j.m_value.number_unsigned <= 0x17)
+ {
+ v.push_back(static_cast<uint8_t>(j.m_value.number_unsigned));
+ }
+ else if (j.m_value.number_unsigned <= 0xff)
+ {
+ v.push_back(0x18);
+ // one-byte uint8_t
+ add_to_vector(v, 1, j.m_value.number_unsigned);
+ }
+ else if (j.m_value.number_unsigned <= 0xffff)
+ {
+ v.push_back(0x19);
+ // two-byte uint16_t
+ add_to_vector(v, 2, j.m_value.number_unsigned);
+ }
+ else if (j.m_value.number_unsigned <= 0xffffffff)
+ {
+ v.push_back(0x1a);
+ // four-byte uint32_t
+ add_to_vector(v, 4, j.m_value.number_unsigned);
+ }
+ else if (j.m_value.number_unsigned <= 0xffffffffffffffff)
+ {
+ v.push_back(0x1b);
+ // eight-byte uint64_t
+ add_to_vector(v, 8, j.m_value.number_unsigned);
+ }
+ break;
+ }
+
+ case value_t::number_float:
+ {
+ // Double-Precision Float
+ v.push_back(0xfb);
+ const uint8_t* helper = reinterpret_cast<const uint8_t*>(&(j.m_value.number_float));
+ for (size_t i = 0; i < 8; ++i)
+ {
+ v.push_back(helper[7 - i]);
+ }
+ break;
+ }
+
+ case value_t::string:
+ {
+ const auto N = j.m_value.string->size();
+ if (N <= 0x17)
+ {
+ v.push_back(0x60 + N); // 1 byte for string + size
+ }
+ else if (N <= 0xff)
+ {
+ v.push_back(0x78); // one-byte uint8_t for N
+ add_to_vector(v, 1, N);
+ }
+ else if (N <= 0xffff)
+ {
+ v.push_back(0x79); // two-byte uint16_t for N
+ add_to_vector(v, 2, N);
+ }
+ else if (N <= 0xffffffff)
+ {
+ v.push_back(0x7a); // four-byte uint32_t for N
+ add_to_vector(v, 4, N);
+ }
+ // LCOV_EXCL_START
+ else if (N <= 0xffffffffffffffff)
+ {
+ v.push_back(0x7b); // eight-byte uint64_t for N
+ add_to_vector(v, 8, N);
+ }
+ // LCOV_EXCL_STOP
+
+ // append string
+ std::copy(j.m_value.string->begin(), j.m_value.string->end(),
+ std::back_inserter(v));
+ break;
+ }
+
+ case value_t::array:
+ {
+ const auto N = j.m_value.array->size();
+ if (N <= 0x17)
+ {
+ v.push_back(0x80 + N); // 1 byte for array + size
+ }
+ else if (N <= 0xff)
+ {
+ v.push_back(0x98); // one-byte uint8_t for N
+ add_to_vector(v, 1, N);
+ }
+ else if (N <= 0xffff)
+ {
+ v.push_back(0x99); // two-byte uint16_t for N
+ add_to_vector(v, 2, N);
+ }
+ else if (N <= 0xffffffff)
+ {
+ v.push_back(0x9a); // four-byte uint32_t for N
+ add_to_vector(v, 4, N);
+ }
+ // LCOV_EXCL_START
+ else if (N <= 0xffffffffffffffff)
+ {
+ v.push_back(0x9b); // eight-byte uint64_t for N
+ add_to_vector(v, 8, N);
+ }
+ // LCOV_EXCL_STOP
+
+ // append each element
+ for (const auto& el : *j.m_value.array)
+ {
+ to_cbor_internal(el, v);
+ }
+ break;
+ }
+
+ case value_t::object:
+ {
+ const auto N = j.m_value.object->size();
+ if (N <= 0x17)
+ {
+ v.push_back(0xa0 + N); // 1 byte for object + size
+ }
+ else if (N <= 0xff)
+ {
+ v.push_back(0xb8);
+ add_to_vector(v, 1, N); // one-byte uint8_t for N
+ }
+ else if (N <= 0xffff)
+ {
+ v.push_back(0xb9);
+ add_to_vector(v, 2, N); // two-byte uint16_t for N
+ }
+ else if (N <= 0xffffffff)
+ {
+ v.push_back(0xba);
+ add_to_vector(v, 4, N); // four-byte uint32_t for N
+ }
+ // LCOV_EXCL_START
+ else if (N <= 0xffffffffffffffff)
+ {
+ v.push_back(0xbb);
+ add_to_vector(v, 8, N); // eight-byte uint64_t for N
+ }
+ // LCOV_EXCL_STOP
+
+ // append each element
+ for (const auto& el : *j.m_value.object)
+ {
+ to_cbor_internal(el.first, v);
+ to_cbor_internal(el.second, v);
+ }
+ break;
+ }
+
+ default:
+ {
+ break;
+ }
+ }
+ }
+
+
+ /*
+ @brief checks if given lengths do not exceed the size of a given vector
+
+ To secure the access to the byte vector during CBOR/MessagePack
+ deserialization, bytes are copied from the vector into buffers. This
+ function checks if the number of bytes to copy (@a len) does not exceed the
+ size @s size of the vector. Additionally, an @a offset is given from where
+ to start reading the bytes.
+
+ This function checks whether reading the bytes is safe; that is, offset is a
+ valid index in the vector, offset+len
+
+ @param[in] size size of the byte vector
+ @param[in] len number of bytes to read
+ @param[in] offset offset where to start reading
+
+ vec: x x x x x X X X X X
+ ^ ^ ^
+ 0 offset len
+
+ @throws out_of_range if `len > v.size()`
+ */
+ static void check_length(const size_t size, const size_t len, const size_t offset)
+ {
+ // simple case: requested length is greater than the vector's length
+ if (len > size or offset > size)
+ {
+ throw std::out_of_range("len out of range");
+ }
+
+ // second case: adding offset would result in overflow
+ if ((size > (std::numeric_limits<size_t>::max() - offset)))
+ {
+ throw std::out_of_range("len+offset out of range");
+ }
+
+ // last case: reading past the end of the vector
+ if (len + offset > size)
+ {
+ throw std::out_of_range("len+offset out of range");
+ }
+ }
+
+ /*!
+ @brief create a JSON value from a given MessagePack vector
+
+ @param[in] v MessagePack serialization
+ @param[in] idx byte index to start reading from @a v
+
+ @return deserialized JSON value
+
+ @throw std::invalid_argument if unsupported features from MessagePack were
+ used in the given vector @a v or if the input is not valid MessagePack
+ @throw std::out_of_range if the given vector ends prematurely
+
+ @sa https://github.com/msgpack/msgpack/blob/master/spec.md
+ */
+ static basic_json from_msgpack_internal(const std::vector<uint8_t>& v, size_t& idx)
+ {
+ // make sure reading 1 byte is safe
+ check_length(v.size(), 1, idx);
+
+ // store and increment index
+ const size_t current_idx = idx++;
+
+ if (v[current_idx] <= 0xbf)
+ {
+ if (v[current_idx] <= 0x7f) // positive fixint
+ {
+ return v[current_idx];
+ }
+ else if (v[current_idx] <= 0x8f) // fixmap
+ {
+ basic_json result = value_t::object;
+ const size_t len = v[current_idx] & 0x0f;
+ for (size_t i = 0; i < len; ++i)
+ {
+ std::string key = from_msgpack_internal(v, idx);
+ result[key] = from_msgpack_internal(v, idx);
+ }
+ return result;
+ }
+ else if (v[current_idx] <= 0x9f) // fixarray
+ {
+ basic_json result = value_t::array;
+ const size_t len = v[current_idx] & 0x0f;
+ for (size_t i = 0; i < len; ++i)
+ {
+ result.push_back(from_msgpack_internal(v, idx));
+ }
+ return result;
+ }
+ else // fixstr
+ {
+ const size_t len = v[current_idx] & 0x1f;
+ const size_t offset = current_idx + 1;
+ idx += len; // skip content bytes
+ check_length(v.size(), len, offset);
+ return std::string(reinterpret_cast<const char*>(v.data()) + offset, len);
+ }
+ }
+ else if (v[current_idx] >= 0xe0) // negative fixint
+ {
+ return static_cast<int8_t>(v[current_idx]);
+ }
+ else
+ {
+ switch (v[current_idx])
+ {
+ case 0xc0: // nil
+ {
+ return value_t::null;
+ }
+
+ case 0xc2: // false
+ {
+ return false;
+ }
+
+ case 0xc3: // true
+ {
+ return true;
+ }
+
+ case 0xca: // float 32
+ {
+ // copy bytes in reverse order into the double variable
+ check_length(v.size(), sizeof(float), 1);
+ float res;
+ for (size_t byte = 0; byte < sizeof(float); ++byte)
+ {
+ reinterpret_cast<uint8_t*>(&res)[sizeof(float) - byte - 1] = v[current_idx + 1 + byte];
+ }
+ idx += sizeof(float); // skip content bytes
+ return res;
+ }
+
+ case 0xcb: // float 64
+ {
+ // copy bytes in reverse order into the double variable
+ check_length(v.size(), sizeof(double), 1);
+ double res;
+ for (size_t byte = 0; byte < sizeof(double); ++byte)
+ {
+ reinterpret_cast<uint8_t*>(&res)[sizeof(double) - byte - 1] = v[current_idx + 1 + byte];
+ }
+ idx += sizeof(double); // skip content bytes
+ return res;
+ }
+
+ case 0xcc: // uint 8
+ {
+ idx += 1; // skip content byte
+ return get_from_vector<uint8_t>(v, current_idx);
+ }
+
+ case 0xcd: // uint 16
+ {
+ idx += 2; // skip 2 content bytes
+ return get_from_vector<uint16_t>(v, current_idx);
+ }
+
+ case 0xce: // uint 32
+ {
+ idx += 4; // skip 4 content bytes
+ return get_from_vector<uint32_t>(v, current_idx);
+ }
+
+ case 0xcf: // uint 64
+ {
+ idx += 8; // skip 8 content bytes
+ return get_from_vector<uint64_t>(v, current_idx);
+ }
+
+ case 0xd0: // int 8
+ {
+ idx += 1; // skip content byte
+ return get_from_vector<int8_t>(v, current_idx);
+ }
+
+ case 0xd1: // int 16
+ {
+ idx += 2; // skip 2 content bytes
+ return get_from_vector<int16_t>(v, current_idx);
+ }
+
+ case 0xd2: // int 32
+ {
+ idx += 4; // skip 4 content bytes
+ return get_from_vector<int32_t>(v, current_idx);
+ }
+
+ case 0xd3: // int 64
+ {
+ idx += 8; // skip 8 content bytes
+ return get_from_vector<int64_t>(v, current_idx);
+ }
+
+ case 0xd9: // str 8
+ {
+ const auto len = static_cast<size_t>(get_from_vector<uint8_t>(v, current_idx));
+ const size_t offset = current_idx + 2;
+ idx += len + 1; // skip size byte + content bytes
+ check_length(v.size(), len, offset);
+ return std::string(reinterpret_cast<const char*>(v.data()) + offset, len);
+ }
+
+ case 0xda: // str 16
+ {
+ const auto len = static_cast<size_t>(get_from_vector<uint16_t>(v, current_idx));
+ const size_t offset = current_idx + 3;
+ idx += len + 2; // skip 2 size bytes + content bytes
+ check_length(v.size(), len, offset);
+ return std::string(reinterpret_cast<const char*>(v.data()) + offset, len);
+ }
+
+ case 0xdb: // str 32
+ {
+ const auto len = static_cast<size_t>(get_from_vector<uint32_t>(v, current_idx));
+ const size_t offset = current_idx + 5;
+ idx += len + 4; // skip 4 size bytes + content bytes
+ check_length(v.size(), len, offset);
+ return std::string(reinterpret_cast<const char*>(v.data()) + offset, len);
+ }
+
+ case 0xdc: // array 16
+ {
+ basic_json result = value_t::array;
+ const auto len = static_cast<size_t>(get_from_vector<uint16_t>(v, current_idx));
+ idx += 2; // skip 2 size bytes
+ for (size_t i = 0; i < len; ++i)
+ {
+ result.push_back(from_msgpack_internal(v, idx));
+ }
+ return result;
+ }
+
+ case 0xdd: // array 32
+ {
+ basic_json result = value_t::array;
+ const auto len = static_cast<size_t>(get_from_vector<uint32_t>(v, current_idx));
+ idx += 4; // skip 4 size bytes
+ for (size_t i = 0; i < len; ++i)
+ {
+ result.push_back(from_msgpack_internal(v, idx));
+ }
+ return result;
+ }
+
+ case 0xde: // map 16
+ {
+ basic_json result = value_t::object;
+ const auto len = static_cast<size_t>(get_from_vector<uint16_t>(v, current_idx));
+ idx += 2; // skip 2 size bytes
+ for (size_t i = 0; i < len; ++i)
+ {
+ std::string key = from_msgpack_internal(v, idx);
+ result[key] = from_msgpack_internal(v, idx);
+ }
+ return result;
+ }
+
+ case 0xdf: // map 32
+ {
+ basic_json result = value_t::object;
+ const auto len = static_cast<size_t>(get_from_vector<uint32_t>(v, current_idx));
+ idx += 4; // skip 4 size bytes
+ for (size_t i = 0; i < len; ++i)
+ {
+ std::string key = from_msgpack_internal(v, idx);
+ result[key] = from_msgpack_internal(v, idx);
+ }
+ return result;
+ }
+
+ default:
+ {
+ throw std::invalid_argument("error parsing a msgpack @ " + std::to_string(current_idx) + ": " + std::to_string(static_cast<int>(v[current_idx])));
+ }
+ }
+ }
+ }
+
+ /*!
+ @brief create a JSON value from a given CBOR vector
+
+ @param[in] v CBOR serialization
+ @param[in] idx byte index to start reading from @a v
+
+ @return deserialized JSON value
+
+ @throw std::invalid_argument if unsupported features from CBOR were used in
+ the given vector @a v or if the input is not valid CBOR
+ @throw std::out_of_range if the given vector ends prematurely
+
+ @sa https://tools.ietf.org/html/rfc7049
+ */
+ static basic_json from_cbor_internal(const std::vector<uint8_t>& v, size_t& idx)
+ {
+ // store and increment index
+ const size_t current_idx = idx++;
+
+ switch (v.at(current_idx))
+ {
+ // Integer 0x00..0x17 (0..23)
+ case 0x00:
+ case 0x01:
+ case 0x02:
+ case 0x03:
+ case 0x04:
+ case 0x05:
+ case 0x06:
+ case 0x07:
+ case 0x08:
+ case 0x09:
+ case 0x0a:
+ case 0x0b:
+ case 0x0c:
+ case 0x0d:
+ case 0x0e:
+ case 0x0f:
+ case 0x10:
+ case 0x11:
+ case 0x12:
+ case 0x13:
+ case 0x14:
+ case 0x15:
+ case 0x16:
+ case 0x17:
+ {
+ return v[current_idx];
+ }
+
+ case 0x18: // Unsigned integer (one-byte uint8_t follows)
+ {
+ idx += 1; // skip content byte
+ return get_from_vector<uint8_t>(v, current_idx);
+ }
+
+ case 0x19: // Unsigned integer (two-byte uint16_t follows)
+ {
+ idx += 2; // skip 2 content bytes
+ return get_from_vector<uint16_t>(v, current_idx);
+ }
+
+ case 0x1a: // Unsigned integer (four-byte uint32_t follows)
+ {
+ idx += 4; // skip 4 content bytes
+ return get_from_vector<uint32_t>(v, current_idx);
+ }
+
+ case 0x1b: // Unsigned integer (eight-byte uint64_t follows)
+ {
+ idx += 8; // skip 8 content bytes
+ return get_from_vector<uint64_t>(v, current_idx);
+ }
+
+ // Negative integer -1-0x00..-1-0x17 (-1..-24)
+ case 0x20:
+ case 0x21:
+ case 0x22:
+ case 0x23:
+ case 0x24:
+ case 0x25:
+ case 0x26:
+ case 0x27:
+ case 0x28:
+ case 0x29:
+ case 0x2a:
+ case 0x2b:
+ case 0x2c:
+ case 0x2d:
+ case 0x2e:
+ case 0x2f:
+ case 0x30:
+ case 0x31:
+ case 0x32:
+ case 0x33:
+ case 0x34:
+ case 0x35:
+ case 0x36:
+ case 0x37:
+ {
+ return static_cast<int8_t>(0x20 - 1 - v[current_idx]);
+ }
+
+ case 0x38: // Negative integer (one-byte uint8_t follows)
+ {
+ idx += 1; // skip content byte
+ // must be uint8_t !
+ return static_cast<number_integer_t>(-1) - get_from_vector<uint8_t>(v, current_idx);
+ }
+
+ case 0x39: // Negative integer -1-n (two-byte uint16_t follows)
+ {
+ idx += 2; // skip 2 content bytes
+ return static_cast<number_integer_t>(-1) - get_from_vector<uint16_t>(v, current_idx);
+ }
+
+ case 0x3a: // Negative integer -1-n (four-byte uint32_t follows)
+ {
+ idx += 4; // skip 4 content bytes
+ return static_cast<number_integer_t>(-1) - get_from_vector<uint32_t>(v, current_idx);
+ }
+
+ case 0x3b: // Negative integer -1-n (eight-byte uint64_t follows)
+ {
+ idx += 8; // skip 8 content bytes
+ return static_cast<number_integer_t>(-1) - static_cast<number_integer_t>(get_from_vector<uint64_t>(v, current_idx));
+ }
+
+ // UTF-8 string (0x00..0x17 bytes follow)
+ case 0x60:
+ case 0x61:
+ case 0x62:
+ case 0x63:
+ case 0x64:
+ case 0x65:
+ case 0x66:
+ case 0x67:
+ case 0x68:
+ case 0x69:
+ case 0x6a:
+ case 0x6b:
+ case 0x6c:
+ case 0x6d:
+ case 0x6e:
+ case 0x6f:
+ case 0x70:
+ case 0x71:
+ case 0x72:
+ case 0x73:
+ case 0x74:
+ case 0x75:
+ case 0x76:
+ case 0x77:
+ {
+ const auto len = static_cast<size_t>(v[current_idx] - 0x60);
+ const size_t offset = current_idx + 1;
+ idx += len; // skip content bytes
+ check_length(v.size(), len, offset);
+ return std::string(reinterpret_cast<const char*>(v.data()) + offset, len);
+ }
+
+ case 0x78: // UTF-8 string (one-byte uint8_t for n follows)
+ {
+ const auto len = static_cast<size_t>(get_from_vector<uint8_t>(v, current_idx));
+ const size_t offset = current_idx + 2;
+ idx += len + 1; // skip size byte + content bytes
+ check_length(v.size(), len, offset);
+ return std::string(reinterpret_cast<const char*>(v.data()) + offset, len);
+ }
+
+ case 0x79: // UTF-8 string (two-byte uint16_t for n follow)
+ {
+ const auto len = static_cast<size_t>(get_from_vector<uint16_t>(v, current_idx));
+ const size_t offset = current_idx + 3;
+ idx += len + 2; // skip 2 size bytes + content bytes
+ check_length(v.size(), len, offset);
+ return std::string(reinterpret_cast<const char*>(v.data()) + offset, len);
+ }
+
+ case 0x7a: // UTF-8 string (four-byte uint32_t for n follow)
+ {
+ const auto len = static_cast<size_t>(get_from_vector<uint32_t>(v, current_idx));
+ const size_t offset = current_idx + 5;
+ idx += len + 4; // skip 4 size bytes + content bytes
+ check_length(v.size(), len, offset);
+ return std::string(reinterpret_cast<const char*>(v.data()) + offset, len);
+ }
+
+ case 0x7b: // UTF-8 string (eight-byte uint64_t for n follow)
+ {
+ const auto len = static_cast<size_t>(get_from_vector<uint64_t>(v, current_idx));
+ const size_t offset = current_idx + 9;
+ idx += len + 8; // skip 8 size bytes + content bytes
+ check_length(v.size(), len, offset);
+ return std::string(reinterpret_cast<const char*>(v.data()) + offset, len);
+ }
+
+ case 0x7f: // UTF-8 string (indefinite length)
+ {
+ std::string result;
+ while (v.at(idx) != 0xff)
+ {
+ string_t s = from_cbor_internal(v, idx);
+ result += s;
+ }
+ // skip break byte (0xFF)
+ idx += 1;
+ return result;
+ }
+
+ // array (0x00..0x17 data items follow)
+ case 0x80:
+ case 0x81:
+ case 0x82:
+ case 0x83:
+ case 0x84:
+ case 0x85:
+ case 0x86:
+ case 0x87:
+ case 0x88:
+ case 0x89:
+ case 0x8a:
+ case 0x8b:
+ case 0x8c:
+ case 0x8d:
+ case 0x8e:
+ case 0x8f:
+ case 0x90:
+ case 0x91:
+ case 0x92:
+ case 0x93:
+ case 0x94:
+ case 0x95:
+ case 0x96:
+ case 0x97:
+ {
+ basic_json result = value_t::array;
+ const auto len = static_cast<size_t>(v[current_idx] - 0x80);
+ for (size_t i = 0; i < len; ++i)
+ {
+ result.push_back(from_cbor_internal(v, idx));
+ }
+ return result;
+ }
+
+ case 0x98: // array (one-byte uint8_t for n follows)
+ {
+ basic_json result = value_t::array;
+ const auto len = static_cast<size_t>(get_from_vector<uint8_t>(v, current_idx));
+ idx += 1; // skip 1 size byte
+ for (size_t i = 0; i < len; ++i)
+ {
+ result.push_back(from_cbor_internal(v, idx));
+ }
+ return result;
+ }
+
+ case 0x99: // array (two-byte uint16_t for n follow)
+ {
+ basic_json result = value_t::array;
+ const auto len = static_cast<size_t>(get_from_vector<uint16_t>(v, current_idx));
+ idx += 2; // skip 4 size bytes
+ for (size_t i = 0; i < len; ++i)
+ {
+ result.push_back(from_cbor_internal(v, idx));
+ }
+ return result;
+ }
+
+ case 0x9a: // array (four-byte uint32_t for n follow)
+ {
+ basic_json result = value_t::array;
+ const auto len = static_cast<size_t>(get_from_vector<uint32_t>(v, current_idx));
+ idx += 4; // skip 4 size bytes
+ for (size_t i = 0; i < len; ++i)
+ {
+ result.push_back(from_cbor_internal(v, idx));
+ }
+ return result;
+ }
+
+ case 0x9b: // array (eight-byte uint64_t for n follow)
+ {
+ basic_json result = value_t::array;
+ const auto len = static_cast<size_t>(get_from_vector<uint64_t>(v, current_idx));
+ idx += 8; // skip 8 size bytes
+ for (size_t i = 0; i < len; ++i)
+ {
+ result.push_back(from_cbor_internal(v, idx));
+ }
+ return result;
+ }
+
+ case 0x9f: // array (indefinite length)
+ {
+ basic_json result = value_t::array;
+ while (v.at(idx) != 0xff)
+ {
+ result.push_back(from_cbor_internal(v, idx));
+ }
+ // skip break byte (0xFF)
+ idx += 1;
+ return result;
+ }
+
+ // map (0x00..0x17 pairs of data items follow)
+ case 0xa0:
+ case 0xa1:
+ case 0xa2:
+ case 0xa3:
+ case 0xa4:
+ case 0xa5:
+ case 0xa6:
+ case 0xa7:
+ case 0xa8:
+ case 0xa9:
+ case 0xaa:
+ case 0xab:
+ case 0xac:
+ case 0xad:
+ case 0xae:
+ case 0xaf:
+ case 0xb0:
+ case 0xb1:
+ case 0xb2:
+ case 0xb3:
+ case 0xb4:
+ case 0xb5:
+ case 0xb6:
+ case 0xb7:
+ {
+ basic_json result = value_t::object;
+ const auto len = static_cast<size_t>(v[current_idx] - 0xa0);
+ for (size_t i = 0; i < len; ++i)
+ {
+ std::string key = from_cbor_internal(v, idx);
+ result[key] = from_cbor_internal(v, idx);
+ }
+ return result;
+ }
+
+ case 0xb8: // map (one-byte uint8_t for n follows)
+ {
+ basic_json result = value_t::object;
+ const auto len = static_cast<size_t>(get_from_vector<uint8_t>(v, current_idx));
+ idx += 1; // skip 1 size byte
+ for (size_t i = 0; i < len; ++i)
+ {
+ std::string key = from_cbor_internal(v, idx);
+ result[key] = from_cbor_internal(v, idx);
+ }
+ return result;
+ }
+
+ case 0xb9: // map (two-byte uint16_t for n follow)
+ {
+ basic_json result = value_t::object;
+ const auto len = static_cast<size_t>(get_from_vector<uint16_t>(v, current_idx));
+ idx += 2; // skip 2 size bytes
+ for (size_t i = 0; i < len; ++i)
+ {
+ std::string key = from_cbor_internal(v, idx);
+ result[key] = from_cbor_internal(v, idx);
+ }
+ return result;
+ }
+
+ case 0xba: // map (four-byte uint32_t for n follow)
+ {
+ basic_json result = value_t::object;
+ const auto len = static_cast<size_t>(get_from_vector<uint32_t>(v, current_idx));
+ idx += 4; // skip 4 size bytes
+ for (size_t i = 0; i < len; ++i)
+ {
+ std::string key = from_cbor_internal(v, idx);
+ result[key] = from_cbor_internal(v, idx);
+ }
+ return result;
+ }
+
+ case 0xbb: // map (eight-byte uint64_t for n follow)
+ {
+ basic_json result = value_t::object;
+ const auto len = static_cast<size_t>(get_from_vector<uint64_t>(v, current_idx));
+ idx += 8; // skip 8 size bytes
+ for (size_t i = 0; i < len; ++i)
+ {
+ std::string key = from_cbor_internal(v, idx);
+ result[key] = from_cbor_internal(v, idx);
+ }
+ return result;
+ }
+
+ case 0xbf: // map (indefinite length)
+ {
+ basic_json result = value_t::object;
+ while (v.at(idx) != 0xff)
+ {
+ std::string key = from_cbor_internal(v, idx);
+ result[key] = from_cbor_internal(v, idx);
+ }
+ // skip break byte (0xFF)
+ idx += 1;
+ return result;
+ }
+
+ case 0xf4: // false
+ {
+ return false;
+ }
+
+ case 0xf5: // true
+ {
+ return true;
+ }
+
+ case 0xf6: // null
+ {
+ return value_t::null;
+ }
+
+ case 0xf9: // Half-Precision Float (two-byte IEEE 754)
+ {
+ check_length(v.size(), 2, 1);
+ idx += 2; // skip two content bytes
+
+ // code from RFC 7049, Appendix D, Figure 3:
+ // As half-precision floating-point numbers were only added to
+ // IEEE 754 in 2008, today's programming platforms often still
+ // only have limited support for them. It is very easy to
+ // include at least decoding support for them even without such
+ // support. An example of a small decoder for half-precision
+ // floating-point numbers in the C language is shown in Fig. 3.
+ const int half = (v[current_idx + 1] << 8) + v[current_idx + 2];
+ const int exp = (half >> 10) & 0x1f;
+ const int mant = half & 0x3ff;
+ double val;
+ if (exp == 0)
+ {
+ val = std::ldexp(mant, -24);
+ }
+ else if (exp != 31)
+ {
+ val = std::ldexp(mant + 1024, exp - 25);
+ }
+ else
+ {
+ val = mant == 0 ? INFINITY : NAN;
+ }
+ return half & 0x8000 ? -val : val;
+ }
+
+ case 0xfa: // Single-Precision Float (four-byte IEEE 754)
+ {
+ // copy bytes in reverse order into the float variable
+ check_length(v.size(), sizeof(float), 1);
+ float res;
+ for (size_t byte = 0; byte < sizeof(float); ++byte)
+ {
+ reinterpret_cast<uint8_t*>(&res)[sizeof(float) - byte - 1] = v[current_idx + 1 + byte];
+ }
+ idx += sizeof(float); // skip content bytes
+ return res;
+ }
+
+ case 0xfb: // Double-Precision Float (eight-byte IEEE 754)
+ {
+ check_length(v.size(), sizeof(double), 1);
+ // copy bytes in reverse order into the double variable
+ double res;
+ for (size_t byte = 0; byte < sizeof(double); ++byte)
+ {
+ reinterpret_cast<uint8_t*>(&res)[sizeof(double) - byte - 1] = v[current_idx + 1 + byte];
+ }
+ idx += sizeof(double); // skip content bytes
+ return res;
+ }
+
+ default: // anything else (0xFF is handled inside the other types)
+ {
+ throw std::invalid_argument("error parsing a CBOR @ " + std::to_string(current_idx) + ": " + std::to_string(static_cast<int>(v[current_idx])));
+ }
+ }
+ }
+
+ public:
+ /*!
+ @brief create a MessagePack serialization of a given JSON value
+
+ Serializes a given JSON value @a j to a byte vector using the MessagePack
+ serialization format. MessagePack is a binary serialization format which
+ aims to be more compact than JSON itself, yet more efficient to parse.
+
+ @param[in] j JSON value to serialize
+ @return MessagePack serialization as byte vector
+
+ @complexity Linear in the size of the JSON value @a j.
+
+ @liveexample{The example shows the serialization of a JSON value to a byte
+ vector in MessagePack format.,to_msgpack}
+
+ @sa http://msgpack.org
+ @sa @ref from_msgpack(const std::vector<uint8_t>&) for the analogous
+ deserialization
+ @sa @ref to_cbor(const basic_json& for the related CBOR format
+ */
+ static std::vector<uint8_t> to_msgpack(const basic_json& j)
+ {
+ std::vector<uint8_t> result;
+ to_msgpack_internal(j, result);
+ return result;
+ }
+
+ /*!
+ @brief create a JSON value from a byte vector in MessagePack format
+
+ Deserializes a given byte vector @a v to a JSON value using the MessagePack
+ serialization format.
+
+ @param[in] v a byte vector in MessagePack format
+ @return deserialized JSON value
+
+ @throw std::invalid_argument if unsupported features from MessagePack were
+ used in the given vector @a v or if the input is not valid MessagePack
+ @throw std::out_of_range if the given vector ends prematurely
+
+ @complexity Linear in the size of the byte vector @a v.
+
+ @liveexample{The example shows the deserialization of a byte vector in
+ MessagePack format to a JSON value.,from_msgpack}
+
+ @sa http://msgpack.org
+ @sa @ref to_msgpack(const basic_json&) for the analogous serialization
+ @sa @ref from_cbor(const std::vector<uint8_t>&) for the related CBOR format
+ */
+ static basic_json from_msgpack(const std::vector<uint8_t>& v)
+ {
+ size_t i = 0;
+ return from_msgpack_internal(v, i);
+ }
+
+ /*!
+ @brief create a MessagePack serialization of a given JSON value
+
+ Serializes a given JSON value @a j to a byte vector using the CBOR (Concise
+ Binary Object Representation) serialization format. CBOR is a binary
+ serialization format which aims to be more compact than JSON itself, yet
+ more efficient to parse.
+
+ @param[in] j JSON value to serialize
+ @return MessagePack serialization as byte vector
+
+ @complexity Linear in the size of the JSON value @a j.
+
+ @liveexample{The example shows the serialization of a JSON value to a byte
+ vector in CBOR format.,to_cbor}
+
+ @sa http://cbor.io
+ @sa @ref from_cbor(const std::vector<uint8_t>&) for the analogous
+ deserialization
+ @sa @ref to_msgpack(const basic_json& for the related MessagePack format
+ */
+ static std::vector<uint8_t> to_cbor(const basic_json& j)
+ {
+ std::vector<uint8_t> result;
+ to_cbor_internal(j, result);
+ return result;
+ }
+
+ /*!
+ @brief create a JSON value from a byte vector in CBOR format
+
+ Deserializes a given byte vector @a v to a JSON value using the CBOR
+ (Concise Binary Object Representation) serialization format.
+
+ @param[in] v a byte vector in CBOR format
+ @return deserialized JSON value
+
+ @throw std::invalid_argument if unsupported features from CBOR were used in
+ the given vector @a v or if the input is not valid MessagePack
+ @throw std::out_of_range if the given vector ends prematurely
+
+ @complexity Linear in the size of the byte vector @a v.
+
+ @liveexample{The example shows the deserialization of a byte vector in CBOR
+ format to a JSON value.,from_cbor}
+
+ @sa http://cbor.io
+ @sa @ref to_cbor(const basic_json&) for the analogous serialization
+ @sa @ref from_msgpack(const std::vector<uint8_t>&) for the related
+ MessagePack format
+ */
+ static basic_json from_cbor(const std::vector<uint8_t>& v)
+ {
+ size_t i = 0;
+ return from_cbor_internal(v, i);
+ }
+
+ /// @}
private:
///////////////////////////
@@ -6044,7 +7739,7 @@ class basic_json
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
+ @return basically a string representation of a the @a m_type member
@complexity Constant.
@@ -6584,43 +8279,53 @@ class basic_json
public:
/*!
- @brief a const random access iterator for the @ref basic_json class
+ @brief a template for a random access iterator for the @ref basic_json class
- This class implements a const iterator for the @ref basic_json class. From
- this class, the @ref iterator class is derived.
+ This class implements a both iterators (iterator and const_iterator) for the
+ @ref basic_json class.
@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.
+ 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
element in constant time.
- @since version 1.0.0
+ @since version 1.0.0, simplified in version 2.0.9
*/
- class const_iterator : public std::iterator<std::random_access_iterator_tag, const basic_json>
+ template<typename U>
+ class iter_impl : public std::iterator<std::random_access_iterator_tag, U>
{
/// allow basic_json to access private members
friend class basic_json;
+ // make sure U is basic_json or const basic_json
+ static_assert(std::is_same<U, basic_json>::value
+ or std::is_same<U, const basic_json>::value,
+ "iter_impl only accepts (const) basic_json");
+
public:
/// the type of the values when the iterator is dereferenced
using value_type = typename basic_json::value_type;
/// a type to represent differences between iterators
using difference_type = typename basic_json::difference_type;
/// defines a pointer to the type iterated over (value_type)
- using pointer = typename basic_json::const_pointer;
+ using pointer = typename std::conditional<std::is_const<U>::value,
+ typename basic_json::const_pointer,
+ typename basic_json::pointer>::type;
/// defines a reference to the type iterated over (value_type)
- using reference = typename basic_json::const_reference;
+ using reference = typename std::conditional<std::is_const<U>::value,
+ typename basic_json::const_reference,
+ typename basic_json::reference>::type;
/// the category of the iterator
using iterator_category = std::bidirectional_iterator_tag;
/// default constructor
- const_iterator() = default;
+ iter_impl() = default;
/*!
@brief constructor for a given JSON instance
@@ -6628,7 +8333,7 @@ class basic_json
@pre object != nullptr
@post The iterator is initialized; i.e. `m_object != nullptr`.
*/
- explicit const_iterator(pointer object) noexcept
+ explicit iter_impl(pointer object) noexcept
: m_object(object)
{
assert(m_object != nullptr);
@@ -6655,37 +8360,25 @@ class basic_json
}
}
- /*!
- @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.
+ /*
+ Use operator `const_iterator` instead of `const_iterator(const iterator&
+ other) noexcept` to avoid two class definitions for @ref iterator and
+ @ref const_iterator.
+
+ This function is only called if this class is an @ref iterator. If this
+ class is a @ref const_iterator this function is not called.
*/
- explicit const_iterator(const iterator& other) noexcept
- : m_object(other.m_object)
+ operator const_iterator() const
{
- if (m_object != nullptr)
- {
- switch (m_object->m_type)
- {
- case basic_json::value_t::object:
- {
- m_it.object_iterator = other.m_it.object_iterator;
- break;
- }
+ const_iterator ret;
- 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;
- }
- }
+ if (m_object)
+ {
+ ret.m_object = m_object;
+ ret.m_it = m_it;
}
+
+ return ret;
}
/*!
@@ -6693,7 +8386,7 @@ class basic_json
@param[in] other iterator to copy from
@note It is not checked whether @a other is initialized.
*/
- const_iterator(const const_iterator& other) noexcept
+ iter_impl(const iter_impl& other) noexcept
: m_object(other.m_object), m_it(other.m_it)
{}
@@ -6702,7 +8395,7 @@ class basic_json
@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(
+ iter_impl& operator=(iter_impl other) noexcept(
std::is_nothrow_move_constructible<pointer>::value and
std::is_nothrow_move_assignable<pointer>::value and
std::is_nothrow_move_constructible<internal_iterator>::value and
@@ -6864,7 +8557,7 @@ class basic_json
@brief post-increment (it++)
@pre The iterator is initialized; i.e. `m_object != nullptr`.
*/
- const_iterator operator++(int)
+ iter_impl operator++(int)
{
auto result = *this;
++(*this);
@@ -6875,7 +8568,7 @@ class basic_json
@brief pre-increment (++it)
@pre The iterator is initialized; i.e. `m_object != nullptr`.
*/
- const_iterator& operator++()
+ iter_impl& operator++()
{
assert(m_object != nullptr);
@@ -6907,7 +8600,7 @@ class basic_json
@brief post-decrement (it--)
@pre The iterator is initialized; i.e. `m_object != nullptr`.
*/
- const_iterator operator--(int)
+ iter_impl operator--(int)
{
auto result = *this;
--(*this);
@@ -6918,7 +8611,7 @@ class basic_json
@brief pre-decrement (--it)
@pre The iterator is initialized; i.e. `m_object != nullptr`.
*/
- const_iterator& operator--()
+ iter_impl& operator--()
{
assert(m_object != nullptr);
@@ -6950,7 +8643,7 @@ class basic_json
@brief comparison: equal
@pre The iterator is initialized; i.e. `m_object != nullptr`.
*/
- bool operator==(const const_iterator& other) const
+ bool operator==(const iter_impl& other) const
{
// if objects are not the same, the comparison is undefined
if (m_object != other.m_object)
@@ -6983,7 +8676,7 @@ class basic_json
@brief comparison: not equal
@pre The iterator is initialized; i.e. `m_object != nullptr`.
*/
- bool operator!=(const const_iterator& other) const
+ bool operator!=(const iter_impl& other) const
{
return not operator==(other);
}
@@ -6992,7 +8685,7 @@ class basic_json
@brief comparison: smaller
@pre The iterator is initialized; i.e. `m_object != nullptr`.
*/
- bool operator<(const const_iterator& other) const
+ bool operator<(const iter_impl& other) const
{
// if objects are not the same, the comparison is undefined
if (m_object != other.m_object)
@@ -7025,7 +8718,7 @@ class basic_json
@brief comparison: less than or equal
@pre The iterator is initialized; i.e. `m_object != nullptr`.
*/
- bool operator<=(const const_iterator& other) const
+ bool operator<=(const iter_impl& other) const
{
return not other.operator < (*this);
}
@@ -7034,7 +8727,7 @@ class basic_json
@brief comparison: greater than
@pre The iterator is initialized; i.e. `m_object != nullptr`.
*/
- bool operator>(const const_iterator& other) const
+ bool operator>(const iter_impl& other) const
{
return not operator<=(other);
}
@@ -7043,7 +8736,7 @@ class basic_json
@brief comparison: greater than or equal
@pre The iterator is initialized; i.e. `m_object != nullptr`.
*/
- bool operator>=(const const_iterator& other) const
+ bool operator>=(const iter_impl& other) const
{
return not operator<(other);
}
@@ -7052,7 +8745,7 @@ class basic_json
@brief add to iterator
@pre The iterator is initialized; i.e. `m_object != nullptr`.
*/
- const_iterator& operator+=(difference_type i)
+ iter_impl& operator+=(difference_type i)
{
assert(m_object != nullptr);
@@ -7083,7 +8776,7 @@ class basic_json
@brief subtract from iterator
@pre The iterator is initialized; i.e. `m_object != nullptr`.
*/
- const_iterator& operator-=(difference_type i)
+ iter_impl& operator-=(difference_type i)
{
return operator+=(-i);
}
@@ -7092,7 +8785,7 @@ class basic_json
@brief add to iterator
@pre The iterator is initialized; i.e. `m_object != nullptr`.
*/
- const_iterator operator+(difference_type i)
+ iter_impl operator+(difference_type i)
{
auto result = *this;
result += i;
@@ -7103,7 +8796,7 @@ class basic_json
@brief subtract from iterator
@pre The iterator is initialized; i.e. `m_object != nullptr`.
*/
- const_iterator operator-(difference_type i)
+ iter_impl operator-(difference_type i)
{
auto result = *this;
result -= i;
@@ -7114,7 +8807,7 @@ class basic_json
@brief return difference
@pre The iterator is initialized; i.e. `m_object != nullptr`.
*/
- difference_type operator-(const const_iterator& other) const
+ difference_type operator-(const iter_impl& other) const
{
assert(m_object != nullptr);
@@ -7211,141 +8904,6 @@ class basic_json
};
/*!
- @brief a mutable random access iterator for the @ref basic_json class
-
- @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
- element in constant time.
- - [OutputIterator](http://en.cppreference.com/w/cpp/concept/OutputIterator):
- It is possible to write to the pointed-to element.
-
- @since version 1.0.0
- */
- class iterator : public const_iterator
- {
- public:
- using base_iterator = const_iterator;
- using pointer = typename basic_json::pointer;
- using reference = typename basic_json::reference;
-
- /// default constructor
- iterator() = default;
-
- /// constructor for a given JSON instance
- explicit iterator(pointer object) noexcept
- : base_iterator(object)
- {}
-
- /// copy constructor
- iterator(const iterator& other) noexcept
- : base_iterator(other)
- {}
-
- /// copy assignment
- iterator& operator=(iterator other) noexcept(
- std::is_nothrow_move_constructible<pointer>::value and
- std::is_nothrow_move_assignable<pointer>::value and
- std::is_nothrow_move_constructible<internal_iterator>::value and
- std::is_nothrow_move_assignable<internal_iterator>::value
- )
- {
- base_iterator::operator=(other);
- return *this;
- }
-
- /// return a reference to the value pointed to by the iterator
- reference operator*() const
- {
- return const_cast<reference>(base_iterator::operator*());
- }
-
- /// dereference the iterator
- pointer operator->() const
- {
- return const_cast<pointer>(base_iterator::operator->());
- }
-
- /// post-increment (it++)
- iterator operator++(int)
- {
- iterator result = *this;
- base_iterator::operator++();
- return result;
- }
-
- /// pre-increment (++it)
- iterator& operator++()
- {
- base_iterator::operator++();
- return *this;
- }
-
- /// post-decrement (it--)
- iterator operator--(int)
- {
- iterator result = *this;
- base_iterator::operator--();
- return result;
- }
-
- /// pre-decrement (--it)
- iterator& operator--()
- {
- base_iterator::operator--();
- return *this;
- }
-
- /// add to iterator
- iterator& operator+=(difference_type i)
- {
- base_iterator::operator+=(i);
- return *this;
- }
-
- /// subtract from iterator
- iterator& operator-=(difference_type i)
- {
- base_iterator::operator-=(i);
- return *this;
- }
-
- /// add to iterator
- iterator operator+(difference_type i)
- {
- auto result = *this;
- result += i;
- return result;
- }
-
- /// subtract from iterator
- iterator operator-(difference_type i)
- {
- auto result = *this;
- result -= i;
- return result;
- }
-
- /// return difference
- difference_type operator-(const iterator& other) const
- {
- return base_iterator::operator-(other);
- }
-
- /// access to successor
- reference operator[](difference_type n) const
- {
- return const_cast<reference>(base_iterator::operator[](n));
- }
-
- /// return the value of an iterator
- reference value() const
- {
- return const_cast<reference>(base_iterator::value());
- }
- };
-
- /*!
@brief a template for a reverse iterator class
@tparam Base the base iterator type to reverse. Valid types are @ref
@@ -7495,32 +9053,39 @@ class basic_json
/// the char type to use in the lexer
using lexer_char_t = unsigned char;
- /// constructor with a given buffer
- explicit lexer(const string_t& s) noexcept
- : m_stream(nullptr), m_buffer(s)
+ /// a lexer from a buffer with given length
+ lexer(const lexer_char_t* buff, const size_t len) noexcept
+ : m_content(buff)
{
- 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();
+ m_limit = m_content + len;
}
- /// constructor with a given stream
- explicit lexer(std::istream* s) noexcept
- : m_stream(s), m_buffer()
+ /// a lexer from an input stream
+ explicit lexer(std::istream& s)
+ : m_stream(&s), m_line_buffer()
{
- assert(m_stream != nullptr);
- 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;
- m_limit = m_content + m_buffer.size();
- }
+ // immediately abort if stream is erroneous
+ if (s.fail())
+ {
+ throw std::invalid_argument("stream error");
+ }
- /// default constructor
- lexer() = default;
+ // fill buffer
+ fill_line_buffer();
+
+ // skip UTF-8 byte-order mark
+ if (m_line_buffer.size() >= 3 and m_line_buffer.substr(0, 3) == "\xEF\xBB\xBF")
+ {
+ m_line_buffer[0] = ' ';
+ m_line_buffer[1] = ' ';
+ m_line_buffer[2] = ' ';
+ }
+ }
- // switch off unwanted functions
+ // switch off unwanted functions (due to pointer members)
+ lexer() = delete;
lexer(const lexer&) = delete;
lexer operator=(const lexer&) = delete;
@@ -7673,7 +9238,7 @@ class basic_json
infinite sequence of whitespace or byte-order-marks. This contradicts
the assumption of finite input, q.e.d.
*/
- token_type scan() noexcept
+ token_type scan()
{
while (true)
{
@@ -7706,33 +9271,33 @@ class basic_json
128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128,
128, 128, 128, 128, 128, 128, 128, 128,
- 128, 128, 128, 128, 128, 128, 128, 128,
- 128, 128, 128, 128, 128, 128, 128, 128,
- 128, 128, 128, 128, 128, 128, 128, 128,
- 128, 128, 128, 128, 128, 128, 128, 128,
- 128, 128, 128, 128, 128, 128, 128, 128,
- 128, 128, 128, 128, 128, 128, 128, 128,
- 128, 128, 128, 128, 128, 128, 128, 128,
- 128, 128, 128, 128, 128, 128, 128, 128,
- 128, 128, 128, 128, 128, 128, 128, 128,
- 128, 128, 128, 128, 128, 128, 128, 128,
- 128, 128, 128, 128, 128, 128, 128, 128,
- 128, 128, 128, 128, 128, 128, 128, 128,
- 128, 128, 128, 128, 128, 128, 128, 128,
- 128, 128, 128, 128, 128, 128, 128, 128,
- 128, 128, 128, 128, 128, 128, 128, 128,
- 128, 128, 128, 128, 128, 128, 128, 128,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
};
if ((m_limit - m_cursor) < 5)
{
- yyfill(); // LCOV_EXCL_LINE;
+ fill_line_buffer(5); // LCOV_EXCL_LINE
}
yych = *m_cursor;
if (yybm[0 + yych] & 32)
{
goto basic_json_parser_6;
}
- if (yych <= '\\')
+ if (yych <= '[')
{
if (yych <= '-')
{
@@ -7781,62 +9346,58 @@ class basic_json
{
goto basic_json_parser_17;
}
- if (yych == '[')
+ if (yych <= 'Z')
{
- goto basic_json_parser_19;
+ goto basic_json_parser_4;
}
- goto basic_json_parser_4;
+ goto basic_json_parser_19;
}
}
}
else
{
- if (yych <= 't')
+ if (yych <= 'n')
{
- if (yych <= 'f')
+ if (yych <= 'e')
{
- if (yych <= ']')
+ if (yych == ']')
{
goto basic_json_parser_21;
}
- if (yych <= 'e')
- {
- goto basic_json_parser_4;
- }
- goto basic_json_parser_23;
+ goto basic_json_parser_4;
}
else
{
- if (yych == 'n')
+ if (yych <= 'f')
{
- goto basic_json_parser_24;
+ goto basic_json_parser_23;
}
- if (yych <= 's')
+ if (yych <= 'm')
{
goto basic_json_parser_4;
}
- goto basic_json_parser_25;
+ goto basic_json_parser_24;
}
}
else
{
- if (yych <= '|')
+ if (yych <= 'z')
{
- if (yych == '{')
+ if (yych == 't')
{
- goto basic_json_parser_26;
+ goto basic_json_parser_25;
}
goto basic_json_parser_4;
}
else
{
- if (yych <= '}')
+ if (yych <= '{')
{
- goto basic_json_parser_28;
+ goto basic_json_parser_26;
}
- if (yych == 0xEF)
+ if (yych == '}')
{
- goto basic_json_parser_30;
+ goto basic_json_parser_28;
}
goto basic_json_parser_4;
}
@@ -7859,7 +9420,7 @@ basic_json_parser_6:
++m_cursor;
if (m_limit <= m_cursor)
{
- yyfill(); // LCOV_EXCL_LINE;
+ fill_line_buffer(1); // LCOV_EXCL_LINE
}
yych = *m_cursor;
if (yybm[0 + yych] & 32)
@@ -7876,7 +9437,19 @@ basic_json_parser_9:
{
goto basic_json_parser_5;
}
- goto basic_json_parser_32;
+ if (yych <= 0x7F)
+ {
+ goto basic_json_parser_31;
+ }
+ if (yych <= 0xC1)
+ {
+ goto basic_json_parser_5;
+ }
+ if (yych <= 0xF4)
+ {
+ goto basic_json_parser_31;
+ }
+ goto basic_json_parser_5;
basic_json_parser_10:
++m_cursor;
{
@@ -7905,18 +9478,18 @@ basic_json_parser_13:
{
if (yych == '.')
{
- goto basic_json_parser_37;
+ goto basic_json_parser_43;
}
}
else
{
if (yych <= 'E')
{
- goto basic_json_parser_38;
+ goto basic_json_parser_44;
}
if (yych == 'e')
{
- goto basic_json_parser_38;
+ goto basic_json_parser_44;
}
}
basic_json_parser_14:
@@ -7929,7 +9502,7 @@ basic_json_parser_15:
m_marker = ++m_cursor;
if ((m_limit - m_cursor) < 3)
{
- yyfill(); // LCOV_EXCL_LINE;
+ fill_line_buffer(3); // LCOV_EXCL_LINE
}
yych = *m_cursor;
if (yybm[0 + yych] & 64)
@@ -7940,7 +9513,7 @@ basic_json_parser_15:
{
if (yych == '.')
{
- goto basic_json_parser_37;
+ goto basic_json_parser_43;
}
goto basic_json_parser_14;
}
@@ -7948,11 +9521,11 @@ basic_json_parser_15:
{
if (yych <= 'E')
{
- goto basic_json_parser_38;
+ goto basic_json_parser_44;
}
if (yych == 'e')
{
- goto basic_json_parser_38;
+ goto basic_json_parser_44;
}
goto basic_json_parser_14;
}
@@ -7979,7 +9552,7 @@ basic_json_parser_23:
yych = *(m_marker = ++m_cursor);
if (yych == 'a')
{
- goto basic_json_parser_39;
+ goto basic_json_parser_45;
}
goto basic_json_parser_5;
basic_json_parser_24:
@@ -7987,7 +9560,7 @@ basic_json_parser_24:
yych = *(m_marker = ++m_cursor);
if (yych == 'u')
{
- goto basic_json_parser_40;
+ goto basic_json_parser_46;
}
goto basic_json_parser_5;
basic_json_parser_25:
@@ -7995,7 +9568,7 @@ basic_json_parser_25:
yych = *(m_marker = ++m_cursor);
if (yych == 'r')
{
- goto basic_json_parser_41;
+ goto basic_json_parser_47;
}
goto basic_json_parser_5;
basic_json_parser_26:
@@ -8011,35 +9584,71 @@ basic_json_parser_28:
break;
}
basic_json_parser_30:
- yyaccept = 0;
- yych = *(m_marker = ++m_cursor);
- if (yych == 0xBB)
- {
- goto basic_json_parser_42;
- }
- goto basic_json_parser_5;
-basic_json_parser_31:
++m_cursor;
if (m_limit <= m_cursor)
{
- yyfill(); // LCOV_EXCL_LINE;
+ fill_line_buffer(1); // LCOV_EXCL_LINE
}
yych = *m_cursor;
-basic_json_parser_32:
+basic_json_parser_31:
if (yybm[0 + yych] & 128)
{
- goto basic_json_parser_31;
+ goto basic_json_parser_30;
}
- if (yych <= 0x1F)
+ if (yych <= 0xE0)
{
- goto basic_json_parser_33;
+ if (yych <= '\\')
+ {
+ if (yych <= 0x1F)
+ {
+ goto basic_json_parser_32;
+ }
+ if (yych <= '"')
+ {
+ goto basic_json_parser_33;
+ }
+ goto basic_json_parser_35;
+ }
+ else
+ {
+ if (yych <= 0xC1)
+ {
+ goto basic_json_parser_32;
+ }
+ if (yych <= 0xDF)
+ {
+ goto basic_json_parser_36;
+ }
+ goto basic_json_parser_37;
+ }
}
- if (yych <= '"')
+ else
{
- goto basic_json_parser_34;
+ if (yych <= 0xEF)
+ {
+ if (yych == 0xED)
+ {
+ goto basic_json_parser_39;
+ }
+ goto basic_json_parser_38;
+ }
+ else
+ {
+ if (yych <= 0xF0)
+ {
+ goto basic_json_parser_40;
+ }
+ if (yych <= 0xF3)
+ {
+ goto basic_json_parser_41;
+ }
+ if (yych <= 0xF4)
+ {
+ goto basic_json_parser_42;
+ }
+ }
}
- goto basic_json_parser_36;
-basic_json_parser_33:
+basic_json_parser_32:
m_cursor = m_marker;
if (yyaccept == 0)
{
@@ -8049,17 +9658,17 @@ basic_json_parser_33:
{
goto basic_json_parser_14;
}
-basic_json_parser_34:
+basic_json_parser_33:
++m_cursor;
{
last_token_type = token_type::value_string;
break;
}
-basic_json_parser_36:
+basic_json_parser_35:
++m_cursor;
if (m_limit <= m_cursor)
{
- yyfill(); // LCOV_EXCL_LINE;
+ fill_line_buffer(1); // LCOV_EXCL_LINE
}
yych = *m_cursor;
if (yych <= 'e')
@@ -8068,13 +9677,13 @@ basic_json_parser_36:
{
if (yych == '"')
{
- goto basic_json_parser_31;
+ goto basic_json_parser_30;
}
if (yych <= '.')
{
- goto basic_json_parser_33;
+ goto basic_json_parser_32;
}
- goto basic_json_parser_31;
+ goto basic_json_parser_30;
}
else
{
@@ -8082,17 +9691,17 @@ basic_json_parser_36:
{
if (yych <= '[')
{
- goto basic_json_parser_33;
+ goto basic_json_parser_32;
}
- goto basic_json_parser_31;
+ goto basic_json_parser_30;
}
else
{
if (yych == 'b')
{
- goto basic_json_parser_31;
+ goto basic_json_parser_30;
}
- goto basic_json_parser_33;
+ goto basic_json_parser_32;
}
}
}
@@ -8102,13 +9711,13 @@ basic_json_parser_36:
{
if (yych <= 'f')
{
- goto basic_json_parser_31;
+ goto basic_json_parser_30;
}
if (yych == 'n')
{
- goto basic_json_parser_31;
+ goto basic_json_parser_30;
}
- goto basic_json_parser_33;
+ goto basic_json_parser_32;
}
else
{
@@ -8116,130 +9725,235 @@ basic_json_parser_36:
{
if (yych <= 'r')
{
- goto basic_json_parser_31;
+ goto basic_json_parser_30;
}
- goto basic_json_parser_33;
+ goto basic_json_parser_32;
}
else
{
if (yych <= 't')
{
- goto basic_json_parser_31;
+ goto basic_json_parser_30;
}
if (yych <= 'u')
{
- goto basic_json_parser_43;
+ goto basic_json_parser_48;
}
- goto basic_json_parser_33;
+ goto basic_json_parser_32;
}
}
}
+basic_json_parser_36:
+ ++m_cursor;
+ if (m_limit <= m_cursor)
+ {
+ fill_line_buffer(1); // LCOV_EXCL_LINE
+ }
+ yych = *m_cursor;
+ if (yych <= 0x7F)
+ {
+ goto basic_json_parser_32;
+ }
+ if (yych <= 0xBF)
+ {
+ goto basic_json_parser_30;
+ }
+ goto basic_json_parser_32;
basic_json_parser_37:
+ ++m_cursor;
+ if (m_limit <= m_cursor)
+ {
+ fill_line_buffer(1); // LCOV_EXCL_LINE
+ }
+ yych = *m_cursor;
+ if (yych <= 0x9F)
+ {
+ goto basic_json_parser_32;
+ }
+ if (yych <= 0xBF)
+ {
+ goto basic_json_parser_36;
+ }
+ goto basic_json_parser_32;
+basic_json_parser_38:
+ ++m_cursor;
+ if (m_limit <= m_cursor)
+ {
+ fill_line_buffer(1); // LCOV_EXCL_LINE
+ }
+ yych = *m_cursor;
+ if (yych <= 0x7F)
+ {
+ goto basic_json_parser_32;
+ }
+ if (yych <= 0xBF)
+ {
+ goto basic_json_parser_36;
+ }
+ goto basic_json_parser_32;
+basic_json_parser_39:
+ ++m_cursor;
+ if (m_limit <= m_cursor)
+ {
+ fill_line_buffer(1); // LCOV_EXCL_LINE
+ }
+ yych = *m_cursor;
+ if (yych <= 0x7F)
+ {
+ goto basic_json_parser_32;
+ }
+ if (yych <= 0x9F)
+ {
+ goto basic_json_parser_36;
+ }
+ goto basic_json_parser_32;
+basic_json_parser_40:
+ ++m_cursor;
+ if (m_limit <= m_cursor)
+ {
+ fill_line_buffer(1); // LCOV_EXCL_LINE
+ }
+ yych = *m_cursor;
+ if (yych <= 0x8F)
+ {
+ goto basic_json_parser_32;
+ }
+ if (yych <= 0xBF)
+ {
+ goto basic_json_parser_38;
+ }
+ goto basic_json_parser_32;
+basic_json_parser_41:
+ ++m_cursor;
+ if (m_limit <= m_cursor)
+ {
+ fill_line_buffer(1); // LCOV_EXCL_LINE
+ }
+ yych = *m_cursor;
+ if (yych <= 0x7F)
+ {
+ goto basic_json_parser_32;
+ }
+ if (yych <= 0xBF)
+ {
+ goto basic_json_parser_38;
+ }
+ goto basic_json_parser_32;
+basic_json_parser_42:
+ ++m_cursor;
+ if (m_limit <= m_cursor)
+ {
+ fill_line_buffer(1); // LCOV_EXCL_LINE
+ }
+ yych = *m_cursor;
+ if (yych <= 0x7F)
+ {
+ goto basic_json_parser_32;
+ }
+ if (yych <= 0x8F)
+ {
+ goto basic_json_parser_38;
+ }
+ goto basic_json_parser_32;
+basic_json_parser_43:
yych = *++m_cursor;
if (yych <= '/')
{
- goto basic_json_parser_33;
+ goto basic_json_parser_32;
}
if (yych <= '9')
{
- goto basic_json_parser_44;
+ goto basic_json_parser_49;
}
- goto basic_json_parser_33;
-basic_json_parser_38:
+ goto basic_json_parser_32;
+basic_json_parser_44:
yych = *++m_cursor;
if (yych <= ',')
{
if (yych == '+')
{
- goto basic_json_parser_46;
+ goto basic_json_parser_51;
}
- goto basic_json_parser_33;
+ goto basic_json_parser_32;
}
else
{
if (yych <= '-')
{
- goto basic_json_parser_46;
+ goto basic_json_parser_51;
}
if (yych <= '/')
{
- goto basic_json_parser_33;
+ goto basic_json_parser_32;
}
if (yych <= '9')
{
- goto basic_json_parser_47;
+ goto basic_json_parser_52;
}
- goto basic_json_parser_33;
+ goto basic_json_parser_32;
}
-basic_json_parser_39:
+basic_json_parser_45:
yych = *++m_cursor;
if (yych == 'l')
{
- goto basic_json_parser_49;
+ goto basic_json_parser_54;
}
- goto basic_json_parser_33;
-basic_json_parser_40:
+ goto basic_json_parser_32;
+basic_json_parser_46:
yych = *++m_cursor;
if (yych == 'l')
{
- goto basic_json_parser_50;
+ goto basic_json_parser_55;
}
- goto basic_json_parser_33;
-basic_json_parser_41:
+ goto basic_json_parser_32;
+basic_json_parser_47:
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_56;
}
- goto basic_json_parser_33;
-basic_json_parser_43:
+ goto basic_json_parser_32;
+basic_json_parser_48:
++m_cursor;
if (m_limit <= m_cursor)
{
- yyfill(); // LCOV_EXCL_LINE;
+ fill_line_buffer(1); // LCOV_EXCL_LINE
}
yych = *m_cursor;
if (yych <= '@')
{
if (yych <= '/')
{
- goto basic_json_parser_33;
+ goto basic_json_parser_32;
}
if (yych <= '9')
{
- goto basic_json_parser_54;
+ goto basic_json_parser_57;
}
- goto basic_json_parser_33;
+ goto basic_json_parser_32;
}
else
{
if (yych <= 'F')
{
- goto basic_json_parser_54;
+ goto basic_json_parser_57;
}
if (yych <= '`')
{
- goto basic_json_parser_33;
+ goto basic_json_parser_32;
}
if (yych <= 'f')
{
- goto basic_json_parser_54;
+ goto basic_json_parser_57;
}
- goto basic_json_parser_33;
+ goto basic_json_parser_32;
}
-basic_json_parser_44:
+basic_json_parser_49:
yyaccept = 1;
m_marker = ++m_cursor;
if ((m_limit - m_cursor) < 3)
{
- yyfill(); // LCOV_EXCL_LINE;
+ fill_line_buffer(3); // LCOV_EXCL_LINE
}
yych = *m_cursor;
if (yych <= 'D')
@@ -8250,7 +9964,7 @@ basic_json_parser_44:
}
if (yych <= '9')
{
- goto basic_json_parser_44;
+ goto basic_json_parser_49;
}
goto basic_json_parser_14;
}
@@ -8258,29 +9972,29 @@ basic_json_parser_44:
{
if (yych <= 'E')
{
- goto basic_json_parser_38;
+ goto basic_json_parser_44;
}
if (yych == 'e')
{
- goto basic_json_parser_38;
+ goto basic_json_parser_44;
}
goto basic_json_parser_14;
}
-basic_json_parser_46:
+basic_json_parser_51:
yych = *++m_cursor;
if (yych <= '/')
{
- goto basic_json_parser_33;
+ goto basic_json_parser_32;
}
if (yych >= ':')
{
- goto basic_json_parser_33;
+ goto basic_json_parser_32;
}
-basic_json_parser_47:
+basic_json_parser_52:
++m_cursor;
if (m_limit <= m_cursor)
{
- yyfill(); // LCOV_EXCL_LINE;
+ fill_line_buffer(1); // LCOV_EXCL_LINE
}
yych = *m_cursor;
if (yych <= '/')
@@ -8289,164 +10003,159 @@ basic_json_parser_47:
}
if (yych <= '9')
{
- goto basic_json_parser_47;
+ goto basic_json_parser_52;
}
goto basic_json_parser_14;
-basic_json_parser_49:
+basic_json_parser_54:
yych = *++m_cursor;
if (yych == 's')
{
- goto basic_json_parser_55;
+ goto basic_json_parser_58;
}
- goto basic_json_parser_33;
-basic_json_parser_50:
+ goto basic_json_parser_32;
+basic_json_parser_55:
yych = *++m_cursor;
if (yych == 'l')
{
- goto basic_json_parser_56;
+ goto basic_json_parser_59;
}
- goto basic_json_parser_33;
-basic_json_parser_51:
+ goto basic_json_parser_32;
+basic_json_parser_56:
yych = *++m_cursor;
if (yych == 'e')
{
- goto basic_json_parser_58;
- }
- goto basic_json_parser_33;
-basic_json_parser_52:
- ++m_cursor;
- {
- continue;
+ goto basic_json_parser_61;
}
-basic_json_parser_54:
+ goto basic_json_parser_32;
+basic_json_parser_57:
++m_cursor;
if (m_limit <= m_cursor)
{
- yyfill(); // LCOV_EXCL_LINE;
+ fill_line_buffer(1); // LCOV_EXCL_LINE
}
yych = *m_cursor;
if (yych <= '@')
{
if (yych <= '/')
{
- goto basic_json_parser_33;
+ goto basic_json_parser_32;
}
if (yych <= '9')
{
- goto basic_json_parser_60;
+ goto basic_json_parser_63;
}
- goto basic_json_parser_33;
+ goto basic_json_parser_32;
}
else
{
if (yych <= 'F')
{
- goto basic_json_parser_60;
+ goto basic_json_parser_63;
}
if (yych <= '`')
{
- goto basic_json_parser_33;
+ goto basic_json_parser_32;
}
if (yych <= 'f')
{
- goto basic_json_parser_60;
+ goto basic_json_parser_63;
}
- goto basic_json_parser_33;
+ goto basic_json_parser_32;
}
-basic_json_parser_55:
+basic_json_parser_58:
yych = *++m_cursor;
if (yych == 'e')
{
- goto basic_json_parser_61;
+ goto basic_json_parser_64;
}
- goto basic_json_parser_33;
-basic_json_parser_56:
+ goto basic_json_parser_32;
+basic_json_parser_59:
++m_cursor;
{
last_token_type = token_type::literal_null;
break;
}
-basic_json_parser_58:
+basic_json_parser_61:
++m_cursor;
{
last_token_type = token_type::literal_true;
break;
}
-basic_json_parser_60:
+basic_json_parser_63:
++m_cursor;
if (m_limit <= m_cursor)
{
- yyfill(); // LCOV_EXCL_LINE;
+ fill_line_buffer(1); // LCOV_EXCL_LINE
}
yych = *m_cursor;
if (yych <= '@')
{
if (yych <= '/')
{
- goto basic_json_parser_33;
+ goto basic_json_parser_32;
}
if (yych <= '9')
{
- goto basic_json_parser_63;
+ goto basic_json_parser_66;
}
- goto basic_json_parser_33;
+ goto basic_json_parser_32;
}
else
{
if (yych <= 'F')
{
- goto basic_json_parser_63;
+ goto basic_json_parser_66;
}
if (yych <= '`')
{
- goto basic_json_parser_33;
+ goto basic_json_parser_32;
}
if (yych <= 'f')
{
- goto basic_json_parser_63;
+ goto basic_json_parser_66;
}
- goto basic_json_parser_33;
+ goto basic_json_parser_32;
}
-basic_json_parser_61:
+basic_json_parser_64:
++m_cursor;
{
last_token_type = token_type::literal_false;
break;
}
-basic_json_parser_63:
+basic_json_parser_66:
++m_cursor;
if (m_limit <= m_cursor)
{
- yyfill(); // LCOV_EXCL_LINE;
+ fill_line_buffer(1); // LCOV_EXCL_LINE
}
yych = *m_cursor;
if (yych <= '@')
{
if (yych <= '/')
{
- goto basic_json_parser_33;
+ goto basic_json_parser_32;
}
if (yych <= '9')
{
- goto basic_json_parser_31;
+ goto basic_json_parser_30;
}
- goto basic_json_parser_33;
+ goto basic_json_parser_32;
}
else
{
if (yych <= 'F')
{
- goto basic_json_parser_31;
+ goto basic_json_parser_30;
}
if (yych <= '`')
{
- goto basic_json_parser_33;
+ goto basic_json_parser_32;
}
if (yych <= 'f')
{
- goto basic_json_parser_31;
+ goto basic_json_parser_30;
}
- goto basic_json_parser_33;
+ goto basic_json_parser_32;
}
}
@@ -8455,30 +10164,93 @@ basic_json_parser_63:
return last_token_type;
}
- /// append data from the stream to the internal buffer
- void yyfill() noexcept
- {
- if (m_stream == nullptr or not * m_stream)
+ /*!
+ @brief append data from the stream to the line buffer
+
+ This function is called by the scan() function when the end of the
+ buffer (`m_limit`) is reached and the `m_cursor` pointer cannot be
+ incremented without leaving the limits of the line buffer. Note re2c
+ decides when to call this function.
+
+ If the lexer reads from contiguous storage, there is no trailing null
+ byte. Therefore, this function must make sure to add these padding
+ null bytes.
+
+ If the lexer reads from an input stream, this function reads the next
+ line of the input.
+
+ @pre
+ p p p p p p u u u u u x . . . . . .
+ ^ ^ ^ ^
+ m_content m_start | m_limit
+ m_cursor
+
+ @post
+ u u u u u x x x x x x x . . . . . .
+ ^ ^ ^
+ | m_cursor m_limit
+ m_start
+ m_content
+ */
+ void fill_line_buffer(size_t n = 0)
+ {
+ // if line buffer is used, m_content points to its data
+ assert(m_line_buffer.empty()
+ or m_content == reinterpret_cast<const lexer_char_t*>(m_line_buffer.data()));
+
+ // if line buffer is used, m_limit is set past the end of its data
+ assert(m_line_buffer.empty()
+ or m_limit == m_content + m_line_buffer.size());
+
+ // pointer relationships
+ assert(m_content <= m_start);
+ assert(m_start <= m_cursor);
+ assert(m_cursor <= m_limit);
+ assert(m_marker == nullptr or m_marker <= m_limit);
+
+ // number of processed characters (p)
+ const size_t num_processed_chars = static_cast<size_t>(m_start - m_content);
+ // offset for m_marker wrt. to m_start
+ const auto offset_marker = (m_marker == nullptr) ? 0 : m_marker - m_start;
+ // number of unprocessed characters (u)
+ const auto offset_cursor = m_cursor - m_start;
+
+ // no stream is used or end of file is reached
+ if (m_stream == nullptr or m_stream->eof())
{
- return;
- }
+ // m_start may or may not be pointing into m_line_buffer at
+ // this point. We trust the standand library to do the right
+ // thing. See http://stackoverflow.com/q/28142011/266378
+ m_line_buffer.assign(m_start, m_limit);
- const auto offset_start = m_start - m_content;
- const auto offset_marker = m_marker - m_start;
- const auto offset_cursor = m_cursor - m_start;
+ // append n characters to make sure that there is sufficient
+ // space between m_cursor and m_limit
+ m_line_buffer.append(1, '\x00');
+ if (n > 0)
+ {
+ m_line_buffer.append(n - 1, '\x01');
+ }
+ }
+ else
+ {
+ // delete processed characters from line buffer
+ m_line_buffer.erase(0, num_processed_chars);
+ // read next line from input stream
+ m_line_buffer_tmp.clear();
+ std::getline(*m_stream, m_line_buffer_tmp, '\n');
- m_buffer.erase(0, static_cast<size_t>(offset_start));
- std::string line;
- assert(m_stream != nullptr);
- std::getline(*m_stream, line);
- m_buffer += "\n" + line; // add line with newline symbol
+ // add line with newline symbol to the line buffer
+ m_line_buffer += m_line_buffer_tmp;
+ m_line_buffer.push_back('\n');
+ }
- m_content = reinterpret_cast<const lexer_char_t*>(m_buffer.c_str());
+ // set pointers
+ m_content = reinterpret_cast<const lexer_char_t*>(m_line_buffer.data());
assert(m_content != nullptr);
m_start = m_content;
m_marker = m_start + offset_marker;
m_cursor = m_start + offset_cursor;
- m_limit = m_start + m_buffer.size() - 1;
+ m_limit = m_start + m_line_buffer.size();
}
/// return string representation of last read token
@@ -8556,9 +10328,20 @@ basic_json_parser_63:
// iterate the result between the quotes
for (const lexer_char_t* i = m_start + 1; i < m_cursor - 1; ++i)
{
- // process escaped characters
- if (*i == '\\')
+ // find next escape character
+ auto e = std::find(i, m_cursor - 1, '\\');
+ if (e != i)
+ {
+ // see https://github.com/nlohmann/json/issues/365#issuecomment-262874705
+ for (auto k = i; k < e; k++)
+ {
+ result.push_back(static_cast<typename string_t::value_type>(*k));
+ }
+ i = e - 1; // -1 because of ++i
+ }
+ else
{
+ // processing escaped character
// read next character
++i;
@@ -8629,6 +10412,11 @@ basic_json_parser_63:
// skip the next 10 characters (xxxx\uyyyy)
i += 10;
}
+ else if (codepoint >= 0xDC00 and codepoint <= 0xDFFF)
+ {
+ // we found a lone low surrogate
+ throw std::invalid_argument("missing high surrogate");
+ }
else
{
// add unicode character(s)
@@ -8640,12 +10428,6 @@ basic_json_parser_63:
}
}
}
- else
- {
- // all other characters are just copied to the end of the
- // string
- result.append(1, static_cast<typename string_t::value_type>(*i));
- }
}
return result;
@@ -8659,8 +10441,6 @@ basic_json_parser_63:
supplied via the first parameter. Set this to @a
static_cast<number_float_t*>(nullptr).
- @param[in] type the @ref number_float_t in use
-
@param[in,out] endptr recieves a pointer to the first character after
the number
@@ -8679,8 +10459,6 @@ basic_json_parser_63:
supplied via the first parameter. Set this to @a
static_cast<number_float_t*>(nullptr).
- @param[in] type the @ref number_float_t in use
-
@param[in,out] endptr recieves a pointer to the first character after
the number
@@ -8699,8 +10477,6 @@ basic_json_parser_63:
supplied via the first parameter. Set this to @a
static_cast<number_float_t*>(nullptr).
- @param[in] type the @ref number_float_t in use
-
@param[in,out] endptr recieves a pointer to the first character after
the number
@@ -8781,19 +10557,19 @@ basic_json_parser_63:
// skip if definitely not an integer
if (type != value_t::number_float)
{
- // multiply last value by ten and add the new digit
- auto temp = value * 10 + *curptr - '0';
+ auto digit = static_cast<number_unsigned_t>(*curptr - '0');
- // test for overflow
- if (temp < value || temp > max)
+ // overflow if value * 10 + digit > max, move terms around
+ // to avoid overflow in intermediate values
+ if (value > (max - digit) / 10)
{
// overflow
type = value_t::number_float;
}
else
{
- // no overflow - save it
- value = temp;
+ // no overflow
+ value = value * 10 + digit;
}
}
}
@@ -8805,12 +10581,34 @@ basic_json_parser_63:
}
else if (type == value_t::number_integer)
{
- result.m_value.number_integer = -static_cast<number_integer_t>(value);
+ // invariant: if we parsed a '-', the absolute value is between
+ // 0 (we allow -0) and max == -INT64_MIN
+ assert(value >= 0);
+ assert(value <= max);
+
+ if (value == max)
+ {
+ // we cannot simply negate value (== max == -INT64_MIN),
+ // see https://github.com/nlohmann/json/issues/389
+ result.m_value.number_integer = static_cast<number_integer_t>(INT64_MIN);
+ }
+ else
+ {
+ // all other values can be negated safely
+ result.m_value.number_integer = -static_cast<number_integer_t>(value);
+ }
}
else
{
// parse with strtod
result.m_value.number_float = str_to_float_t(static_cast<number_float_t*>(nullptr), NULL);
+
+ // replace infinity and NAN by null
+ if (not std::isfinite(result.m_value.number_float))
+ {
+ type = value_t::null;
+ result.m_value = basic_json::json_value();
+ }
}
// save the type
@@ -8820,8 +10618,10 @@ basic_json_parser_63:
private:
/// optional input stream
std::istream* m_stream = nullptr;
- /// the buffer
- string_t m_buffer;
+ /// line buffer buffer for m_stream
+ string_t m_line_buffer {};
+ /// used for filling m_line_buffer
+ string_t m_line_buffer_tmp {};
/// the buffer pointer
const lexer_char_t* m_content = nullptr;
/// pointer to the beginning of the current symbol
@@ -8844,25 +10644,34 @@ basic_json_parser_63:
class parser
{
public:
- /// constructor for strings
- parser(const string_t& s, const parser_callback_t cb = nullptr) noexcept
- : callback(cb), m_lexer(s)
- {
- // read first token
- get_token();
- }
+ /// a parser reading from a string literal
+ parser(const char* buff, const parser_callback_t cb = nullptr)
+ : callback(cb),
+ m_lexer(reinterpret_cast<const typename lexer::lexer_char_t*>(buff), std::strlen(buff))
+ {}
/// a parser reading from an input stream
- parser(std::istream& _is, const parser_callback_t cb = nullptr) noexcept
- : callback(cb), m_lexer(&_is)
- {
- // read first token
- get_token();
- }
+ parser(std::istream& is, const parser_callback_t cb = nullptr)
+ : callback(cb), m_lexer(is)
+ {}
+
+ /// a parser reading from an iterator range with contiguous storage
+ template<class IteratorType, typename std::enable_if<
+ std::is_same<typename std::iterator_traits<IteratorType>::iterator_category, std::random_access_iterator_tag>::value
+ , int>::type
+ = 0>
+ parser(IteratorType first, IteratorType last, const parser_callback_t cb = nullptr)
+ : callback(cb),
+ m_lexer(reinterpret_cast<const typename lexer::lexer_char_t*>(&(*first)),
+ static_cast<size_t>(std::distance(first, last)))
+ {}
/// public parser interface
basic_json parse()
{
+ // read first token
+ get_token();
+
basic_json result = parse_internal(true);
result.assert_invariant();
@@ -8883,7 +10692,8 @@ basic_json_parser_63:
{
case lexer::token_type::begin_object:
{
- if (keep and (not callback or (keep = callback(depth++, parse_event_t::object_start, result))))
+ if (keep and (not callback
+ or ((keep = callback(depth++, parse_event_t::object_start, result)) != 0)))
{
// explicitly set result to object to cope with {}
result.m_type = value_t::object;
@@ -8961,7 +10771,8 @@ basic_json_parser_63:
case lexer::token_type::begin_array:
{
- if (keep and (not callback or (keep = callback(depth++, parse_event_t::array_start, result))))
+ if (keep and (not callback
+ or ((keep = callback(depth++, parse_event_t::array_start, result)) != 0)))
{
// explicitly set result to object to cope with []
result.m_type = value_t::array;
@@ -9067,7 +10878,7 @@ basic_json_parser_63:
}
/// get next token from lexer
- typename lexer::token_type get_token() noexcept
+ typename lexer::token_type get_token()
{
last_token = m_lexer.scan();
return last_token;
@@ -9280,6 +11091,12 @@ basic_json_parser_63:
/*!
@brief return a reference to the pointed to value
+ @note This version does not throw if a value is not present, but tries
+ to create nested values instead. For instance, calling this function
+ with pointer `"/this/that"` on a null value is equivalent to calling
+ `operator[]("this").operator[]("that")` on that value, effectively
+ changing the null value to an object.
+
@param[in] ptr a JSON value
@return reference to the JSON value pointed to by the JSON pointer
@@ -9294,6 +11111,29 @@ basic_json_parser_63:
{
for (const auto& reference_token : reference_tokens)
{
+ // convert null values to arrays or objects before continuing
+ if (ptr->m_type == value_t::null)
+ {
+ // check if reference token is a number
+ const bool nums = std::all_of(reference_token.begin(),
+ reference_token.end(),
+ [](const char x)
+ {
+ return std::isdigit(x);
+ });
+
+ // change value to array for numbers or "-" or to object
+ // otherwise
+ if (nums or reference_token == "-")
+ {
+ *ptr = value_t::array;
+ }
+ else
+ {
+ *ptr = value_t::object;
+ }
+ }
+
switch (ptr->m_type)
{
case value_t::object:
@@ -9475,7 +11315,7 @@ basic_json_parser_63:
}
/// split the string input to reference tokens
- static std::vector<std::string> split(std::string reference_string)
+ static std::vector<std::string> split(const std::string& reference_string)
{
std::vector<std::string> result;
@@ -9539,13 +11379,11 @@ basic_json_parser_63:
/*!
@brief replace all occurrences of a substring by another string
- @param[in,out] s the string to manipulate
+ @param[in,out] s the string to manipulate; changed so that all
+ occurrences of @a f are replaced with @a t
@param[in] f the substring to replace with @a t
@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.
-
@pre The search string @a f must not be empty.
@since version 2.0.0
@@ -9960,7 +11798,7 @@ basic_json_parser_63:
json_pointer top_pointer = ptr.top();
if (top_pointer != ptr)
{
- basic_json& x = result.at(top_pointer);
+ result.at(top_pointer);
}
// get reference to parent of JSON pointer ptr
@@ -10203,7 +12041,7 @@ basic_json_parser_63:
*/
static basic_json diff(const basic_json& source,
const basic_json& target,
- std::string path = "")
+ const std::string& path = "")
{
// the patch
basic_json result(value_t::array);
@@ -10365,7 +12203,7 @@ namespace std
@since version 1.0.0
*/
-template <>
+template<>
inline void swap(nlohmann::json& j1,
nlohmann::json& j2) noexcept(
is_nothrow_move_constructible<nlohmann::json>::value and
@@ -10376,7 +12214,7 @@ inline void swap(nlohmann::json& j1,
}
/// hash value for JSON objects
-template <>
+template<>
struct hash<nlohmann::json>
{
/*!
@@ -10401,30 +12239,32 @@ can be used by adding `"_json"` to a string literal and returns a JSON object
if no parse error occurred.
@param[in] s a string representation of a JSON object
+@param[in] n the length of string @a s
@return a JSON object
@since version 1.0.0
*/
-inline nlohmann::json operator "" _json(const char* s, std::size_t)
+inline nlohmann::json operator "" _json(const char* s, std::size_t n)
{
- return nlohmann::json::parse(reinterpret_cast<const nlohmann::json::string_t::value_type*>(s));
+ return nlohmann::json::parse(s, s + n);
}
/*!
@brief user-defined string literal for JSON pointer
This operator implements a user-defined string literal for JSON Pointers. It
-can be used by adding `"_json"` to a string literal and returns a JSON pointer
+can be used by adding `"_json_pointer"` to a string literal and returns a JSON pointer
object if no parse error occurred.
@param[in] s a string representation of a JSON Pointer
+@param[in] n the length of string @a s
@return a JSON pointer object
@since version 2.0.0
*/
-inline nlohmann::json::json_pointer operator "" _json_pointer(const char* s, std::size_t)
+inline nlohmann::json::json_pointer operator "" _json_pointer(const char* s, std::size_t n)
{
- return nlohmann::json::json_pointer(s);
+ return nlohmann::json::json_pointer(std::string(s, n));
}
// restore GCC/clang diagnostic settings