Merge branch 'develop' into feature/release_information
This commit is contained in:
commit
e1b89dd1d6
7 changed files with 287 additions and 348 deletions
|
@ -600,6 +600,7 @@ Thanks a lot for helping out!
|
||||||
- Other encodings such as Latin-1, UTF-16, or UTF-32 are not supported and will yield parse errors.
|
- Other encodings such as Latin-1, UTF-16, or UTF-32 are not supported and will yield parse errors.
|
||||||
- [Unicode noncharacters](http://www.unicode.org/faq/private_use.html#nonchar1) will not be replaced by the library.
|
- [Unicode noncharacters](http://www.unicode.org/faq/private_use.html#nonchar1) will not be replaced by the library.
|
||||||
- Invalid surrogates (e.g., incomplete pairs such as `\uDEAD`) will yield parse errors.
|
- Invalid surrogates (e.g., incomplete pairs such as `\uDEAD`) will yield parse errors.
|
||||||
|
- The strings stored in the library are UTF-8 encoded. When using the default string type (`std::string`), note that its length/size functions return the number of stored bytes rather than the number of characters or glyphs.
|
||||||
|
|
||||||
|
|
||||||
## Execute unit tests
|
## Execute unit tests
|
||||||
|
|
297
src/json.hpp
297
src/json.hpp
|
@ -58,13 +58,11 @@ SOFTWARE.
|
||||||
|
|
||||||
// exclude unsupported compilers
|
// exclude unsupported compilers
|
||||||
#if defined(__clang__)
|
#if defined(__clang__)
|
||||||
#define CLANG_VERSION (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__)
|
#if (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) < 30400
|
||||||
#if CLANG_VERSION < 30400
|
|
||||||
#error "unsupported Clang version - see https://github.com/nlohmann/json#supported-compilers"
|
#error "unsupported Clang version - see https://github.com/nlohmann/json#supported-compilers"
|
||||||
#endif
|
#endif
|
||||||
#elif defined(__GNUC__)
|
#elif defined(__GNUC__)
|
||||||
#define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
|
#if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40900
|
||||||
#if GCC_VERSION < 40900
|
|
||||||
#error "unsupported GCC version - see https://github.com/nlohmann/json#supported-compilers"
|
#error "unsupported GCC version - see https://github.com/nlohmann/json#supported-compilers"
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
@ -128,7 +126,7 @@ struct has_mapped_type
|
||||||
std::is_integral<decltype(detect(std::declval<T>()))>::value;
|
std::is_integral<decltype(detect(std::declval<T>()))>::value;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
} // namespace
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@brief a class to store JSON values
|
@brief a class to store JSON values
|
||||||
|
@ -153,7 +151,8 @@ default)
|
||||||
@requirement The class satisfies the following concept requirements:
|
@requirement The class satisfies the following concept requirements:
|
||||||
- Basic
|
- Basic
|
||||||
- [DefaultConstructible](http://en.cppreference.com/w/cpp/concept/DefaultConstructible):
|
- [DefaultConstructible](http://en.cppreference.com/w/cpp/concept/DefaultConstructible):
|
||||||
JSON values can be default constructed. The result will be a JSON null value.
|
JSON values can be default constructed. The result will be a JSON null
|
||||||
|
value.
|
||||||
- [MoveConstructible](http://en.cppreference.com/w/cpp/concept/MoveConstructible):
|
- [MoveConstructible](http://en.cppreference.com/w/cpp/concept/MoveConstructible):
|
||||||
A JSON value can be constructed from an rvalue argument.
|
A JSON value can be constructed from an rvalue argument.
|
||||||
- [CopyConstructible](http://en.cppreference.com/w/cpp/concept/CopyConstructible):
|
- [CopyConstructible](http://en.cppreference.com/w/cpp/concept/CopyConstructible):
|
||||||
|
@ -168,8 +167,8 @@ default)
|
||||||
- [StandardLayoutType](http://en.cppreference.com/w/cpp/concept/StandardLayoutType):
|
- [StandardLayoutType](http://en.cppreference.com/w/cpp/concept/StandardLayoutType):
|
||||||
JSON values have
|
JSON values have
|
||||||
[standard layout](http://en.cppreference.com/w/cpp/language/data_members#Standard_layout):
|
[standard layout](http://en.cppreference.com/w/cpp/language/data_members#Standard_layout):
|
||||||
All non-static data members are private and standard layout types, the class
|
All non-static data members are private and standard layout types, the
|
||||||
has no virtual functions or (virtual) base classes.
|
class has no virtual functions or (virtual) base classes.
|
||||||
- Library-wide
|
- Library-wide
|
||||||
- [EqualityComparable](http://en.cppreference.com/w/cpp/concept/EqualityComparable):
|
- [EqualityComparable](http://en.cppreference.com/w/cpp/concept/EqualityComparable):
|
||||||
JSON values can be compared with `==`, see @ref
|
JSON values can be compared with `==`, see @ref
|
||||||
|
@ -507,6 +506,12 @@ class basic_json
|
||||||
std::string
|
std::string
|
||||||
@endcode
|
@endcode
|
||||||
|
|
||||||
|
#### Encoding
|
||||||
|
|
||||||
|
Strings are stored in UTF-8 encoding. Therefore, functions like
|
||||||
|
`std::string::size()` or `std::string::length()` return the number of
|
||||||
|
bytes in the string rather than the number of characters or glyphs.
|
||||||
|
|
||||||
#### String comparison
|
#### String comparison
|
||||||
|
|
||||||
[RFC 7159](http://rfc7159.net/rfc7159) states:
|
[RFC 7159](http://rfc7159.net/rfc7159) states:
|
||||||
|
@ -825,7 +830,7 @@ class basic_json
|
||||||
};
|
};
|
||||||
std::unique_ptr<T, decltype(deleter)> object(alloc.allocate(1), deleter);
|
std::unique_ptr<T, decltype(deleter)> object(alloc.allocate(1), deleter);
|
||||||
alloc.construct(object.get(), std::forward<Args>(args)...);
|
alloc.construct(object.get(), std::forward<Args>(args)...);
|
||||||
assert(object.get() != nullptr);
|
assert(object != nullptr);
|
||||||
return object.release();
|
return object.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1952,13 +1957,15 @@ class basic_json
|
||||||
|
|
||||||
case value_t::object:
|
case value_t::object:
|
||||||
{
|
{
|
||||||
m_value.object = create<object_t>(first.m_it.object_iterator, last.m_it.object_iterator);
|
m_value.object = create<object_t>(first.m_it.object_iterator,
|
||||||
|
last.m_it.object_iterator);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case value_t::array:
|
case value_t::array:
|
||||||
{
|
{
|
||||||
m_value.array = create<array_t>(first.m_it.array_iterator, last.m_it.array_iterator);
|
m_value.array = create<array_t>(first.m_it.array_iterator,
|
||||||
|
last.m_it.array_iterator);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2641,29 +2648,25 @@ class basic_json
|
||||||
template<class T, typename std::enable_if<
|
template<class T, typename std::enable_if<
|
||||||
std::is_convertible<typename object_t::key_type, typename T::key_type>::value and
|
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>
|
std::is_convertible<basic_json_t, typename T::mapped_type>::value, int>::type = 0>
|
||||||
T get_impl(T*) const
|
T get_impl(T* /*unused*/) const
|
||||||
{
|
{
|
||||||
if (is_object())
|
if (is_object())
|
||||||
{
|
{
|
||||||
return T(m_value.object->begin(), m_value.object->end());
|
return T(m_value.object->begin(), m_value.object->end());
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
throw std::domain_error("type must be object, but is " + type_name());
|
||||||
throw std::domain_error("type must be object, but is " + type_name());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// get an object (explicit)
|
/// get an object (explicit)
|
||||||
object_t get_impl(object_t*) const
|
object_t get_impl(object_t* /*unused*/) const
|
||||||
{
|
{
|
||||||
if (is_object())
|
if (is_object())
|
||||||
{
|
{
|
||||||
return *(m_value.object);
|
return *(m_value.object);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
throw std::domain_error("type must be object, but is " + type_name());
|
||||||
throw std::domain_error("type must be object, but is " + type_name());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// get an array (explicit)
|
/// get an array (explicit)
|
||||||
|
@ -2673,7 +2676,7 @@ class basic_json
|
||||||
not std::is_arithmetic<T>::value and
|
not std::is_arithmetic<T>::value and
|
||||||
not std::is_convertible<std::string, T>::value and
|
not std::is_convertible<std::string, T>::value and
|
||||||
not has_mapped_type<T>::value, int>::type = 0>
|
not has_mapped_type<T>::value, int>::type = 0>
|
||||||
T get_impl(T*) const
|
T get_impl(T* /*unused*/) const
|
||||||
{
|
{
|
||||||
if (is_array())
|
if (is_array())
|
||||||
{
|
{
|
||||||
|
@ -2685,17 +2688,15 @@ class basic_json
|
||||||
});
|
});
|
||||||
return to_vector;
|
return to_vector;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
throw std::domain_error("type must be array, but is " + type_name());
|
||||||
throw std::domain_error("type must be array, but is " + type_name());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// get an array (explicit)
|
/// get an array (explicit)
|
||||||
template<class T, typename std::enable_if<
|
template<class T, typename std::enable_if<
|
||||||
std::is_convertible<basic_json_t, T>::value and
|
std::is_convertible<basic_json_t, T>::value and
|
||||||
not std::is_same<basic_json_t, T>::value, int>::type = 0>
|
not std::is_same<basic_json_t, T>::value, int>::type = 0>
|
||||||
std::vector<T> get_impl(std::vector<T>*) const
|
std::vector<T> get_impl(std::vector<T>* /*unused*/) const
|
||||||
{
|
{
|
||||||
if (is_array())
|
if (is_array())
|
||||||
{
|
{
|
||||||
|
@ -2708,60 +2709,52 @@ class basic_json
|
||||||
});
|
});
|
||||||
return to_vector;
|
return to_vector;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
throw std::domain_error("type must be array, but is " + type_name());
|
||||||
throw std::domain_error("type must be array, but is " + type_name());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// get an array (explicit)
|
/// get an array (explicit)
|
||||||
template<class T, typename std::enable_if<
|
template<class T, typename std::enable_if<
|
||||||
std::is_same<basic_json, typename T::value_type>::value and
|
std::is_same<basic_json, typename T::value_type>::value and
|
||||||
not has_mapped_type<T>::value, int>::type = 0>
|
not has_mapped_type<T>::value, int>::type = 0>
|
||||||
T get_impl(T*) const
|
T get_impl(T* /*unused*/) const
|
||||||
{
|
{
|
||||||
if (is_array())
|
if (is_array())
|
||||||
{
|
{
|
||||||
return T(m_value.array->begin(), m_value.array->end());
|
return T(m_value.array->begin(), m_value.array->end());
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
throw std::domain_error("type must be array, but is " + type_name());
|
||||||
throw std::domain_error("type must be array, but is " + type_name());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// get an array (explicit)
|
/// get an array (explicit)
|
||||||
array_t get_impl(array_t*) const
|
array_t get_impl(array_t* /*unused*/) const
|
||||||
{
|
{
|
||||||
if (is_array())
|
if (is_array())
|
||||||
{
|
{
|
||||||
return *(m_value.array);
|
return *(m_value.array);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
throw std::domain_error("type must be array, but is " + type_name());
|
||||||
throw std::domain_error("type must be array, but is " + type_name());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// get a string (explicit)
|
/// get a string (explicit)
|
||||||
template<typename T, typename std::enable_if<
|
template<typename T, typename std::enable_if<
|
||||||
std::is_convertible<string_t, T>::value, int>::type = 0>
|
std::is_convertible<string_t, T>::value, int>::type = 0>
|
||||||
T get_impl(T*) const
|
T get_impl(T* /*unused*/) const
|
||||||
{
|
{
|
||||||
if (is_string())
|
if (is_string())
|
||||||
{
|
{
|
||||||
return *m_value.string;
|
return *m_value.string;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
throw std::domain_error("type must be string, but is " + type_name());
|
||||||
throw std::domain_error("type must be string, but is " + type_name());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// get a number (explicit)
|
/// get a number (explicit)
|
||||||
template<typename T, typename std::enable_if<
|
template<typename T, typename std::enable_if<
|
||||||
std::is_arithmetic<T>::value, int>::type = 0>
|
std::is_arithmetic<T>::value, int>::type = 0>
|
||||||
T get_impl(T*) const
|
T get_impl(T* /*unused*/) const
|
||||||
{
|
{
|
||||||
switch (m_type)
|
switch (m_type)
|
||||||
{
|
{
|
||||||
|
@ -2788,7 +2781,7 @@ class basic_json
|
||||||
}
|
}
|
||||||
|
|
||||||
/// get a boolean (explicit)
|
/// get a boolean (explicit)
|
||||||
constexpr boolean_t get_impl(boolean_t*) const
|
constexpr boolean_t get_impl(boolean_t* /*unused*/) const
|
||||||
{
|
{
|
||||||
return is_boolean()
|
return is_boolean()
|
||||||
? m_value.boolean
|
? m_value.boolean
|
||||||
|
@ -2796,85 +2789,85 @@ class basic_json
|
||||||
}
|
}
|
||||||
|
|
||||||
/// get a pointer to the value (object)
|
/// get a pointer to the value (object)
|
||||||
object_t* get_impl_ptr(object_t*) noexcept
|
object_t* get_impl_ptr(object_t* /*unused*/) noexcept
|
||||||
{
|
{
|
||||||
return is_object() ? m_value.object : nullptr;
|
return is_object() ? m_value.object : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// get a pointer to the value (object)
|
/// get a pointer to the value (object)
|
||||||
constexpr const object_t* get_impl_ptr(const object_t*) const noexcept
|
constexpr const object_t* get_impl_ptr(const object_t* /*unused*/) const noexcept
|
||||||
{
|
{
|
||||||
return is_object() ? m_value.object : nullptr;
|
return is_object() ? m_value.object : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// get a pointer to the value (array)
|
/// get a pointer to the value (array)
|
||||||
array_t* get_impl_ptr(array_t*) noexcept
|
array_t* get_impl_ptr(array_t* /*unused*/) noexcept
|
||||||
{
|
{
|
||||||
return is_array() ? m_value.array : nullptr;
|
return is_array() ? m_value.array : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// get a pointer to the value (array)
|
/// get a pointer to the value (array)
|
||||||
constexpr const array_t* get_impl_ptr(const array_t*) const noexcept
|
constexpr const array_t* get_impl_ptr(const array_t* /*unused*/) const noexcept
|
||||||
{
|
{
|
||||||
return is_array() ? m_value.array : nullptr;
|
return is_array() ? m_value.array : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// get a pointer to the value (string)
|
/// get a pointer to the value (string)
|
||||||
string_t* get_impl_ptr(string_t*) noexcept
|
string_t* get_impl_ptr(string_t* /*unused*/) noexcept
|
||||||
{
|
{
|
||||||
return is_string() ? m_value.string : nullptr;
|
return is_string() ? m_value.string : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// get a pointer to the value (string)
|
/// get a pointer to the value (string)
|
||||||
constexpr const string_t* get_impl_ptr(const string_t*) const noexcept
|
constexpr const string_t* get_impl_ptr(const string_t* /*unused*/) const noexcept
|
||||||
{
|
{
|
||||||
return is_string() ? m_value.string : nullptr;
|
return is_string() ? m_value.string : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// get a pointer to the value (boolean)
|
/// get a pointer to the value (boolean)
|
||||||
boolean_t* get_impl_ptr(boolean_t*) noexcept
|
boolean_t* get_impl_ptr(boolean_t* /*unused*/) noexcept
|
||||||
{
|
{
|
||||||
return is_boolean() ? &m_value.boolean : nullptr;
|
return is_boolean() ? &m_value.boolean : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// get a pointer to the value (boolean)
|
/// get a pointer to the value (boolean)
|
||||||
constexpr const boolean_t* get_impl_ptr(const boolean_t*) const noexcept
|
constexpr const boolean_t* get_impl_ptr(const boolean_t* /*unused*/) const noexcept
|
||||||
{
|
{
|
||||||
return is_boolean() ? &m_value.boolean : nullptr;
|
return is_boolean() ? &m_value.boolean : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// get a pointer to the value (integer number)
|
/// get a pointer to the value (integer number)
|
||||||
number_integer_t* get_impl_ptr(number_integer_t*) noexcept
|
number_integer_t* get_impl_ptr(number_integer_t* /*unused*/) noexcept
|
||||||
{
|
{
|
||||||
return is_number_integer() ? &m_value.number_integer : nullptr;
|
return is_number_integer() ? &m_value.number_integer : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// get a pointer to the value (integer number)
|
/// get a pointer to the value (integer number)
|
||||||
constexpr const number_integer_t* get_impl_ptr(const number_integer_t*) const noexcept
|
constexpr const number_integer_t* get_impl_ptr(const number_integer_t* /*unused*/) const noexcept
|
||||||
{
|
{
|
||||||
return is_number_integer() ? &m_value.number_integer : nullptr;
|
return is_number_integer() ? &m_value.number_integer : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// get a pointer to the value (unsigned number)
|
/// get a pointer to the value (unsigned number)
|
||||||
number_unsigned_t* get_impl_ptr(number_unsigned_t*) noexcept
|
number_unsigned_t* get_impl_ptr(number_unsigned_t* /*unused*/) noexcept
|
||||||
{
|
{
|
||||||
return is_number_unsigned() ? &m_value.number_unsigned : nullptr;
|
return is_number_unsigned() ? &m_value.number_unsigned : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// get a pointer to the value (unsigned number)
|
/// get a pointer to the value (unsigned number)
|
||||||
constexpr const number_unsigned_t* get_impl_ptr(const number_unsigned_t*) const noexcept
|
constexpr const number_unsigned_t* get_impl_ptr(const number_unsigned_t* /*unused*/) const noexcept
|
||||||
{
|
{
|
||||||
return is_number_unsigned() ? &m_value.number_unsigned : nullptr;
|
return is_number_unsigned() ? &m_value.number_unsigned : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// get a pointer to the value (floating-point number)
|
/// get a pointer to the value (floating-point number)
|
||||||
number_float_t* get_impl_ptr(number_float_t*) noexcept
|
number_float_t* get_impl_ptr(number_float_t* /*unused*/) noexcept
|
||||||
{
|
{
|
||||||
return is_number_float() ? &m_value.number_float : nullptr;
|
return is_number_float() ? &m_value.number_float : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// get a pointer to the value (floating-point number)
|
/// get a pointer to the value (floating-point number)
|
||||||
constexpr const number_float_t* get_impl_ptr(const number_float_t*) const noexcept
|
constexpr const number_float_t* get_impl_ptr(const number_float_t* /*unused*/) const noexcept
|
||||||
{
|
{
|
||||||
return is_number_float() ? &m_value.number_float : nullptr;
|
return is_number_float() ? &m_value.number_float : nullptr;
|
||||||
}
|
}
|
||||||
|
@ -2903,11 +2896,9 @@ class basic_json
|
||||||
{
|
{
|
||||||
return *ptr;
|
return *ptr;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
throw std::domain_error("incompatible ReferenceType for get_ref, actual type is " +
|
||||||
throw std::domain_error("incompatible ReferenceType for get_ref, actual type is " +
|
obj.type_name());
|
||||||
obj.type_name());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -3158,7 +3149,7 @@ class basic_json
|
||||||
template < typename ValueType, typename std::enable_if <
|
template < typename ValueType, typename std::enable_if <
|
||||||
not std::is_pointer<ValueType>::value and
|
not std::is_pointer<ValueType>::value and
|
||||||
not std::is_same<ValueType, typename string_t::value_type>::value
|
not std::is_same<ValueType, typename string_t::value_type>::value
|
||||||
#ifndef _MSC_VER // Fix for issue #167 operator<< abiguity under VS2015
|
#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
|
and not std::is_same<ValueType, std::initializer_list<typename string_t::value_type>>::value
|
||||||
#endif
|
#endif
|
||||||
, int >::type = 0 >
|
, int >::type = 0 >
|
||||||
|
@ -3407,10 +3398,8 @@ class basic_json
|
||||||
|
|
||||||
return m_value.array->operator[](idx);
|
return m_value.array->operator[](idx);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
throw std::domain_error("cannot use operator[] with " + type_name());
|
||||||
throw std::domain_error("cannot use operator[] with " + type_name());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -3439,10 +3428,8 @@ class basic_json
|
||||||
{
|
{
|
||||||
return m_value.array->operator[](idx);
|
return m_value.array->operator[](idx);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
throw std::domain_error("cannot use operator[] with " + type_name());
|
||||||
throw std::domain_error("cannot use operator[] with " + type_name());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -3487,10 +3474,8 @@ class basic_json
|
||||||
{
|
{
|
||||||
return m_value.object->operator[](key);
|
return m_value.object->operator[](key);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
throw std::domain_error("cannot use operator[] with " + type_name());
|
||||||
throw std::domain_error("cannot use operator[] with " + type_name());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -3531,10 +3516,8 @@ class basic_json
|
||||||
assert(m_value.object->find(key) != m_value.object->end());
|
assert(m_value.object->find(key) != m_value.object->end());
|
||||||
return m_value.object->find(key)->second;
|
return m_value.object->find(key)->second;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
throw std::domain_error("cannot use operator[] with " + type_name());
|
||||||
throw std::domain_error("cannot use operator[] with " + type_name());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -3648,10 +3631,8 @@ class basic_json
|
||||||
{
|
{
|
||||||
return m_value.object->operator[](key);
|
return m_value.object->operator[](key);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
throw std::domain_error("cannot use operator[] with " + type_name());
|
||||||
throw std::domain_error("cannot use operator[] with " + type_name());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -3693,10 +3674,8 @@ class basic_json
|
||||||
assert(m_value.object->find(key) != m_value.object->end());
|
assert(m_value.object->find(key) != m_value.object->end());
|
||||||
return m_value.object->find(key)->second;
|
return m_value.object->find(key)->second;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
throw std::domain_error("cannot use operator[] with " + type_name());
|
||||||
throw std::domain_error("cannot use operator[] with " + type_name());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -3760,10 +3739,8 @@ class basic_json
|
||||||
{
|
{
|
||||||
return *it;
|
return *it;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
return default_value;
|
||||||
return default_value;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -3838,10 +3815,8 @@ class basic_json
|
||||||
return default_value;
|
return default_value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
throw std::domain_error("cannot use value() with " + type_name());
|
||||||
throw std::domain_error("cannot use value() with " + type_name());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -4189,10 +4164,8 @@ class basic_json
|
||||||
{
|
{
|
||||||
return m_value.object->erase(key);
|
return m_value.object->erase(key);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
throw std::domain_error("cannot use erase() with " + type_name());
|
||||||
throw std::domain_error("cannot use erase() with " + type_name());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -5155,8 +5128,8 @@ class basic_json
|
||||||
/*!
|
/*!
|
||||||
@brief add an object to an object if key does not exist
|
@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
|
Inserts a new element into a JSON object constructed in-place with the
|
||||||
@a args if there is no element with the key in the container. If 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
|
function is called on a JSON null value, an empty object is created before
|
||||||
appending the value created from @a args.
|
appending the value created from @a args.
|
||||||
|
|
||||||
|
@ -5221,8 +5194,8 @@ class basic_json
|
||||||
@throw std::domain_error if @a pos is not an iterator of *this; example:
|
@throw std::domain_error if @a pos is not an iterator of *this; example:
|
||||||
`"iterator does not fit current value"`
|
`"iterator does not fit current value"`
|
||||||
|
|
||||||
@complexity Constant plus linear in the distance between pos and end of the
|
@complexity Constant plus linear in the distance between pos and end of
|
||||||
container.
|
the container.
|
||||||
|
|
||||||
@liveexample{The example shows how `insert()` is used.,insert}
|
@liveexample{The example shows how `insert()` is used.,insert}
|
||||||
|
|
||||||
|
@ -5244,10 +5217,8 @@ class basic_json
|
||||||
result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, val);
|
result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, val);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
throw std::domain_error("cannot use insert() with " + type_name());
|
||||||
throw std::domain_error("cannot use insert() with " + type_name());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -5299,10 +5270,8 @@ class basic_json
|
||||||
result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, cnt, val);
|
result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, cnt, val);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
throw std::domain_error("cannot use insert() with " + type_name());
|
||||||
throw std::domain_error("cannot use insert() with " + type_name());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -5452,8 +5421,8 @@ class basic_json
|
||||||
|
|
||||||
@param[in,out] other array to exchange the contents with
|
@param[in,out] other array to exchange the contents with
|
||||||
|
|
||||||
@throw std::domain_error when JSON value is not an array; example: `"cannot
|
@throw std::domain_error when JSON value is not an array; example:
|
||||||
use swap() with string"`
|
`"cannot use swap() with string"`
|
||||||
|
|
||||||
@complexity Constant.
|
@complexity Constant.
|
||||||
|
|
||||||
|
@ -6180,7 +6149,7 @@ class basic_json
|
||||||
{
|
{
|
||||||
// assertion to check that the iterator range is indeed contiguous,
|
// assertion to check that the iterator range is indeed contiguous,
|
||||||
// see http://stackoverflow.com/a/35008842/266378 for more discussion
|
// see http://stackoverflow.com/a/35008842/266378 for more discussion
|
||||||
assert(std::accumulate(first, last, std::make_pair<bool, int>(true, 0),
|
assert(std::accumulate(first, last, std::pair<bool, int>(true, 0),
|
||||||
[&first](std::pair<bool, int> res, decltype(*first) val)
|
[&first](std::pair<bool, int> res, decltype(*first) val)
|
||||||
{
|
{
|
||||||
res.first &= (val == *(std::next(std::addressof(*first), res.second++)));
|
res.first &= (val == *(std::next(std::addressof(*first), res.second++)));
|
||||||
|
@ -6385,7 +6354,7 @@ class basic_json
|
||||||
}
|
}
|
||||||
|
|
||||||
T result;
|
T result;
|
||||||
uint8_t* ptr = reinterpret_cast<uint8_t*>(&result);
|
auto* ptr = reinterpret_cast<uint8_t*>(&result);
|
||||||
for (size_t i = 0; i < sizeof(T); ++i)
|
for (size_t i = 0; i < sizeof(T); ++i)
|
||||||
{
|
{
|
||||||
*ptr++ = vec[current_index + sizeof(T) - i];
|
*ptr++ = vec[current_index + sizeof(T) - i];
|
||||||
|
@ -6426,8 +6395,9 @@ class basic_json
|
||||||
if (j.m_value.number_integer >= 0)
|
if (j.m_value.number_integer >= 0)
|
||||||
{
|
{
|
||||||
// MessagePack does not differentiate between positive
|
// MessagePack does not differentiate between positive
|
||||||
// signed integers and unsigned integers. Therefore, we used
|
// signed integers and unsigned integers. Therefore, we
|
||||||
// the code from the value_t::number_unsigned case here.
|
// used the code from the value_t::number_unsigned case
|
||||||
|
// here.
|
||||||
if (j.m_value.number_unsigned < 128)
|
if (j.m_value.number_unsigned < 128)
|
||||||
{
|
{
|
||||||
// positive fixnum
|
// positive fixnum
|
||||||
|
@ -6531,7 +6501,7 @@ class basic_json
|
||||||
{
|
{
|
||||||
// float 64
|
// float 64
|
||||||
v.push_back(0xcb);
|
v.push_back(0xcb);
|
||||||
const uint8_t* helper = reinterpret_cast<const uint8_t*>(&(j.m_value.number_float));
|
const auto* helper = reinterpret_cast<const uint8_t*>(&(j.m_value.number_float));
|
||||||
for (size_t i = 0; i < 8; ++i)
|
for (size_t i = 0; i < 8; ++i)
|
||||||
{
|
{
|
||||||
v.push_back(helper[7 - i]);
|
v.push_back(helper[7 - i]);
|
||||||
|
@ -6702,8 +6672,8 @@ class basic_json
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// The conversions below encode the sign in the first byte,
|
// The conversions below encode the sign in the first
|
||||||
// and the value is converted to a positive number.
|
// byte, and the value is converted to a positive number.
|
||||||
const auto positive_number = -1 - j.m_value.number_integer;
|
const auto positive_number = -1 - j.m_value.number_integer;
|
||||||
if (j.m_value.number_integer >= -24)
|
if (j.m_value.number_integer >= -24)
|
||||||
{
|
{
|
||||||
|
@ -6774,7 +6744,7 @@ class basic_json
|
||||||
{
|
{
|
||||||
// Double-Precision Float
|
// Double-Precision Float
|
||||||
v.push_back(0xfb);
|
v.push_back(0xfb);
|
||||||
const uint8_t* helper = reinterpret_cast<const uint8_t*>(&(j.m_value.number_float));
|
const auto* helper = reinterpret_cast<const uint8_t*>(&(j.m_value.number_float));
|
||||||
for (size_t i = 0; i < 8; ++i)
|
for (size_t i = 0; i < 8; ++i)
|
||||||
{
|
{
|
||||||
v.push_back(helper[7 - i]);
|
v.push_back(helper[7 - i]);
|
||||||
|
@ -6908,12 +6878,12 @@ class basic_json
|
||||||
|
|
||||||
To secure the access to the byte vector during CBOR/MessagePack
|
To secure the access to the byte vector during CBOR/MessagePack
|
||||||
deserialization, bytes are copied from the vector into buffers. This
|
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
|
function checks if the number of bytes to copy (@a len) does not exceed
|
||||||
size @s size of the vector. Additionally, an @a offset is given from where
|
the size @s size of the vector. Additionally, an @a offset is given from
|
||||||
to start reading the bytes.
|
where to start reading the bytes.
|
||||||
|
|
||||||
This function checks whether reading the bytes is safe; that is, offset is a
|
This function checks whether reading the bytes is safe; that is, offset is
|
||||||
valid index in the vector, offset+len
|
a valid index in the vector, offset+len
|
||||||
|
|
||||||
@param[in] size size of the byte vector
|
@param[in] size size of the byte vector
|
||||||
@param[in] len number of bytes to read
|
@param[in] len number of bytes to read
|
||||||
|
@ -6974,7 +6944,7 @@ class basic_json
|
||||||
{
|
{
|
||||||
return v[current_idx];
|
return v[current_idx];
|
||||||
}
|
}
|
||||||
else if (v[current_idx] <= 0x8f) // fixmap
|
if (v[current_idx] <= 0x8f) // fixmap
|
||||||
{
|
{
|
||||||
basic_json result = value_t::object;
|
basic_json result = value_t::object;
|
||||||
const size_t len = v[current_idx] & 0x0f;
|
const size_t len = v[current_idx] & 0x0f;
|
||||||
|
@ -7030,11 +7000,10 @@ class basic_json
|
||||||
case 0xca: // float 32
|
case 0xca: // float 32
|
||||||
{
|
{
|
||||||
// copy bytes in reverse order into the double variable
|
// copy bytes in reverse order into the double variable
|
||||||
check_length(v.size(), sizeof(float), 1);
|
|
||||||
float res;
|
float res;
|
||||||
for (size_t byte = 0; byte < sizeof(float); ++byte)
|
for (size_t byte = 0; byte < sizeof(float); ++byte)
|
||||||
{
|
{
|
||||||
reinterpret_cast<uint8_t*>(&res)[sizeof(float) - byte - 1] = v[current_idx + 1 + byte];
|
reinterpret_cast<uint8_t*>(&res)[sizeof(float) - byte - 1] = v.at(current_idx + 1 + byte);
|
||||||
}
|
}
|
||||||
idx += sizeof(float); // skip content bytes
|
idx += sizeof(float); // skip content bytes
|
||||||
return res;
|
return res;
|
||||||
|
@ -7043,11 +7012,10 @@ class basic_json
|
||||||
case 0xcb: // float 64
|
case 0xcb: // float 64
|
||||||
{
|
{
|
||||||
// copy bytes in reverse order into the double variable
|
// copy bytes in reverse order into the double variable
|
||||||
check_length(v.size(), sizeof(double), 1);
|
|
||||||
double res;
|
double res;
|
||||||
for (size_t byte = 0; byte < sizeof(double); ++byte)
|
for (size_t byte = 0; byte < sizeof(double); ++byte)
|
||||||
{
|
{
|
||||||
reinterpret_cast<uint8_t*>(&res)[sizeof(double) - byte - 1] = v[current_idx + 1 + byte];
|
reinterpret_cast<uint8_t*>(&res)[sizeof(double) - byte - 1] = v.at(current_idx + 1 + byte);
|
||||||
}
|
}
|
||||||
idx += sizeof(double); // skip content bytes
|
idx += sizeof(double); // skip content bytes
|
||||||
return res;
|
return res;
|
||||||
|
@ -7609,7 +7577,6 @@ class basic_json
|
||||||
|
|
||||||
case 0xf9: // Half-Precision Float (two-byte IEEE 754)
|
case 0xf9: // Half-Precision Float (two-byte IEEE 754)
|
||||||
{
|
{
|
||||||
check_length(v.size(), 2, 1);
|
|
||||||
idx += 2; // skip two content bytes
|
idx += 2; // skip two content bytes
|
||||||
|
|
||||||
// code from RFC 7049, Appendix D, Figure 3:
|
// code from RFC 7049, Appendix D, Figure 3:
|
||||||
|
@ -7619,7 +7586,7 @@ class basic_json
|
||||||
// include at least decoding support for them even without such
|
// include at least decoding support for them even without such
|
||||||
// support. An example of a small decoder for half-precision
|
// support. An example of a small decoder for half-precision
|
||||||
// floating-point numbers in the C language is shown in Fig. 3.
|
// 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 half = (v.at(current_idx + 1) << 8) + v.at(current_idx + 2);
|
||||||
const int exp = (half >> 10) & 0x1f;
|
const int exp = (half >> 10) & 0x1f;
|
||||||
const int mant = half & 0x3ff;
|
const int mant = half & 0x3ff;
|
||||||
double val;
|
double val;
|
||||||
|
@ -7635,17 +7602,16 @@ class basic_json
|
||||||
{
|
{
|
||||||
val = mant == 0 ? INFINITY : NAN;
|
val = mant == 0 ? INFINITY : NAN;
|
||||||
}
|
}
|
||||||
return half & 0x8000 ? -val : val;
|
return (half & 0x8000) != 0 ? -val : val;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 0xfa: // Single-Precision Float (four-byte IEEE 754)
|
case 0xfa: // Single-Precision Float (four-byte IEEE 754)
|
||||||
{
|
{
|
||||||
// copy bytes in reverse order into the float variable
|
// copy bytes in reverse order into the float variable
|
||||||
check_length(v.size(), sizeof(float), 1);
|
|
||||||
float res;
|
float res;
|
||||||
for (size_t byte = 0; byte < sizeof(float); ++byte)
|
for (size_t byte = 0; byte < sizeof(float); ++byte)
|
||||||
{
|
{
|
||||||
reinterpret_cast<uint8_t*>(&res)[sizeof(float) - byte - 1] = v[current_idx + 1 + byte];
|
reinterpret_cast<uint8_t*>(&res)[sizeof(float) - byte - 1] = v.at(current_idx + 1 + byte);
|
||||||
}
|
}
|
||||||
idx += sizeof(float); // skip content bytes
|
idx += sizeof(float); // skip content bytes
|
||||||
return res;
|
return res;
|
||||||
|
@ -7653,12 +7619,11 @@ class basic_json
|
||||||
|
|
||||||
case 0xfb: // Double-Precision Float (eight-byte IEEE 754)
|
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
|
// copy bytes in reverse order into the double variable
|
||||||
double res;
|
double res;
|
||||||
for (size_t byte = 0; byte < sizeof(double); ++byte)
|
for (size_t byte = 0; byte < sizeof(double); ++byte)
|
||||||
{
|
{
|
||||||
reinterpret_cast<uint8_t*>(&res)[sizeof(double) - byte - 1] = v[current_idx + 1 + byte];
|
reinterpret_cast<uint8_t*>(&res)[sizeof(double) - byte - 1] = v.at(current_idx + 1 + byte);
|
||||||
}
|
}
|
||||||
idx += sizeof(double); // skip content bytes
|
idx += sizeof(double); // skip content bytes
|
||||||
return res;
|
return res;
|
||||||
|
@ -7858,10 +7823,8 @@ class basic_json
|
||||||
// from c (1 byte) to \uxxxx (6 bytes)
|
// from c (1 byte) to \uxxxx (6 bytes)
|
||||||
return res + 5;
|
return res + 5;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
return res;
|
||||||
return res;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -8567,10 +8530,8 @@ class basic_json
|
||||||
{
|
{
|
||||||
return *m_object;
|
return *m_object;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
throw std::out_of_range("cannot get value");
|
||||||
throw std::out_of_range("cannot get value");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8603,10 +8564,8 @@ class basic_json
|
||||||
{
|
{
|
||||||
return m_object;
|
return m_object;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
throw std::out_of_range("cannot get value");
|
||||||
throw std::out_of_range("cannot get value");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8919,10 +8878,8 @@ class basic_json
|
||||||
{
|
{
|
||||||
return *m_object;
|
return *m_object;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
throw std::out_of_range("cannot get value");
|
||||||
throw std::out_of_range("cannot get value");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8939,10 +8896,8 @@ class basic_json
|
||||||
{
|
{
|
||||||
return m_it.object_iterator->first;
|
return m_it.object_iterator->first;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
throw std::domain_error("cannot use key() for non-object iterators");
|
||||||
throw std::domain_error("cannot use key() for non-object iterators");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -10267,7 +10222,7 @@ basic_json_parser_66:
|
||||||
assert(m_marker == nullptr or m_marker <= m_limit);
|
assert(m_marker == nullptr or m_marker <= m_limit);
|
||||||
|
|
||||||
// number of processed characters (p)
|
// number of processed characters (p)
|
||||||
const size_t num_processed_chars = static_cast<size_t>(m_start - m_content);
|
const auto num_processed_chars = static_cast<size_t>(m_start - m_content);
|
||||||
// offset for m_marker wrt. to m_start
|
// offset for m_marker wrt. to m_start
|
||||||
const auto offset_marker = (m_marker == nullptr) ? 0 : m_marker - m_start;
|
const auto offset_marker = (m_marker == nullptr) ? 0 : m_marker - m_start;
|
||||||
// number of unprocessed characters (u)
|
// number of unprocessed characters (u)
|
||||||
|
@ -10659,7 +10614,7 @@ basic_json_parser_66:
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// parse with strtod
|
// parse with strtod
|
||||||
result.m_value.number_float = str_to_float_t(static_cast<number_float_t*>(nullptr), NULL);
|
result.m_value.number_float = str_to_float_t(static_cast<number_float_t*>(nullptr), nullptr);
|
||||||
|
|
||||||
// replace infinity and NAN by null
|
// replace infinity and NAN by null
|
||||||
if (not std::isfinite(result.m_value.number_float))
|
if (not std::isfinite(result.m_value.number_float))
|
||||||
|
@ -11394,7 +11349,7 @@ basic_json_parser_66:
|
||||||
// - start: position after the previous slash
|
// - start: position after the previous slash
|
||||||
for (
|
for (
|
||||||
// search for the first slash after the first character
|
// search for the first slash after the first character
|
||||||
size_t slash = reference_string.find_first_of("/", 1),
|
size_t slash = reference_string.find_first_of('/', 1),
|
||||||
// set the beginning of the first reference token
|
// set the beginning of the first reference token
|
||||||
start = 1;
|
start = 1;
|
||||||
// we can stop if start == string::npos+1 = 0
|
// we can stop if start == string::npos+1 = 0
|
||||||
|
@ -11403,16 +11358,16 @@ basic_json_parser_66:
|
||||||
// (will eventually be 0 if slash == std::string::npos)
|
// (will eventually be 0 if slash == std::string::npos)
|
||||||
start = slash + 1,
|
start = slash + 1,
|
||||||
// find next slash
|
// find next slash
|
||||||
slash = reference_string.find_first_of("/", start))
|
slash = reference_string.find_first_of('/', start))
|
||||||
{
|
{
|
||||||
// use the text between the beginning of the reference token
|
// use the text between the beginning of the reference token
|
||||||
// (start) and the last slash (slash).
|
// (start) and the last slash (slash).
|
||||||
auto reference_token = reference_string.substr(start, slash - start);
|
auto reference_token = reference_string.substr(start, slash - start);
|
||||||
|
|
||||||
// check reference tokens are properly escaped
|
// check reference tokens are properly escaped
|
||||||
for (size_t pos = reference_token.find_first_of("~");
|
for (size_t pos = reference_token.find_first_of('~');
|
||||||
pos != std::string::npos;
|
pos != std::string::npos;
|
||||||
pos = reference_token.find_first_of("~", pos + 1))
|
pos = reference_token.find_first_of('~', pos + 1))
|
||||||
{
|
{
|
||||||
assert(reference_token[pos] == '~');
|
assert(reference_token[pos] == '~');
|
||||||
|
|
||||||
|
@ -12246,7 +12201,7 @@ uses the standard template types.
|
||||||
@since version 1.0.0
|
@since version 1.0.0
|
||||||
*/
|
*/
|
||||||
using json = basic_json<>;
|
using json = basic_json<>;
|
||||||
}
|
} // namespace nlohmann
|
||||||
|
|
||||||
|
|
||||||
///////////////////////
|
///////////////////////
|
||||||
|
@ -12287,7 +12242,7 @@ struct hash<nlohmann::json>
|
||||||
return h(j.dump());
|
return h(j.dump());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
} // namespace std
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@brief user-defined string literal for JSON values
|
@brief user-defined string literal for JSON values
|
||||||
|
|
|
@ -58,13 +58,11 @@ SOFTWARE.
|
||||||
|
|
||||||
// exclude unsupported compilers
|
// exclude unsupported compilers
|
||||||
#if defined(__clang__)
|
#if defined(__clang__)
|
||||||
#define CLANG_VERSION (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__)
|
#if (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) < 30400
|
||||||
#if CLANG_VERSION < 30400
|
|
||||||
#error "unsupported Clang version - see https://github.com/nlohmann/json#supported-compilers"
|
#error "unsupported Clang version - see https://github.com/nlohmann/json#supported-compilers"
|
||||||
#endif
|
#endif
|
||||||
#elif defined(__GNUC__)
|
#elif defined(__GNUC__)
|
||||||
#define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
|
#if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40900
|
||||||
#if GCC_VERSION < 40900
|
|
||||||
#error "unsupported GCC version - see https://github.com/nlohmann/json#supported-compilers"
|
#error "unsupported GCC version - see https://github.com/nlohmann/json#supported-compilers"
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
@ -128,7 +126,7 @@ struct has_mapped_type
|
||||||
std::is_integral<decltype(detect(std::declval<T>()))>::value;
|
std::is_integral<decltype(detect(std::declval<T>()))>::value;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
} // namespace
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@brief a class to store JSON values
|
@brief a class to store JSON values
|
||||||
|
@ -153,7 +151,8 @@ default)
|
||||||
@requirement The class satisfies the following concept requirements:
|
@requirement The class satisfies the following concept requirements:
|
||||||
- Basic
|
- Basic
|
||||||
- [DefaultConstructible](http://en.cppreference.com/w/cpp/concept/DefaultConstructible):
|
- [DefaultConstructible](http://en.cppreference.com/w/cpp/concept/DefaultConstructible):
|
||||||
JSON values can be default constructed. The result will be a JSON null value.
|
JSON values can be default constructed. The result will be a JSON null
|
||||||
|
value.
|
||||||
- [MoveConstructible](http://en.cppreference.com/w/cpp/concept/MoveConstructible):
|
- [MoveConstructible](http://en.cppreference.com/w/cpp/concept/MoveConstructible):
|
||||||
A JSON value can be constructed from an rvalue argument.
|
A JSON value can be constructed from an rvalue argument.
|
||||||
- [CopyConstructible](http://en.cppreference.com/w/cpp/concept/CopyConstructible):
|
- [CopyConstructible](http://en.cppreference.com/w/cpp/concept/CopyConstructible):
|
||||||
|
@ -168,8 +167,8 @@ default)
|
||||||
- [StandardLayoutType](http://en.cppreference.com/w/cpp/concept/StandardLayoutType):
|
- [StandardLayoutType](http://en.cppreference.com/w/cpp/concept/StandardLayoutType):
|
||||||
JSON values have
|
JSON values have
|
||||||
[standard layout](http://en.cppreference.com/w/cpp/language/data_members#Standard_layout):
|
[standard layout](http://en.cppreference.com/w/cpp/language/data_members#Standard_layout):
|
||||||
All non-static data members are private and standard layout types, the class
|
All non-static data members are private and standard layout types, the
|
||||||
has no virtual functions or (virtual) base classes.
|
class has no virtual functions or (virtual) base classes.
|
||||||
- Library-wide
|
- Library-wide
|
||||||
- [EqualityComparable](http://en.cppreference.com/w/cpp/concept/EqualityComparable):
|
- [EqualityComparable](http://en.cppreference.com/w/cpp/concept/EqualityComparable):
|
||||||
JSON values can be compared with `==`, see @ref
|
JSON values can be compared with `==`, see @ref
|
||||||
|
@ -507,6 +506,12 @@ class basic_json
|
||||||
std::string
|
std::string
|
||||||
@endcode
|
@endcode
|
||||||
|
|
||||||
|
#### Encoding
|
||||||
|
|
||||||
|
Strings are stored in UTF-8 encoding. Therefore, functions like
|
||||||
|
`std::string::size()` or `std::string::length()` return the number of
|
||||||
|
bytes in the string rather than the number of characters or glyphs.
|
||||||
|
|
||||||
#### String comparison
|
#### String comparison
|
||||||
|
|
||||||
[RFC 7159](http://rfc7159.net/rfc7159) states:
|
[RFC 7159](http://rfc7159.net/rfc7159) states:
|
||||||
|
@ -825,7 +830,7 @@ class basic_json
|
||||||
};
|
};
|
||||||
std::unique_ptr<T, decltype(deleter)> object(alloc.allocate(1), deleter);
|
std::unique_ptr<T, decltype(deleter)> object(alloc.allocate(1), deleter);
|
||||||
alloc.construct(object.get(), std::forward<Args>(args)...);
|
alloc.construct(object.get(), std::forward<Args>(args)...);
|
||||||
assert(object.get() != nullptr);
|
assert(object != nullptr);
|
||||||
return object.release();
|
return object.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1952,13 +1957,15 @@ class basic_json
|
||||||
|
|
||||||
case value_t::object:
|
case value_t::object:
|
||||||
{
|
{
|
||||||
m_value.object = create<object_t>(first.m_it.object_iterator, last.m_it.object_iterator);
|
m_value.object = create<object_t>(first.m_it.object_iterator,
|
||||||
|
last.m_it.object_iterator);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case value_t::array:
|
case value_t::array:
|
||||||
{
|
{
|
||||||
m_value.array = create<array_t>(first.m_it.array_iterator, last.m_it.array_iterator);
|
m_value.array = create<array_t>(first.m_it.array_iterator,
|
||||||
|
last.m_it.array_iterator);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2641,29 +2648,25 @@ class basic_json
|
||||||
template<class T, typename std::enable_if<
|
template<class T, typename std::enable_if<
|
||||||
std::is_convertible<typename object_t::key_type, typename T::key_type>::value and
|
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>
|
std::is_convertible<basic_json_t, typename T::mapped_type>::value, int>::type = 0>
|
||||||
T get_impl(T*) const
|
T get_impl(T* /*unused*/) const
|
||||||
{
|
{
|
||||||
if (is_object())
|
if (is_object())
|
||||||
{
|
{
|
||||||
return T(m_value.object->begin(), m_value.object->end());
|
return T(m_value.object->begin(), m_value.object->end());
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
throw std::domain_error("type must be object, but is " + type_name());
|
||||||
throw std::domain_error("type must be object, but is " + type_name());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// get an object (explicit)
|
/// get an object (explicit)
|
||||||
object_t get_impl(object_t*) const
|
object_t get_impl(object_t* /*unused*/) const
|
||||||
{
|
{
|
||||||
if (is_object())
|
if (is_object())
|
||||||
{
|
{
|
||||||
return *(m_value.object);
|
return *(m_value.object);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
throw std::domain_error("type must be object, but is " + type_name());
|
||||||
throw std::domain_error("type must be object, but is " + type_name());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// get an array (explicit)
|
/// get an array (explicit)
|
||||||
|
@ -2673,7 +2676,7 @@ class basic_json
|
||||||
not std::is_arithmetic<T>::value and
|
not std::is_arithmetic<T>::value and
|
||||||
not std::is_convertible<std::string, T>::value and
|
not std::is_convertible<std::string, T>::value and
|
||||||
not has_mapped_type<T>::value, int>::type = 0>
|
not has_mapped_type<T>::value, int>::type = 0>
|
||||||
T get_impl(T*) const
|
T get_impl(T* /*unused*/) const
|
||||||
{
|
{
|
||||||
if (is_array())
|
if (is_array())
|
||||||
{
|
{
|
||||||
|
@ -2685,17 +2688,15 @@ class basic_json
|
||||||
});
|
});
|
||||||
return to_vector;
|
return to_vector;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
throw std::domain_error("type must be array, but is " + type_name());
|
||||||
throw std::domain_error("type must be array, but is " + type_name());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// get an array (explicit)
|
/// get an array (explicit)
|
||||||
template<class T, typename std::enable_if<
|
template<class T, typename std::enable_if<
|
||||||
std::is_convertible<basic_json_t, T>::value and
|
std::is_convertible<basic_json_t, T>::value and
|
||||||
not std::is_same<basic_json_t, T>::value, int>::type = 0>
|
not std::is_same<basic_json_t, T>::value, int>::type = 0>
|
||||||
std::vector<T> get_impl(std::vector<T>*) const
|
std::vector<T> get_impl(std::vector<T>* /*unused*/) const
|
||||||
{
|
{
|
||||||
if (is_array())
|
if (is_array())
|
||||||
{
|
{
|
||||||
|
@ -2708,60 +2709,52 @@ class basic_json
|
||||||
});
|
});
|
||||||
return to_vector;
|
return to_vector;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
throw std::domain_error("type must be array, but is " + type_name());
|
||||||
throw std::domain_error("type must be array, but is " + type_name());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// get an array (explicit)
|
/// get an array (explicit)
|
||||||
template<class T, typename std::enable_if<
|
template<class T, typename std::enable_if<
|
||||||
std::is_same<basic_json, typename T::value_type>::value and
|
std::is_same<basic_json, typename T::value_type>::value and
|
||||||
not has_mapped_type<T>::value, int>::type = 0>
|
not has_mapped_type<T>::value, int>::type = 0>
|
||||||
T get_impl(T*) const
|
T get_impl(T* /*unused*/) const
|
||||||
{
|
{
|
||||||
if (is_array())
|
if (is_array())
|
||||||
{
|
{
|
||||||
return T(m_value.array->begin(), m_value.array->end());
|
return T(m_value.array->begin(), m_value.array->end());
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
throw std::domain_error("type must be array, but is " + type_name());
|
||||||
throw std::domain_error("type must be array, but is " + type_name());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// get an array (explicit)
|
/// get an array (explicit)
|
||||||
array_t get_impl(array_t*) const
|
array_t get_impl(array_t* /*unused*/) const
|
||||||
{
|
{
|
||||||
if (is_array())
|
if (is_array())
|
||||||
{
|
{
|
||||||
return *(m_value.array);
|
return *(m_value.array);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
throw std::domain_error("type must be array, but is " + type_name());
|
||||||
throw std::domain_error("type must be array, but is " + type_name());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// get a string (explicit)
|
/// get a string (explicit)
|
||||||
template<typename T, typename std::enable_if<
|
template<typename T, typename std::enable_if<
|
||||||
std::is_convertible<string_t, T>::value, int>::type = 0>
|
std::is_convertible<string_t, T>::value, int>::type = 0>
|
||||||
T get_impl(T*) const
|
T get_impl(T* /*unused*/) const
|
||||||
{
|
{
|
||||||
if (is_string())
|
if (is_string())
|
||||||
{
|
{
|
||||||
return *m_value.string;
|
return *m_value.string;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
throw std::domain_error("type must be string, but is " + type_name());
|
||||||
throw std::domain_error("type must be string, but is " + type_name());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// get a number (explicit)
|
/// get a number (explicit)
|
||||||
template<typename T, typename std::enable_if<
|
template<typename T, typename std::enable_if<
|
||||||
std::is_arithmetic<T>::value, int>::type = 0>
|
std::is_arithmetic<T>::value, int>::type = 0>
|
||||||
T get_impl(T*) const
|
T get_impl(T* /*unused*/) const
|
||||||
{
|
{
|
||||||
switch (m_type)
|
switch (m_type)
|
||||||
{
|
{
|
||||||
|
@ -2788,7 +2781,7 @@ class basic_json
|
||||||
}
|
}
|
||||||
|
|
||||||
/// get a boolean (explicit)
|
/// get a boolean (explicit)
|
||||||
constexpr boolean_t get_impl(boolean_t*) const
|
constexpr boolean_t get_impl(boolean_t* /*unused*/) const
|
||||||
{
|
{
|
||||||
return is_boolean()
|
return is_boolean()
|
||||||
? m_value.boolean
|
? m_value.boolean
|
||||||
|
@ -2796,85 +2789,85 @@ class basic_json
|
||||||
}
|
}
|
||||||
|
|
||||||
/// get a pointer to the value (object)
|
/// get a pointer to the value (object)
|
||||||
object_t* get_impl_ptr(object_t*) noexcept
|
object_t* get_impl_ptr(object_t* /*unused*/) noexcept
|
||||||
{
|
{
|
||||||
return is_object() ? m_value.object : nullptr;
|
return is_object() ? m_value.object : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// get a pointer to the value (object)
|
/// get a pointer to the value (object)
|
||||||
constexpr const object_t* get_impl_ptr(const object_t*) const noexcept
|
constexpr const object_t* get_impl_ptr(const object_t* /*unused*/) const noexcept
|
||||||
{
|
{
|
||||||
return is_object() ? m_value.object : nullptr;
|
return is_object() ? m_value.object : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// get a pointer to the value (array)
|
/// get a pointer to the value (array)
|
||||||
array_t* get_impl_ptr(array_t*) noexcept
|
array_t* get_impl_ptr(array_t* /*unused*/) noexcept
|
||||||
{
|
{
|
||||||
return is_array() ? m_value.array : nullptr;
|
return is_array() ? m_value.array : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// get a pointer to the value (array)
|
/// get a pointer to the value (array)
|
||||||
constexpr const array_t* get_impl_ptr(const array_t*) const noexcept
|
constexpr const array_t* get_impl_ptr(const array_t* /*unused*/) const noexcept
|
||||||
{
|
{
|
||||||
return is_array() ? m_value.array : nullptr;
|
return is_array() ? m_value.array : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// get a pointer to the value (string)
|
/// get a pointer to the value (string)
|
||||||
string_t* get_impl_ptr(string_t*) noexcept
|
string_t* get_impl_ptr(string_t* /*unused*/) noexcept
|
||||||
{
|
{
|
||||||
return is_string() ? m_value.string : nullptr;
|
return is_string() ? m_value.string : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// get a pointer to the value (string)
|
/// get a pointer to the value (string)
|
||||||
constexpr const string_t* get_impl_ptr(const string_t*) const noexcept
|
constexpr const string_t* get_impl_ptr(const string_t* /*unused*/) const noexcept
|
||||||
{
|
{
|
||||||
return is_string() ? m_value.string : nullptr;
|
return is_string() ? m_value.string : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// get a pointer to the value (boolean)
|
/// get a pointer to the value (boolean)
|
||||||
boolean_t* get_impl_ptr(boolean_t*) noexcept
|
boolean_t* get_impl_ptr(boolean_t* /*unused*/) noexcept
|
||||||
{
|
{
|
||||||
return is_boolean() ? &m_value.boolean : nullptr;
|
return is_boolean() ? &m_value.boolean : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// get a pointer to the value (boolean)
|
/// get a pointer to the value (boolean)
|
||||||
constexpr const boolean_t* get_impl_ptr(const boolean_t*) const noexcept
|
constexpr const boolean_t* get_impl_ptr(const boolean_t* /*unused*/) const noexcept
|
||||||
{
|
{
|
||||||
return is_boolean() ? &m_value.boolean : nullptr;
|
return is_boolean() ? &m_value.boolean : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// get a pointer to the value (integer number)
|
/// get a pointer to the value (integer number)
|
||||||
number_integer_t* get_impl_ptr(number_integer_t*) noexcept
|
number_integer_t* get_impl_ptr(number_integer_t* /*unused*/) noexcept
|
||||||
{
|
{
|
||||||
return is_number_integer() ? &m_value.number_integer : nullptr;
|
return is_number_integer() ? &m_value.number_integer : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// get a pointer to the value (integer number)
|
/// get a pointer to the value (integer number)
|
||||||
constexpr const number_integer_t* get_impl_ptr(const number_integer_t*) const noexcept
|
constexpr const number_integer_t* get_impl_ptr(const number_integer_t* /*unused*/) const noexcept
|
||||||
{
|
{
|
||||||
return is_number_integer() ? &m_value.number_integer : nullptr;
|
return is_number_integer() ? &m_value.number_integer : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// get a pointer to the value (unsigned number)
|
/// get a pointer to the value (unsigned number)
|
||||||
number_unsigned_t* get_impl_ptr(number_unsigned_t*) noexcept
|
number_unsigned_t* get_impl_ptr(number_unsigned_t* /*unused*/) noexcept
|
||||||
{
|
{
|
||||||
return is_number_unsigned() ? &m_value.number_unsigned : nullptr;
|
return is_number_unsigned() ? &m_value.number_unsigned : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// get a pointer to the value (unsigned number)
|
/// get a pointer to the value (unsigned number)
|
||||||
constexpr const number_unsigned_t* get_impl_ptr(const number_unsigned_t*) const noexcept
|
constexpr const number_unsigned_t* get_impl_ptr(const number_unsigned_t* /*unused*/) const noexcept
|
||||||
{
|
{
|
||||||
return is_number_unsigned() ? &m_value.number_unsigned : nullptr;
|
return is_number_unsigned() ? &m_value.number_unsigned : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// get a pointer to the value (floating-point number)
|
/// get a pointer to the value (floating-point number)
|
||||||
number_float_t* get_impl_ptr(number_float_t*) noexcept
|
number_float_t* get_impl_ptr(number_float_t* /*unused*/) noexcept
|
||||||
{
|
{
|
||||||
return is_number_float() ? &m_value.number_float : nullptr;
|
return is_number_float() ? &m_value.number_float : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// get a pointer to the value (floating-point number)
|
/// get a pointer to the value (floating-point number)
|
||||||
constexpr const number_float_t* get_impl_ptr(const number_float_t*) const noexcept
|
constexpr const number_float_t* get_impl_ptr(const number_float_t* /*unused*/) const noexcept
|
||||||
{
|
{
|
||||||
return is_number_float() ? &m_value.number_float : nullptr;
|
return is_number_float() ? &m_value.number_float : nullptr;
|
||||||
}
|
}
|
||||||
|
@ -2903,11 +2896,9 @@ class basic_json
|
||||||
{
|
{
|
||||||
return *ptr;
|
return *ptr;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
throw std::domain_error("incompatible ReferenceType for get_ref, actual type is " +
|
||||||
throw std::domain_error("incompatible ReferenceType for get_ref, actual type is " +
|
obj.type_name());
|
||||||
obj.type_name());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -3158,7 +3149,7 @@ class basic_json
|
||||||
template < typename ValueType, typename std::enable_if <
|
template < typename ValueType, typename std::enable_if <
|
||||||
not std::is_pointer<ValueType>::value and
|
not std::is_pointer<ValueType>::value and
|
||||||
not std::is_same<ValueType, typename string_t::value_type>::value
|
not std::is_same<ValueType, typename string_t::value_type>::value
|
||||||
#ifndef _MSC_VER // Fix for issue #167 operator<< abiguity under VS2015
|
#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
|
and not std::is_same<ValueType, std::initializer_list<typename string_t::value_type>>::value
|
||||||
#endif
|
#endif
|
||||||
, int >::type = 0 >
|
, int >::type = 0 >
|
||||||
|
@ -3407,10 +3398,8 @@ class basic_json
|
||||||
|
|
||||||
return m_value.array->operator[](idx);
|
return m_value.array->operator[](idx);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
throw std::domain_error("cannot use operator[] with " + type_name());
|
||||||
throw std::domain_error("cannot use operator[] with " + type_name());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -3439,10 +3428,8 @@ class basic_json
|
||||||
{
|
{
|
||||||
return m_value.array->operator[](idx);
|
return m_value.array->operator[](idx);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
throw std::domain_error("cannot use operator[] with " + type_name());
|
||||||
throw std::domain_error("cannot use operator[] with " + type_name());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -3487,10 +3474,8 @@ class basic_json
|
||||||
{
|
{
|
||||||
return m_value.object->operator[](key);
|
return m_value.object->operator[](key);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
throw std::domain_error("cannot use operator[] with " + type_name());
|
||||||
throw std::domain_error("cannot use operator[] with " + type_name());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -3531,10 +3516,8 @@ class basic_json
|
||||||
assert(m_value.object->find(key) != m_value.object->end());
|
assert(m_value.object->find(key) != m_value.object->end());
|
||||||
return m_value.object->find(key)->second;
|
return m_value.object->find(key)->second;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
throw std::domain_error("cannot use operator[] with " + type_name());
|
||||||
throw std::domain_error("cannot use operator[] with " + type_name());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -3648,10 +3631,8 @@ class basic_json
|
||||||
{
|
{
|
||||||
return m_value.object->operator[](key);
|
return m_value.object->operator[](key);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
throw std::domain_error("cannot use operator[] with " + type_name());
|
||||||
throw std::domain_error("cannot use operator[] with " + type_name());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -3693,10 +3674,8 @@ class basic_json
|
||||||
assert(m_value.object->find(key) != m_value.object->end());
|
assert(m_value.object->find(key) != m_value.object->end());
|
||||||
return m_value.object->find(key)->second;
|
return m_value.object->find(key)->second;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
throw std::domain_error("cannot use operator[] with " + type_name());
|
||||||
throw std::domain_error("cannot use operator[] with " + type_name());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -3760,10 +3739,8 @@ class basic_json
|
||||||
{
|
{
|
||||||
return *it;
|
return *it;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
return default_value;
|
||||||
return default_value;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -3838,10 +3815,8 @@ class basic_json
|
||||||
return default_value;
|
return default_value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
throw std::domain_error("cannot use value() with " + type_name());
|
||||||
throw std::domain_error("cannot use value() with " + type_name());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -4189,10 +4164,8 @@ class basic_json
|
||||||
{
|
{
|
||||||
return m_value.object->erase(key);
|
return m_value.object->erase(key);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
throw std::domain_error("cannot use erase() with " + type_name());
|
||||||
throw std::domain_error("cannot use erase() with " + type_name());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -5155,8 +5128,8 @@ class basic_json
|
||||||
/*!
|
/*!
|
||||||
@brief add an object to an object if key does not exist
|
@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
|
Inserts a new element into a JSON object constructed in-place with the
|
||||||
@a args if there is no element with the key in the container. If 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
|
function is called on a JSON null value, an empty object is created before
|
||||||
appending the value created from @a args.
|
appending the value created from @a args.
|
||||||
|
|
||||||
|
@ -5221,8 +5194,8 @@ class basic_json
|
||||||
@throw std::domain_error if @a pos is not an iterator of *this; example:
|
@throw std::domain_error if @a pos is not an iterator of *this; example:
|
||||||
`"iterator does not fit current value"`
|
`"iterator does not fit current value"`
|
||||||
|
|
||||||
@complexity Constant plus linear in the distance between pos and end of the
|
@complexity Constant plus linear in the distance between pos and end of
|
||||||
container.
|
the container.
|
||||||
|
|
||||||
@liveexample{The example shows how `insert()` is used.,insert}
|
@liveexample{The example shows how `insert()` is used.,insert}
|
||||||
|
|
||||||
|
@ -5244,10 +5217,8 @@ class basic_json
|
||||||
result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, val);
|
result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, val);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
throw std::domain_error("cannot use insert() with " + type_name());
|
||||||
throw std::domain_error("cannot use insert() with " + type_name());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -5299,10 +5270,8 @@ class basic_json
|
||||||
result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, cnt, val);
|
result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, cnt, val);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
throw std::domain_error("cannot use insert() with " + type_name());
|
||||||
throw std::domain_error("cannot use insert() with " + type_name());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -5452,8 +5421,8 @@ class basic_json
|
||||||
|
|
||||||
@param[in,out] other array to exchange the contents with
|
@param[in,out] other array to exchange the contents with
|
||||||
|
|
||||||
@throw std::domain_error when JSON value is not an array; example: `"cannot
|
@throw std::domain_error when JSON value is not an array; example:
|
||||||
use swap() with string"`
|
`"cannot use swap() with string"`
|
||||||
|
|
||||||
@complexity Constant.
|
@complexity Constant.
|
||||||
|
|
||||||
|
@ -6180,7 +6149,7 @@ class basic_json
|
||||||
{
|
{
|
||||||
// assertion to check that the iterator range is indeed contiguous,
|
// assertion to check that the iterator range is indeed contiguous,
|
||||||
// see http://stackoverflow.com/a/35008842/266378 for more discussion
|
// see http://stackoverflow.com/a/35008842/266378 for more discussion
|
||||||
assert(std::accumulate(first, last, std::make_pair<bool, int>(true, 0),
|
assert(std::accumulate(first, last, std::pair<bool, int>(true, 0),
|
||||||
[&first](std::pair<bool, int> res, decltype(*first) val)
|
[&first](std::pair<bool, int> res, decltype(*first) val)
|
||||||
{
|
{
|
||||||
res.first &= (val == *(std::next(std::addressof(*first), res.second++)));
|
res.first &= (val == *(std::next(std::addressof(*first), res.second++)));
|
||||||
|
@ -6385,7 +6354,7 @@ class basic_json
|
||||||
}
|
}
|
||||||
|
|
||||||
T result;
|
T result;
|
||||||
uint8_t* ptr = reinterpret_cast<uint8_t*>(&result);
|
auto* ptr = reinterpret_cast<uint8_t*>(&result);
|
||||||
for (size_t i = 0; i < sizeof(T); ++i)
|
for (size_t i = 0; i < sizeof(T); ++i)
|
||||||
{
|
{
|
||||||
*ptr++ = vec[current_index + sizeof(T) - i];
|
*ptr++ = vec[current_index + sizeof(T) - i];
|
||||||
|
@ -6426,8 +6395,9 @@ class basic_json
|
||||||
if (j.m_value.number_integer >= 0)
|
if (j.m_value.number_integer >= 0)
|
||||||
{
|
{
|
||||||
// MessagePack does not differentiate between positive
|
// MessagePack does not differentiate between positive
|
||||||
// signed integers and unsigned integers. Therefore, we used
|
// signed integers and unsigned integers. Therefore, we
|
||||||
// the code from the value_t::number_unsigned case here.
|
// used the code from the value_t::number_unsigned case
|
||||||
|
// here.
|
||||||
if (j.m_value.number_unsigned < 128)
|
if (j.m_value.number_unsigned < 128)
|
||||||
{
|
{
|
||||||
// positive fixnum
|
// positive fixnum
|
||||||
|
@ -6531,7 +6501,7 @@ class basic_json
|
||||||
{
|
{
|
||||||
// float 64
|
// float 64
|
||||||
v.push_back(0xcb);
|
v.push_back(0xcb);
|
||||||
const uint8_t* helper = reinterpret_cast<const uint8_t*>(&(j.m_value.number_float));
|
const auto* helper = reinterpret_cast<const uint8_t*>(&(j.m_value.number_float));
|
||||||
for (size_t i = 0; i < 8; ++i)
|
for (size_t i = 0; i < 8; ++i)
|
||||||
{
|
{
|
||||||
v.push_back(helper[7 - i]);
|
v.push_back(helper[7 - i]);
|
||||||
|
@ -6702,8 +6672,8 @@ class basic_json
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// The conversions below encode the sign in the first byte,
|
// The conversions below encode the sign in the first
|
||||||
// and the value is converted to a positive number.
|
// byte, and the value is converted to a positive number.
|
||||||
const auto positive_number = -1 - j.m_value.number_integer;
|
const auto positive_number = -1 - j.m_value.number_integer;
|
||||||
if (j.m_value.number_integer >= -24)
|
if (j.m_value.number_integer >= -24)
|
||||||
{
|
{
|
||||||
|
@ -6774,7 +6744,7 @@ class basic_json
|
||||||
{
|
{
|
||||||
// Double-Precision Float
|
// Double-Precision Float
|
||||||
v.push_back(0xfb);
|
v.push_back(0xfb);
|
||||||
const uint8_t* helper = reinterpret_cast<const uint8_t*>(&(j.m_value.number_float));
|
const auto* helper = reinterpret_cast<const uint8_t*>(&(j.m_value.number_float));
|
||||||
for (size_t i = 0; i < 8; ++i)
|
for (size_t i = 0; i < 8; ++i)
|
||||||
{
|
{
|
||||||
v.push_back(helper[7 - i]);
|
v.push_back(helper[7 - i]);
|
||||||
|
@ -6908,12 +6878,12 @@ class basic_json
|
||||||
|
|
||||||
To secure the access to the byte vector during CBOR/MessagePack
|
To secure the access to the byte vector during CBOR/MessagePack
|
||||||
deserialization, bytes are copied from the vector into buffers. This
|
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
|
function checks if the number of bytes to copy (@a len) does not exceed
|
||||||
size @s size of the vector. Additionally, an @a offset is given from where
|
the size @s size of the vector. Additionally, an @a offset is given from
|
||||||
to start reading the bytes.
|
where to start reading the bytes.
|
||||||
|
|
||||||
This function checks whether reading the bytes is safe; that is, offset is a
|
This function checks whether reading the bytes is safe; that is, offset is
|
||||||
valid index in the vector, offset+len
|
a valid index in the vector, offset+len
|
||||||
|
|
||||||
@param[in] size size of the byte vector
|
@param[in] size size of the byte vector
|
||||||
@param[in] len number of bytes to read
|
@param[in] len number of bytes to read
|
||||||
|
@ -6974,7 +6944,7 @@ class basic_json
|
||||||
{
|
{
|
||||||
return v[current_idx];
|
return v[current_idx];
|
||||||
}
|
}
|
||||||
else if (v[current_idx] <= 0x8f) // fixmap
|
if (v[current_idx] <= 0x8f) // fixmap
|
||||||
{
|
{
|
||||||
basic_json result = value_t::object;
|
basic_json result = value_t::object;
|
||||||
const size_t len = v[current_idx] & 0x0f;
|
const size_t len = v[current_idx] & 0x0f;
|
||||||
|
@ -7030,11 +7000,10 @@ class basic_json
|
||||||
case 0xca: // float 32
|
case 0xca: // float 32
|
||||||
{
|
{
|
||||||
// copy bytes in reverse order into the double variable
|
// copy bytes in reverse order into the double variable
|
||||||
check_length(v.size(), sizeof(float), 1);
|
|
||||||
float res;
|
float res;
|
||||||
for (size_t byte = 0; byte < sizeof(float); ++byte)
|
for (size_t byte = 0; byte < sizeof(float); ++byte)
|
||||||
{
|
{
|
||||||
reinterpret_cast<uint8_t*>(&res)[sizeof(float) - byte - 1] = v[current_idx + 1 + byte];
|
reinterpret_cast<uint8_t*>(&res)[sizeof(float) - byte - 1] = v.at(current_idx + 1 + byte);
|
||||||
}
|
}
|
||||||
idx += sizeof(float); // skip content bytes
|
idx += sizeof(float); // skip content bytes
|
||||||
return res;
|
return res;
|
||||||
|
@ -7043,11 +7012,10 @@ class basic_json
|
||||||
case 0xcb: // float 64
|
case 0xcb: // float 64
|
||||||
{
|
{
|
||||||
// copy bytes in reverse order into the double variable
|
// copy bytes in reverse order into the double variable
|
||||||
check_length(v.size(), sizeof(double), 1);
|
|
||||||
double res;
|
double res;
|
||||||
for (size_t byte = 0; byte < sizeof(double); ++byte)
|
for (size_t byte = 0; byte < sizeof(double); ++byte)
|
||||||
{
|
{
|
||||||
reinterpret_cast<uint8_t*>(&res)[sizeof(double) - byte - 1] = v[current_idx + 1 + byte];
|
reinterpret_cast<uint8_t*>(&res)[sizeof(double) - byte - 1] = v.at(current_idx + 1 + byte);
|
||||||
}
|
}
|
||||||
idx += sizeof(double); // skip content bytes
|
idx += sizeof(double); // skip content bytes
|
||||||
return res;
|
return res;
|
||||||
|
@ -7609,7 +7577,6 @@ class basic_json
|
||||||
|
|
||||||
case 0xf9: // Half-Precision Float (two-byte IEEE 754)
|
case 0xf9: // Half-Precision Float (two-byte IEEE 754)
|
||||||
{
|
{
|
||||||
check_length(v.size(), 2, 1);
|
|
||||||
idx += 2; // skip two content bytes
|
idx += 2; // skip two content bytes
|
||||||
|
|
||||||
// code from RFC 7049, Appendix D, Figure 3:
|
// code from RFC 7049, Appendix D, Figure 3:
|
||||||
|
@ -7619,7 +7586,7 @@ class basic_json
|
||||||
// include at least decoding support for them even without such
|
// include at least decoding support for them even without such
|
||||||
// support. An example of a small decoder for half-precision
|
// support. An example of a small decoder for half-precision
|
||||||
// floating-point numbers in the C language is shown in Fig. 3.
|
// 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 half = (v.at(current_idx + 1) << 8) + v.at(current_idx + 2);
|
||||||
const int exp = (half >> 10) & 0x1f;
|
const int exp = (half >> 10) & 0x1f;
|
||||||
const int mant = half & 0x3ff;
|
const int mant = half & 0x3ff;
|
||||||
double val;
|
double val;
|
||||||
|
@ -7635,17 +7602,16 @@ class basic_json
|
||||||
{
|
{
|
||||||
val = mant == 0 ? INFINITY : NAN;
|
val = mant == 0 ? INFINITY : NAN;
|
||||||
}
|
}
|
||||||
return half & 0x8000 ? -val : val;
|
return (half & 0x8000) != 0 ? -val : val;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 0xfa: // Single-Precision Float (four-byte IEEE 754)
|
case 0xfa: // Single-Precision Float (four-byte IEEE 754)
|
||||||
{
|
{
|
||||||
// copy bytes in reverse order into the float variable
|
// copy bytes in reverse order into the float variable
|
||||||
check_length(v.size(), sizeof(float), 1);
|
|
||||||
float res;
|
float res;
|
||||||
for (size_t byte = 0; byte < sizeof(float); ++byte)
|
for (size_t byte = 0; byte < sizeof(float); ++byte)
|
||||||
{
|
{
|
||||||
reinterpret_cast<uint8_t*>(&res)[sizeof(float) - byte - 1] = v[current_idx + 1 + byte];
|
reinterpret_cast<uint8_t*>(&res)[sizeof(float) - byte - 1] = v.at(current_idx + 1 + byte);
|
||||||
}
|
}
|
||||||
idx += sizeof(float); // skip content bytes
|
idx += sizeof(float); // skip content bytes
|
||||||
return res;
|
return res;
|
||||||
|
@ -7653,12 +7619,11 @@ class basic_json
|
||||||
|
|
||||||
case 0xfb: // Double-Precision Float (eight-byte IEEE 754)
|
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
|
// copy bytes in reverse order into the double variable
|
||||||
double res;
|
double res;
|
||||||
for (size_t byte = 0; byte < sizeof(double); ++byte)
|
for (size_t byte = 0; byte < sizeof(double); ++byte)
|
||||||
{
|
{
|
||||||
reinterpret_cast<uint8_t*>(&res)[sizeof(double) - byte - 1] = v[current_idx + 1 + byte];
|
reinterpret_cast<uint8_t*>(&res)[sizeof(double) - byte - 1] = v.at(current_idx + 1 + byte);
|
||||||
}
|
}
|
||||||
idx += sizeof(double); // skip content bytes
|
idx += sizeof(double); // skip content bytes
|
||||||
return res;
|
return res;
|
||||||
|
@ -7858,10 +7823,8 @@ class basic_json
|
||||||
// from c (1 byte) to \uxxxx (6 bytes)
|
// from c (1 byte) to \uxxxx (6 bytes)
|
||||||
return res + 5;
|
return res + 5;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
return res;
|
||||||
return res;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -8567,10 +8530,8 @@ class basic_json
|
||||||
{
|
{
|
||||||
return *m_object;
|
return *m_object;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
throw std::out_of_range("cannot get value");
|
||||||
throw std::out_of_range("cannot get value");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8603,10 +8564,8 @@ class basic_json
|
||||||
{
|
{
|
||||||
return m_object;
|
return m_object;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
throw std::out_of_range("cannot get value");
|
||||||
throw std::out_of_range("cannot get value");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8919,10 +8878,8 @@ class basic_json
|
||||||
{
|
{
|
||||||
return *m_object;
|
return *m_object;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
throw std::out_of_range("cannot get value");
|
||||||
throw std::out_of_range("cannot get value");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8939,10 +8896,8 @@ class basic_json
|
||||||
{
|
{
|
||||||
return m_it.object_iterator->first;
|
return m_it.object_iterator->first;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
throw std::domain_error("cannot use key() for non-object iterators");
|
||||||
throw std::domain_error("cannot use key() for non-object iterators");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -9417,7 +9372,7 @@ class basic_json
|
||||||
assert(m_marker == nullptr or m_marker <= m_limit);
|
assert(m_marker == nullptr or m_marker <= m_limit);
|
||||||
|
|
||||||
// number of processed characters (p)
|
// number of processed characters (p)
|
||||||
const size_t num_processed_chars = static_cast<size_t>(m_start - m_content);
|
const auto num_processed_chars = static_cast<size_t>(m_start - m_content);
|
||||||
// offset for m_marker wrt. to m_start
|
// offset for m_marker wrt. to m_start
|
||||||
const auto offset_marker = (m_marker == nullptr) ? 0 : m_marker - m_start;
|
const auto offset_marker = (m_marker == nullptr) ? 0 : m_marker - m_start;
|
||||||
// number of unprocessed characters (u)
|
// number of unprocessed characters (u)
|
||||||
|
@ -9809,7 +9764,7 @@ class basic_json
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// parse with strtod
|
// parse with strtod
|
||||||
result.m_value.number_float = str_to_float_t(static_cast<number_float_t*>(nullptr), NULL);
|
result.m_value.number_float = str_to_float_t(static_cast<number_float_t*>(nullptr), nullptr);
|
||||||
|
|
||||||
// replace infinity and NAN by null
|
// replace infinity and NAN by null
|
||||||
if (not std::isfinite(result.m_value.number_float))
|
if (not std::isfinite(result.m_value.number_float))
|
||||||
|
@ -10544,7 +10499,7 @@ class basic_json
|
||||||
// - start: position after the previous slash
|
// - start: position after the previous slash
|
||||||
for (
|
for (
|
||||||
// search for the first slash after the first character
|
// search for the first slash after the first character
|
||||||
size_t slash = reference_string.find_first_of("/", 1),
|
size_t slash = reference_string.find_first_of('/', 1),
|
||||||
// set the beginning of the first reference token
|
// set the beginning of the first reference token
|
||||||
start = 1;
|
start = 1;
|
||||||
// we can stop if start == string::npos+1 = 0
|
// we can stop if start == string::npos+1 = 0
|
||||||
|
@ -10553,16 +10508,16 @@ class basic_json
|
||||||
// (will eventually be 0 if slash == std::string::npos)
|
// (will eventually be 0 if slash == std::string::npos)
|
||||||
start = slash + 1,
|
start = slash + 1,
|
||||||
// find next slash
|
// find next slash
|
||||||
slash = reference_string.find_first_of("/", start))
|
slash = reference_string.find_first_of('/', start))
|
||||||
{
|
{
|
||||||
// use the text between the beginning of the reference token
|
// use the text between the beginning of the reference token
|
||||||
// (start) and the last slash (slash).
|
// (start) and the last slash (slash).
|
||||||
auto reference_token = reference_string.substr(start, slash - start);
|
auto reference_token = reference_string.substr(start, slash - start);
|
||||||
|
|
||||||
// check reference tokens are properly escaped
|
// check reference tokens are properly escaped
|
||||||
for (size_t pos = reference_token.find_first_of("~");
|
for (size_t pos = reference_token.find_first_of('~');
|
||||||
pos != std::string::npos;
|
pos != std::string::npos;
|
||||||
pos = reference_token.find_first_of("~", pos + 1))
|
pos = reference_token.find_first_of('~', pos + 1))
|
||||||
{
|
{
|
||||||
assert(reference_token[pos] == '~');
|
assert(reference_token[pos] == '~');
|
||||||
|
|
||||||
|
@ -11396,7 +11351,7 @@ uses the standard template types.
|
||||||
@since version 1.0.0
|
@since version 1.0.0
|
||||||
*/
|
*/
|
||||||
using json = basic_json<>;
|
using json = basic_json<>;
|
||||||
}
|
} // namespace nlohmann
|
||||||
|
|
||||||
|
|
||||||
///////////////////////
|
///////////////////////
|
||||||
|
@ -11437,7 +11392,7 @@ struct hash<nlohmann::json>
|
||||||
return h(j.dump());
|
return h(j.dump());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
} // namespace std
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@brief user-defined string literal for JSON values
|
@brief user-defined string literal for JSON values
|
||||||
|
|
|
@ -52,7 +52,7 @@ TESTCASES = $(patsubst src/unit-%.cpp,test-%,$(wildcard src/unit-*.cpp))
|
||||||
all: $(TESTCASES)
|
all: $(TESTCASES)
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -fr json_unit $(OBJECTS) $(SOURCES:.cpp=.gcno) $(SOURCES:.cpp=.gcda) $(TESTCASES)
|
rm -fr json_unit $(OBJECTS) $(SOURCES:.cpp=.gcno) $(SOURCES:.cpp=.gcda) $(TESTCASES) parse_afl_fuzzer parse_cbor_fuzzer parse_msgpack_fuzzer
|
||||||
|
|
||||||
##############################################################################
|
##############################################################################
|
||||||
# single test file
|
# single test file
|
||||||
|
@ -85,13 +85,14 @@ check: $(TESTCASES)
|
||||||
# fuzzer
|
# fuzzer
|
||||||
##############################################################################
|
##############################################################################
|
||||||
|
|
||||||
|
FUZZER_ENGINE = src/fuzzer-driver_afl.cpp
|
||||||
fuzzers: parse_afl_fuzzer parse_cbor_fuzzer parse_msgpack_fuzzer
|
fuzzers: parse_afl_fuzzer parse_cbor_fuzzer parse_msgpack_fuzzer
|
||||||
|
|
||||||
parse_afl_fuzzer:
|
parse_afl_fuzzer:
|
||||||
$(CXX) $(CXXFLAGS) $(CPPFLAGS) src/fuzzer-driver_afl.cpp src/fuzzer-parse_json.cpp -o $@
|
$(CXX) $(CXXFLAGS) $(CPPFLAGS) $(FUZZER_ENGINE) src/fuzzer-parse_json.cpp -o $@
|
||||||
|
|
||||||
parse_cbor_fuzzer:
|
parse_cbor_fuzzer:
|
||||||
$(CXX) $(CXXFLAGS) $(CPPFLAGS) src/fuzzer-driver_afl.cpp src/fuzzer-parse_cbor.cpp -o $@
|
$(CXX) $(CXXFLAGS) $(CPPFLAGS) $(FUZZER_ENGINE) src/fuzzer-parse_cbor.cpp -o $@
|
||||||
|
|
||||||
parse_msgpack_fuzzer:
|
parse_msgpack_fuzzer:
|
||||||
$(CXX) $(CXXFLAGS) $(CPPFLAGS) src/fuzzer-driver_afl.cpp src/fuzzer-parse_msgpack.cpp -o $@
|
$(CXX) $(CXXFLAGS) $(CPPFLAGS) $(FUZZER_ENGINE) src/fuzzer-parse_msgpack.cpp -o $@
|
||||||
|
|
|
@ -80,7 +80,7 @@ struct my_allocator : std::allocator<T>
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
::new(reinterpret_cast<void*>(p)) T(std::forward<Args>(args)...);
|
::new (reinterpret_cast<void*>(p)) T(std::forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -912,7 +912,7 @@ TEST_CASE("constructors")
|
||||||
|
|
||||||
SECTION("array")
|
SECTION("array")
|
||||||
{
|
{
|
||||||
json j { {"one", 1}, {"two", 1u}, {"three", 2.2}, {"four", false} , 13 };
|
json j { {"one", 1}, {"two", 1u}, {"three", 2.2}, {"four", false}, 13 };
|
||||||
CHECK(j.type() == json::value_t::array);
|
CHECK(j.type() == json::value_t::array);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -663,4 +663,31 @@ TEST_CASE("regression tests")
|
||||||
std::vector<uint8_t> vec3 {0xbf, 0x61, 0x61, 0x01};
|
std::vector<uint8_t> vec3 {0xbf, 0x61, 0x61, 0x01};
|
||||||
CHECK_THROWS_AS(json::from_cbor(vec3), std::out_of_range);
|
CHECK_THROWS_AS(json::from_cbor(vec3), std::out_of_range);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SECTION("issue #416 - Use-of-uninitialized-value (OSS-Fuzz issue 377)")
|
||||||
|
{
|
||||||
|
// original test case
|
||||||
|
std::vector<uint8_t> vec1
|
||||||
|
{
|
||||||
|
0x94, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa,
|
||||||
|
0x3a, 0x96, 0x96, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
|
||||||
|
0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0x71,
|
||||||
|
0xb4, 0xb4, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0x3a,
|
||||||
|
0x96, 0x96, 0xb4, 0xb4, 0xfa, 0x94, 0x94, 0x61,
|
||||||
|
0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0xfa
|
||||||
|
};
|
||||||
|
CHECK_THROWS_AS(json::from_cbor(vec1), std::out_of_range);
|
||||||
|
|
||||||
|
// related test case: double-precision
|
||||||
|
std::vector<uint8_t> vec2
|
||||||
|
{
|
||||||
|
0x94, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa,
|
||||||
|
0x3a, 0x96, 0x96, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4,
|
||||||
|
0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0x71,
|
||||||
|
0xb4, 0xb4, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0x3a,
|
||||||
|
0x96, 0x96, 0xb4, 0xb4, 0xfa, 0x94, 0x94, 0x61,
|
||||||
|
0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0xfb
|
||||||
|
};
|
||||||
|
CHECK_THROWS_AS(json::from_cbor(vec2), std::out_of_range);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue