clean up after #193

This commit is contained in:
Niels 2016-01-26 19:50:49 +01:00
parent e46cc6327f
commit 707732a53e
4 changed files with 1012 additions and 545 deletions

View file

@ -390,7 +390,7 @@ I deeply appreciate the help of the following people.
- [406345](https://github.com/406345) fixed two small warnings. - [406345](https://github.com/406345) fixed two small warnings.
- [Glen Fernandes](https://github.com/glenfe) noted a potential portability problem in the `has_mapped_type` function. - [Glen Fernandes](https://github.com/glenfe) noted a potential portability problem in the `has_mapped_type` function.
- [Corbin Hughes](https://github.com/nibroc) fixed some typos in the contribution guidelines. - [Corbin Hughes](https://github.com/nibroc) fixed some typos in the contribution guidelines.
- [twelsby](https://github.com/twelsby) fixed the array subscript operator, an issue that failed the MSVC build, and floating-point parsing/dumping. - [twelsby](https://github.com/twelsby) fixed the array subscript operator, an issue that failed the MSVC build, and floating-point parsing/dumping. He further added support for unsigned integer numbers.
- [Volker Diels-Grabsch](https://github.com/vog) fixed a link in the README file. - [Volker Diels-Grabsch](https://github.com/vog) fixed a link in the README file.
Thanks a lot for helping out! Thanks a lot for helping out!
@ -409,7 +409,7 @@ $ make
$ ./json_unit "*" $ ./json_unit "*"
=============================================================================== ===============================================================================
All tests passed (3343329 assertions in 29 test cases) All tests passed (3344278 assertions in 29 test cases)
``` ```
For more information, have a look at the file [.travis.yml](https://github.com/nlohmann/json/blob/master/.travis.yml). For more information, have a look at the file [.travis.yml](https://github.com/nlohmann/json/blob/master/.travis.yml).

File diff suppressed because it is too large Load diff

View file

@ -124,8 +124,8 @@ default; will be used in @ref string_t)
in @ref boolean_t) in @ref boolean_t)
@tparam NumberIntegerType type for JSON integer numbers (@c `int64_t` by @tparam NumberIntegerType type for JSON integer numbers (@c `int64_t` by
default; will be used in @ref number_integer_t) default; will be used in @ref number_integer_t)
@tparam NumberUnsignedType type for JSON unsigned integer numbers (@c `uint64_t` by @tparam NumberUnsignedType type for JSON unsigned integer numbers (@c
default; will be used in @ref number_unsigned_t) `uint64_t` by default; will be used in @ref number_unsigned_t)
@tparam NumberFloatType type for JSON floating-point numbers (@c `double` by @tparam NumberFloatType type for JSON floating-point numbers (@c `double` by
default; will be used in @ref number_float_t) default; will be used in @ref number_float_t)
@tparam AllocatorType type of the allocator to use (@c `std::allocator` by @tparam AllocatorType type of the allocator to use (@c `std::allocator` by
@ -485,9 +485,9 @@ class basic_json
> permitted. > permitted.
This description includes both integer and floating-point numbers. However, This description includes both integer and floating-point numbers. However,
C++ allows more precise storage if it is known whether the number is a C++ allows more precise storage if it is known whether the number is a
signed integer, an unsigned integer or a floating-point number. Therefore, signed integer, an unsigned integer or a floating-point number. Therefore,
three different types, @ref number_integer_t, @ref number_unsigned_t and three different types, @ref number_integer_t, @ref number_unsigned_t and
@ref number_float_t are used. @ref number_float_t are used.
To store integer numbers in C++, a type is defined by the template To store integer numbers in C++, a type is defined by the template
@ -556,9 +556,9 @@ class basic_json
> permitted. > permitted.
This description includes both integer and floating-point numbers. However, This description includes both integer and floating-point numbers. However,
C++ allows more precise storage if it is known whether the number is a C++ allows more precise storage if it is known whether the number is a
signed integer, an unsigned integer or a floating-point number. Therefore, signed integer, an unsigned integer or a floating-point number. Therefore,
three different types, @ref number_integer_t, @ref number_unsigned_t and three different types, @ref number_integer_t, @ref number_unsigned_t and
@ref number_float_t are used. @ref number_float_t are used.
To store unsigned integer numbers in C++, a type is defined by the template To store unsigned integer numbers in C++, a type is defined by the template
@ -588,11 +588,11 @@ class basic_json
> An implementation may set limits on the range and precision of numbers. > An implementation may set limits on the range and precision of numbers.
When the default type is used, the maximal integer number that can be When the default type is used, the maximal integer number that can be
stored is `18446744073709551615` (UINT64_MAX) and the minimal integer number stored is `18446744073709551615` (UINT64_MAX) and the minimal integer
that can be stored is `0`. Integer numbers number that can be stored is `0`. Integer numbers that are out of range
that are out of range will yield over/underflow when used in a constructor. will yield over/underflow when used in a constructor. During
During deserialization, too large or small integer numbers will be deserialization, too large or small integer numbers will be automatically
automatically be stored as @ref number_integer_t or @ref number_float_t. be stored as @ref number_integer_t or @ref number_float_t.
[RFC 7159](http://rfc7159.net/rfc7159) further states: [RFC 7159](http://rfc7159.net/rfc7159) further states:
> Note that when such software is used, numbers that are integers and are > Note that when such software is used, numbers that are integers and are
@ -600,7 +600,7 @@ class basic_json
> that implementations will agree exactly on their numeric values. > that implementations will agree exactly on their numeric values.
As this range is a subrange (when considered in conjunction with the As this range is a subrange (when considered in conjunction with the
number_integer_t type) of the exactly supported range [0, UINT64_MAX], this number_integer_t type) of the exactly supported range [0, UINT64_MAX], this
class's integer type is interoperable. class's integer type is interoperable.
#### Storage #### Storage
@ -614,7 +614,7 @@ class basic_json
@since version 2.0.0 @since version 2.0.0
*/ */
using number_unsigned_t = NumberUnsignedType; using number_unsigned_t = NumberUnsignedType;
/*! /*!
@brief a type for a number (floating-point) @brief a type for a number (floating-point)
@ -628,9 +628,9 @@ class basic_json
> permitted. > permitted.
This description includes both integer and floating-point numbers. However, This description includes both integer and floating-point numbers. However,
C++ allows more precise storage if it is known whether the number is a C++ allows more precise storage if it is known whether the number is a
signed integer, an unsigned integer or a floating-point number. Therefore, signed integer, an unsigned integer or a floating-point number. Therefore,
three different types, @ref number_integer_t, @ref number_unsigned_t and three different types, @ref number_integer_t, @ref number_unsigned_t and
@ref number_float_t are used. @ref number_float_t are used.
To store floating-point numbers in C++, a type is defined by the template To store floating-point numbers in C++, a type is defined by the template
@ -801,7 +801,7 @@ class basic_json
number_integer = number_integer_t(0); number_integer = number_integer_t(0);
break; break;
} }
case value_t::number_unsigned: case value_t::number_unsigned:
{ {
number_unsigned = number_unsigned_t(0); number_unsigned = number_unsigned_t(0);
@ -1330,8 +1330,8 @@ class basic_json
template<typename CompatibleNumberIntegerType, typename template<typename CompatibleNumberIntegerType, typename
std::enable_if< std::enable_if<
std::is_constructible<number_integer_t, CompatibleNumberIntegerType>::value and std::is_constructible<number_integer_t, CompatibleNumberIntegerType>::value and
std::numeric_limits<CompatibleNumberIntegerType>::is_integer and std::numeric_limits<CompatibleNumberIntegerType>::is_integer and
std::numeric_limits<CompatibleNumberIntegerType>::is_signed, std::numeric_limits<CompatibleNumberIntegerType>::is_signed,
CompatibleNumberIntegerType>::type CompatibleNumberIntegerType>::type
= 0> = 0>
basic_json(const CompatibleNumberIntegerType val) noexcept basic_json(const CompatibleNumberIntegerType val) noexcept
@ -1344,7 +1344,7 @@ class basic_json
Create an unsigned integer number JSON value with a given content. Create an unsigned integer number JSON value with a given content.
@tparam T helper type to compare number_unsigned_t and unsigned int @tparam T helper type to compare number_unsigned_t and unsigned int
(not visible in) the interface. (not visible in) the interface.
@param[in] val an integer to create a JSON number from @param[in] val an integer to create a JSON number from
@ -1365,14 +1365,14 @@ class basic_json
basic_json(const number_unsigned_t val) basic_json(const number_unsigned_t val)
: m_type(value_t::number_unsigned), m_value(val) : m_type(value_t::number_unsigned), m_value(val)
{} {}
/*! /*!
@brief create an unsigned number (implicit) @brief create an unsigned number (implicit)
Create an unsigned number JSON value with a given content. This constructor Create an unsigned number JSON value with a given content. This constructor
allows any type that can be used to construct values of type @ref allows any type that can be used to construct values of type @ref
number_unsigned_t. Examples may include the types `unsigned int`, `uint32_t`, number_unsigned_t. Examples may include the types `unsigned int`,
or `unsigned short`. `uint32_t`, or `unsigned short`.
@tparam CompatibleNumberUnsignedType an integer type which is compatible to @tparam CompatibleNumberUnsignedType an integer type which is compatible to
@ref number_unsigned_t. @ref number_unsigned_t.
@ -1386,13 +1386,13 @@ class basic_json
@since version 2.0.0 @since version 2.0.0
*/ */
template<typename CompatibleNumberUnsignedType, typename template < typename CompatibleNumberUnsignedType, typename
std::enable_if< std::enable_if <
std::is_constructible<number_unsigned_t, CompatibleNumberUnsignedType>::value and std::is_constructible<number_unsigned_t, CompatibleNumberUnsignedType>::value and
std::numeric_limits<CompatibleNumberUnsignedType>::is_integer and std::numeric_limits<CompatibleNumberUnsignedType>::is_integer and
!std::numeric_limits<CompatibleNumberUnsignedType>::is_signed, !std::numeric_limits<CompatibleNumberUnsignedType>::is_signed,
CompatibleNumberUnsignedType>::type CompatibleNumberUnsignedType >::type
= 0> = 0 >
basic_json(const CompatibleNumberUnsignedType val) noexcept basic_json(const CompatibleNumberUnsignedType val) noexcept
: m_type(value_t::number_unsigned), : m_type(value_t::number_unsigned),
m_value(static_cast<number_unsigned_t>(val)) m_value(static_cast<number_unsigned_t>(val))
@ -1781,7 +1781,7 @@ class basic_json
m_value.number_integer = first.m_object->m_value.number_integer; m_value.number_integer = first.m_object->m_value.number_integer;
break; break;
} }
case value_t::number_unsigned: case value_t::number_unsigned:
{ {
assert(first.m_object != nullptr); assert(first.m_object != nullptr);
@ -1891,7 +1891,7 @@ class basic_json
m_value = other.m_value.number_integer; m_value = other.m_value.number_integer;
break; break;
} }
case value_t::number_unsigned: case value_t::number_unsigned:
{ {
m_value = other.m_value.number_unsigned; m_value = other.m_value.number_unsigned;
@ -2183,9 +2183,10 @@ class basic_json
@liveexample{The following code exemplifies @ref is_number for all JSON @liveexample{The following code exemplifies @ref is_number for all JSON
types.,is_number} types.,is_number}
@sa @ref is_number_integer() -- check if value is an integer or unsigned @sa @ref is_number_integer() -- check if value is an integer or unsigned
integer number integer number
@sa @ref is_number_unsigned() -- check if value is an unsigned integer number @sa @ref is_number_unsigned() -- check if value is an unsigned integer
number
@sa @ref is_number_float() -- check if value is a floating-point number @sa @ref is_number_float() -- check if value is a floating-point number
@since version 1.0.0 @since version 1.0.0
@ -2198,10 +2199,10 @@ class basic_json
/*! /*!
@brief return whether value is an integer number @brief return whether value is an integer number
This function returns true iff the JSON value is an integer or unsigned This function returns true iff the JSON value is an integer or unsigned
integer number. This excludes floating-point values. integer number. This excludes floating-point values.
@return `true` if type is an integer or unsigned integer number, `false` @return `true` if type is an integer or unsigned integer number, `false`
otherwise. otherwise.
@complexity Constant. @complexity Constant.
@ -2210,7 +2211,8 @@ class basic_json
JSON types.,is_number_integer} JSON types.,is_number_integer}
@sa @ref is_number() -- check if value is a number @sa @ref is_number() -- check if value is a number
@sa @ref is_number_unsigned() -- check if value is an unsigned integer number @sa @ref is_number_unsigned() -- check if value is an unsigned integer
number
@sa @ref is_number_float() -- check if value is a floating-point number @sa @ref is_number_float() -- check if value is a floating-point number
@since version 1.0.0 @since version 1.0.0
@ -2219,19 +2221,19 @@ class basic_json
{ {
return m_type == value_t::number_integer or m_type == value_t::number_unsigned; return m_type == value_t::number_integer or m_type == value_t::number_unsigned;
} }
/*! /*!
@brief return whether value is an unsigned integer number @brief return whether value is an unsigned integer number
This function returns true iff the JSON value is an unsigned integer number. This function returns true iff the JSON value is an unsigned integer
This excludes floating-point and (signed) integer values. number. This excludes floating-point and (signed) integer values.
@return `true` if type is an unsigned integer number, `false` otherwise. @return `true` if type is an unsigned integer number, `false` otherwise.
@complexity Constant. @complexity Constant.
@sa @ref is_number() -- check if value is a number @sa @ref is_number() -- check if value is a number
@sa @ref is_number_integer() -- check if value is an integer or unsigned @sa @ref is_number_integer() -- check if value is an integer or unsigned
integer number integer number
@sa @ref is_number_float() -- check if value is a floating-point number @sa @ref is_number_float() -- check if value is a floating-point number
@ -2257,7 +2259,8 @@ class basic_json
@sa @ref is_number() -- check if value is number @sa @ref is_number() -- check if value is number
@sa @ref is_number_integer() -- check if value is an integer number @sa @ref is_number_integer() -- check if value is an integer number
@sa @ref is_number_unsigned() -- check if value is an unsigned integer number @sa @ref is_number_unsigned() -- check if value is an unsigned integer
number
@since version 1.0.0 @since version 1.0.0
*/ */
@ -2525,7 +2528,7 @@ class basic_json
{ {
return static_cast<T>(m_value.number_integer); return static_cast<T>(m_value.number_integer);
} }
case value_t::number_unsigned: case value_t::number_unsigned:
{ {
return static_cast<T>(m_value.number_unsigned); return static_cast<T>(m_value.number_unsigned);
@ -2615,7 +2618,7 @@ class basic_json
{ {
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*) noexcept
{ {
@ -2627,7 +2630,7 @@ class basic_json
{ {
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*) noexcept
{ {
@ -2725,7 +2728,7 @@ class basic_json
@warning The pointer becomes invalid if the underlying JSON object changes. @warning The pointer becomes invalid if the underlying JSON object changes.
@tparam PointerType pointer type; must be a pointer to @ref array_t, @ref @tparam PointerType pointer type; must be a pointer to @ref array_t, @ref
object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, object_t, @ref string_t, @ref boolean_t, @ref number_integer_t,
@ref number_unsigned_t, or @ref number_float_t. @ref number_unsigned_t, or @ref number_float_t.
@return pointer to the internally stored JSON value if the requested @return pointer to the internally stored JSON value if the requested
@ -2776,7 +2779,7 @@ class basic_json
state. state.
@tparam PointerType pointer type; must be a pointer to @ref array_t, @ref @tparam PointerType pointer type; must be a pointer to @ref array_t, @ref
object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, object_t, @ref string_t, @ref boolean_t, @ref number_integer_t,
@ref number_unsigned_t, or @ref number_float_t. @ref number_unsigned_t, or @ref number_float_t.
@return pointer to the internally stored JSON value if the requested @return pointer to the internally stored JSON value if the requested
@ -2895,14 +2898,14 @@ class basic_json
@since version 1.0.0 @since version 1.0.0
*/ */
template<typename ValueType, typename template < typename ValueType, typename
std::enable_if< std::enable_if <
not std::is_pointer<ValueType>::value not std::is_pointer<ValueType>::value
and not std::is_same<ValueType, typename string_t::value_type>::value and 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 >
operator ValueType() const operator ValueType() const
{ {
// delegate the call to get<>() const // delegate the call to get<>() const
@ -7390,17 +7393,17 @@ class basic_json
/*! /*!
@brief static_cast between two types and indicate if it results in error @brief static_cast between two types and indicate if it results in error
This function performs a static_cast between @a source and @a dest. It This function performs a static_cast between @a source and @a dest. It
then checks if a static_cast back to @a dest produces an error. then checks if a static_cast back to @a dest produces an error.
@param[in] source the value to cast from @param[in] source the value to cast from
@param[out] dest the value to cast to @param[out] dest the value to cast to
@return @a true if the cast was performed without error, @a false otherwise @return @a true if the cast was performed without error, @a false otherwise
*/ */
template <typename T_A, typename T_B> template <typename T_A, typename T_B>
bool attempt_cast(T_A source, T_B & dest) const bool attempt_cast(T_A source, T_B& dest) const
{ {
dest = static_cast<T_B>(source); dest = static_cast<T_B>(source);
return (source == static_cast<T_A>(dest)); return (source == static_cast<T_A>(dest));
@ -7409,74 +7412,101 @@ class basic_json
/*! /*!
@brief return number value for number tokens @brief return number value for number tokens
This function translates the last token into the most appropriate This function translates the last token into the most appropriate
number type (either integer, unsigned integer or floating point), number type (either integer, unsigned integer or floating point), which
which is passed back to the caller via the result parameter. The pointer is passed back to the caller via the result parameter. The pointer @a
@a m_start points to the beginning of the parsed number. We first examine m_start points to the beginning of the parsed number. We first examine
the first character to determine the sign of the number and then pass the first character to determine the sign of the number and then pass
this pointer to either @a std::strtoull (if positive) or @a std::strtoll this pointer to either @a std::strtoull (if positive) or @a
(if negative), both of which set @a endptr to the first character past the std::strtoll (if negative), both of which set @a endptr to the first
converted number. If this pointer is not the same as @a m_cursor, then character past the converted number. If this pointer is not the same as
either more or less characters have been used during the comparison. @a m_cursor, then either more or less characters have been used during
the comparison.
This can happen for inputs like "01" which will be treated like number 0
followed by number 1. This will also occur for valid floating point This can happen for inputs like "01" which will be treated like number
inputs like "12e3" will be incorrectly read as 12. Numbers that are too 0 followed by number 1. This will also occur for valid floating point
inputs like "12e3" will be incorrectly read as 12. Numbers that are too
large or too small for a signed/unsigned long long will cause a range large or too small for a signed/unsigned long long will cause a range
error (@a errno set to ERANGE). The parsed number is cast to a @ref error (@a errno set to ERANGE). The parsed number is cast to a @ref
number_integer_t/@ref number_unsigned_t using the helper function @ref attempt_cast, number_integer_t/@ref number_unsigned_t using the helper function @ref
which returns @a false if the cast could not be peformed without error. attempt_cast, which returns @a false if the cast could not be peformed
without error.
In any of these cases (more/less characters read, range error or a cast In any of these cases (more/less characters read, range error or a cast
error) the pointer is passed to @a std:strtod, which also sets @a endptr to the error) the pointer is passed to @a std:strtod, which also sets @a
first character past the converted number. The resulting @ref number_float_t endptr to the first character past the converted number. The resulting
is then cast to a @ref number_integer_t/@ref number_unsigned_t using @ref number_float_t is then cast to a @ref number_integer_t/@ref
@ref attempt_cast and if no error occurs is stored in that form, otherwise number_unsigned_t using @ref attempt_cast and if no error occurs is
it is stored as a @ref number_float_t. stored in that form, otherwise it is stored as a @ref number_float_t.
A final comparison is made of @a endptr and if still not the same as
@ref m_cursor a bad input is assumed and @a result parameter is set to NAN.
@param[out] result @ref basic_json object to receive the number, or NAN if the A final comparison is made of @a endptr and if still not the same as
conversion read past the current token. The latter case needs to be @ref m_cursor a bad input is assumed and @a result parameter is set to
treated by the caller function. NAN.
@param[out] result @ref basic_json object to receive the number, or NAN
if the conversion read past the current token. The latter case needs to
be treated by the caller function.
*/ */
void get_number(basic_json& result) const void get_number(basic_json& result) const
{ {
typename string_t::value_type* endptr; typename string_t::value_type* endptr;
assert(m_start != nullptr); assert(m_start != nullptr);
errno = 0; errno = 0;
// Attempt to parse it as an integer - first checking for a negative number // attempt to parse it as an integer - first checking for a
// negative number
if (*reinterpret_cast<typename string_t::const_pointer>(m_start) != '-') if (*reinterpret_cast<typename string_t::const_pointer>(m_start) != '-')
{ {
// Positive, parse with strtoull and attempt cast to number_unsigned_t // positive, parse with strtoull and attempt cast to
if (attempt_cast(std::strtoull(reinterpret_cast<typename string_t::const_pointer>(m_start), &endptr, 10), result.m_value.number_unsigned)) // number_unsigned_t
if (attempt_cast(std::strtoull(reinterpret_cast<typename string_t::const_pointer>(m_start), &endptr,
10), result.m_value.number_unsigned))
{
result.m_type = value_t::number_unsigned; result.m_type = value_t::number_unsigned;
else result.m_type = value_t::number_float; // Cast failed due to overflow - store as float }
else
{
// cast failed due to overflow - store as float
result.m_type = value_t::number_float;
}
} }
else else
{ {
// Negative, parse with strtoll and attempt cast to number_integer_t // Negative, parse with strtoll and attempt cast to
if (attempt_cast(std::strtoll(reinterpret_cast<typename string_t::const_pointer>(m_start), &endptr, 10), result.m_value.number_unsigned)) // number_integer_t
if (attempt_cast(std::strtoll(reinterpret_cast<typename string_t::const_pointer>(m_start), &endptr,
10), result.m_value.number_unsigned))
{
result.m_type = value_t::number_integer; result.m_type = value_t::number_integer;
else result.m_type = value_t::number_float; // Cast failed due to overflow - store as float }
else
{
// cast failed due to overflow - store as float
result.m_type = value_t::number_float;
}
} }
// Check the end of the number was reached and no range error occurred // check the end of the number was reached and no range error
if (reinterpret_cast<lexer_char_t*>(endptr) != m_cursor || errno == ERANGE) result.m_type = value_t::number_float; // occurred
if (reinterpret_cast<lexer_char_t*>(endptr) != m_cursor || errno == ERANGE)
{
result.m_type = value_t::number_float;
}
if (result.m_type == value_t::number_float) if (result.m_type == value_t::number_float)
{ {
// Either the number won't fit in an integer (range error from strtoull/strtoll or overflow on cast) or there was // either the number won't fit in an integer (range error from
// something else after the number, which could be an exponent // strtoull/strtoll or overflow on cast) or there was something
// else after the number, which could be an exponent
// Parse with strtod
// parse with strtod
result.m_value.number_float = str_to_float_t(static_cast<number_float_t*>(nullptr), &endptr); result.m_value.number_float = str_to_float_t(static_cast<number_float_t*>(nullptr), &endptr);
// Anything after the number is an error // anything after the number is an error
if(reinterpret_cast<lexer_char_t*>(endptr) != m_cursor) if (reinterpret_cast<lexer_char_t*>(endptr) != m_cursor)
{
throw std::invalid_argument(std::string("parse error - ") + get_token() + " is not a number"); throw std::invalid_argument(std::string("parse error - ") + get_token() + " is not a number");
}
} }
} }
@ -7848,5 +7878,3 @@ inline nlohmann::json operator "" _json(const char* s, std::size_t)
#endif #endif
#endif #endif

View file

@ -924,7 +924,8 @@ TEST_CASE("constructors")
SECTION("object with error") SECTION("object with error")
{ {
CHECK_THROWS_AS(json::object({ {"one", 1}, {"two", 1u}, {"three", 2.2}, {"four", false}, 13 }), std::logic_error); CHECK_THROWS_AS(json::object({ {"one", 1}, {"two", 1u}, {"three", 2.2}, {"four", false}, 13 }),
std::logic_error);
CHECK_THROWS_WITH(json::object({ {"one", 1}, {"two", 1u}, {"three", 2.2}, {"four", false}, 13 }), CHECK_THROWS_WITH(json::object({ {"one", 1}, {"two", 1u}, {"three", 2.2}, {"four", false}, 13 }),
"cannot create object from initializer list"); "cannot create object from initializer list");
} }
@ -2312,7 +2313,7 @@ TEST_CASE("value conversion")
json::number_integer_t n = j.get<json::number_integer_t>(); json::number_integer_t n = j.get<json::number_integer_t>();
CHECK(json(n) == j); CHECK(json(n) == j);
} }
SECTION("number_unsigned_t") SECTION("number_unsigned_t")
{ {
json::number_unsigned_t n = j_unsigned.get<json::number_unsigned_t>(); json::number_unsigned_t n = j_unsigned.get<json::number_unsigned_t>();
@ -3665,7 +3666,7 @@ TEST_CASE("element access")
CHECK_THROWS_WITH(j_nonobject.at("foo"), "cannot use at() with number"); CHECK_THROWS_WITH(j_nonobject.at("foo"), "cannot use at() with number");
CHECK_THROWS_WITH(j_nonobject_const.at("foo"), "cannot use at() with number"); CHECK_THROWS_WITH(j_nonobject_const.at("foo"), "cannot use at() with number");
} }
SECTION("number (unsigned)") SECTION("number (unsigned)")
{ {
json j_nonobject(json::value_t::number_unsigned); json j_nonobject(json::value_t::number_unsigned);
@ -3675,7 +3676,7 @@ TEST_CASE("element access")
CHECK_THROWS_WITH(j_nonobject.at("foo"), "cannot use at() with number"); CHECK_THROWS_WITH(j_nonobject.at("foo"), "cannot use at() with number");
CHECK_THROWS_WITH(j_nonobject_const.at("foo"), "cannot use at() with number"); CHECK_THROWS_WITH(j_nonobject_const.at("foo"), "cannot use at() with number");
} }
SECTION("number (floating-point)") SECTION("number (floating-point)")
{ {
json j_nonobject(json::value_t::number_float); json j_nonobject(json::value_t::number_float);
@ -5435,7 +5436,7 @@ TEST_CASE("iterators")
SECTION("object") SECTION("object")
{ {
json j = {{"A", 1},{"B", 2},{"C", 3}}; json j = {{"A", 1}, {"B", 2}, {"C", 3}};
json j_const(j); json j_const(j);
SECTION("json + begin/end") SECTION("json + begin/end")
@ -9661,7 +9662,7 @@ TEST_CASE("parser class")
// (2**53)-1 // (2**53)-1
CHECK(json::parser("9007199254740991").parse().get<int64_t>() == 9007199254740991); CHECK(json::parser("9007199254740991").parse().get<int64_t>() == 9007199254740991);
} }
SECTION("over the edge cases") // issue #178 - Integer conversion to unsigned (incorrect handling of 64 bit integers) SECTION("over the edge cases") // issue #178 - Integer conversion to unsigned (incorrect handling of 64 bit integers)
{ {
// While RFC7159, Section 6 specifies a preference for support // While RFC7159, Section 6 specifies a preference for support
@ -9672,7 +9673,7 @@ TEST_CASE("parser class")
// i.e. -(2**63) -> (2**64)-1. // i.e. -(2**63) -> (2**64)-1.
// -(2**63) ** Note: compilers see negative literals as negated positive numbers (hence the -1)) // -(2**63) ** Note: compilers see negative literals as negated positive numbers (hence the -1))
CHECK(json::parser("-9223372036854775808").parse().get<int64_t>() == -9223372036854775807-1); CHECK(json::parser("-9223372036854775808").parse().get<int64_t>() == -9223372036854775807 - 1);
// (2**63)-1 // (2**63)-1
CHECK(json::parser("9223372036854775807").parse().get<int64_t>() == 9223372036854775807); CHECK(json::parser("9223372036854775807").parse().get<int64_t>() == 9223372036854775807);
// (2**64)-1 // (2**64)-1
@ -9720,12 +9721,14 @@ TEST_CASE("parser class")
CHECK_THROWS_WITH(json::parser("01").parse(), "parse error - 0 is not a number"); CHECK_THROWS_WITH(json::parser("01").parse(), "parse error - 0 is not a number");
CHECK_THROWS_WITH(json::parser("--1").parse(), "parse error - unexpected '-'"); CHECK_THROWS_WITH(json::parser("--1").parse(), "parse error - unexpected '-'");
CHECK_THROWS_WITH(json::parser("1.").parse(), "parse error - unexpected '.'; expected end of input"); CHECK_THROWS_WITH(json::parser("1.").parse(),
"parse error - unexpected '.'; expected end of input");
CHECK_THROWS_WITH(json::parser("1E").parse(), CHECK_THROWS_WITH(json::parser("1E").parse(),
"parse error - unexpected 'E'; expected end of input"); "parse error - unexpected 'E'; expected end of input");
CHECK_THROWS_WITH(json::parser("1E-").parse(), CHECK_THROWS_WITH(json::parser("1E-").parse(),
"parse error - unexpected 'E'; expected end of input"); "parse error - unexpected 'E'; expected end of input");
CHECK_THROWS_WITH(json::parser("1.E1").parse(), "parse error - unexpected '.'; expected end of input"); CHECK_THROWS_WITH(json::parser("1.E1").parse(),
"parse error - unexpected '.'; expected end of input");
CHECK_THROWS_WITH(json::parser("-1E").parse(), CHECK_THROWS_WITH(json::parser("-1E").parse(),
"parse error - unexpected 'E'; expected end of input"); "parse error - unexpected 'E'; expected end of input");
CHECK_THROWS_WITH(json::parser("-0E#").parse(), CHECK_THROWS_WITH(json::parser("-0E#").parse(),
@ -9767,7 +9770,8 @@ TEST_CASE("parser class")
CHECK_THROWS_AS(json::parser("1E.").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("1E.").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("1E/").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("1E/").parse(), std::invalid_argument);
CHECK_THROWS_AS(json::parser("1E:").parse(), std::invalid_argument); CHECK_THROWS_AS(json::parser("1E:").parse(), std::invalid_argument);
CHECK_THROWS_WITH(json::parser("0.").parse(), "parse error - unexpected '.'; expected end of input"); CHECK_THROWS_WITH(json::parser("0.").parse(),
"parse error - unexpected '.'; expected end of input");
CHECK_THROWS_WITH(json::parser("-").parse(), "parse error - unexpected '-'"); CHECK_THROWS_WITH(json::parser("-").parse(), "parse error - unexpected '-'");
CHECK_THROWS_WITH(json::parser("--").parse(), CHECK_THROWS_WITH(json::parser("--").parse(),
"parse error - unexpected '-'"); "parse error - unexpected '-'");
@ -12076,14 +12080,15 @@ TEST_CASE("regression tests")
SECTION("issue #89 - nonstandard integer type") SECTION("issue #89 - nonstandard integer type")
{ {
// create JSON class with nonstandard integer number type // create JSON class with nonstandard integer number type
using custom_json = nlohmann::basic_json<std::map, std::vector, std::string, bool, int32_t, uint32_t, float>; using custom_json =
nlohmann::basic_json<std::map, std::vector, std::string, bool, int32_t, uint32_t, float>;
custom_json j; custom_json j;
j["int_1"] = 1; j["int_1"] = 1;
// we need to cast to int to compile with Catch - the value is int32_t // we need to cast to int to compile with Catch - the value is int32_t
CHECK(static_cast<int>(j["int_1"]) == 1); CHECK(static_cast<int>(j["int_1"]) == 1);
// tests for correct handling of non-standard integers that overflow the type selected by the user // tests for correct handling of non-standard integers that overflow the type selected by the user
// unsigned integer object creation - expected to wrap and still be stored as an integer // unsigned integer object creation - expected to wrap and still be stored as an integer
j = 4294967296U; // 2^32 j = 4294967296U; // 2^32
CHECK(static_cast<int>(j.type()) == static_cast<int>(custom_json::value_t::number_unsigned)); CHECK(static_cast<int>(j.type()) == static_cast<int>(custom_json::value_t::number_unsigned));
@ -12201,11 +12206,11 @@ TEST_CASE("regression tests")
{ {
CHECK(json::parse("\"\\ud80c\\udc60abc\"").get<json::string_t>() == u8"\U00013060abc"); CHECK(json::parse("\"\\ud80c\\udc60abc\"").get<json::string_t>() == u8"\U00013060abc");
} }
SECTION("issue #171 - Cannot index by key of type static constexpr const char*") SECTION("issue #171 - Cannot index by key of type static constexpr const char*")
{ {
json j; json j;
// Non-const access with key as "char []" // Non-const access with key as "char []"
char array_key[] = "Key1"; char array_key[] = "Key1";
CHECK_NOTHROW(j[array_key] = 1); CHECK_NOTHROW(j[array_key] = 1);
@ -12281,15 +12286,18 @@ TEST_CASE("regression tests")
// create JSON class with nonstandard float number type // create JSON class with nonstandard float number type
// float // float
nlohmann::basic_json<std::map, std::vector, std::string, bool, int32_t, uint32_t, float> j_float = 1.23e25f; nlohmann::basic_json<std::map, std::vector, std::string, bool, int32_t, uint32_t, float> j_float =
1.23e25f;
CHECK(j_float.get<float>() == 1.23e25f); CHECK(j_float.get<float>() == 1.23e25f);
// double // double
nlohmann::basic_json<std::map, std::vector, std::string, bool, int64_t, uint64_t, double> j_double = 1.23e35f; nlohmann::basic_json<std::map, std::vector, std::string, bool, int64_t, uint64_t, double> j_double =
1.23e35f;
CHECK(j_double.get<double>() == 1.23e35f); CHECK(j_double.get<double>() == 1.23e35f);
// long double // long double
nlohmann::basic_json<std::map, std::vector, std::string, bool, int64_t, uint64_t, long double> j_long_double = 1.23e45L; nlohmann::basic_json<std::map, std::vector, std::string, bool, int64_t, uint64_t, long double>
j_long_double = 1.23e45L;
CHECK(j_long_double.get<long double>() == 1.23e45L); CHECK(j_long_double.get<long double>() == 1.23e45L);
} }
} }