mirror of
https://github.com/nlohmann/json.git
synced 2025-07-15 07:41:50 +03:00
clean up after #193
This commit is contained in:
@ -124,8 +124,8 @@ default; will be used in @ref string_t)
|
||||
in @ref boolean_t)
|
||||
@tparam NumberIntegerType type for JSON integer numbers (@c `int64_t` by
|
||||
default; will be used in @ref number_integer_t)
|
||||
@tparam NumberUnsignedType type for JSON unsigned integer numbers (@c `uint64_t` by
|
||||
default; will be used in @ref number_unsigned_t)
|
||||
@tparam NumberUnsignedType type for JSON unsigned integer numbers (@c
|
||||
`uint64_t` by default; will be used in @ref number_unsigned_t)
|
||||
@tparam NumberFloatType type for JSON floating-point numbers (@c `double` by
|
||||
default; will be used in @ref number_float_t)
|
||||
@tparam AllocatorType type of the allocator to use (@c `std::allocator` by
|
||||
@ -485,9 +485,9 @@ class basic_json
|
||||
> permitted.
|
||||
|
||||
This description includes both integer and floating-point numbers. However,
|
||||
C++ allows more precise storage if it is known whether the number is a
|
||||
C++ allows more precise storage if it is known whether the number is a
|
||||
signed integer, an unsigned integer or a floating-point number. Therefore,
|
||||
three different types, @ref number_integer_t, @ref number_unsigned_t and
|
||||
three different types, @ref number_integer_t, @ref number_unsigned_t and
|
||||
@ref number_float_t are used.
|
||||
|
||||
To store integer numbers in C++, a type is defined by the template
|
||||
@ -556,9 +556,9 @@ class basic_json
|
||||
> permitted.
|
||||
|
||||
This description includes both integer and floating-point numbers. However,
|
||||
C++ allows more precise storage if it is known whether the number is a
|
||||
C++ allows more precise storage if it is known whether the number is a
|
||||
signed integer, an unsigned integer or a floating-point number. Therefore,
|
||||
three different types, @ref number_integer_t, @ref number_unsigned_t and
|
||||
three different types, @ref number_integer_t, @ref number_unsigned_t and
|
||||
@ref number_float_t are used.
|
||||
|
||||
To store unsigned integer numbers in C++, a type is defined by the template
|
||||
@ -588,11 +588,11 @@ class basic_json
|
||||
> An implementation may set limits on the range and precision of numbers.
|
||||
|
||||
When the default type is used, the maximal integer number that can be
|
||||
stored is `18446744073709551615` (UINT64_MAX) and the minimal integer number
|
||||
that can be stored is `0`. Integer numbers
|
||||
that are out of range will yield over/underflow when used in a constructor.
|
||||
During deserialization, too large or small integer numbers will be
|
||||
automatically be stored as @ref number_integer_t or @ref number_float_t.
|
||||
stored is `18446744073709551615` (UINT64_MAX) and the minimal integer
|
||||
number that can be stored is `0`. Integer numbers that are out of range
|
||||
will yield over/underflow when used in a constructor. During
|
||||
deserialization, too large or small integer numbers will be automatically
|
||||
be stored as @ref number_integer_t or @ref number_float_t.
|
||||
|
||||
[RFC 7159](http://rfc7159.net/rfc7159) further states:
|
||||
> Note that when such software is used, numbers that are integers and are
|
||||
@ -600,7 +600,7 @@ class basic_json
|
||||
> that implementations will agree exactly on their numeric values.
|
||||
|
||||
As this range is a subrange (when considered in conjunction with the
|
||||
number_integer_t type) of the exactly supported range [0, UINT64_MAX], this
|
||||
number_integer_t type) of the exactly supported range [0, UINT64_MAX], this
|
||||
class's integer type is interoperable.
|
||||
|
||||
#### Storage
|
||||
@ -614,7 +614,7 @@ class basic_json
|
||||
@since version 2.0.0
|
||||
*/
|
||||
using number_unsigned_t = NumberUnsignedType;
|
||||
|
||||
|
||||
/*!
|
||||
@brief a type for a number (floating-point)
|
||||
|
||||
@ -628,9 +628,9 @@ class basic_json
|
||||
> permitted.
|
||||
|
||||
This description includes both integer and floating-point numbers. However,
|
||||
C++ allows more precise storage if it is known whether the number is a
|
||||
C++ allows more precise storage if it is known whether the number is a
|
||||
signed integer, an unsigned integer or a floating-point number. Therefore,
|
||||
three different types, @ref number_integer_t, @ref number_unsigned_t and
|
||||
three different types, @ref number_integer_t, @ref number_unsigned_t and
|
||||
@ref number_float_t are used.
|
||||
|
||||
To store floating-point numbers in C++, a type is defined by the template
|
||||
@ -801,7 +801,7 @@ class basic_json
|
||||
number_integer = number_integer_t(0);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
case value_t::number_unsigned:
|
||||
{
|
||||
number_unsigned = number_unsigned_t(0);
|
||||
@ -1330,8 +1330,8 @@ class basic_json
|
||||
template<typename CompatibleNumberIntegerType, typename
|
||||
std::enable_if<
|
||||
std::is_constructible<number_integer_t, CompatibleNumberIntegerType>::value and
|
||||
std::numeric_limits<CompatibleNumberIntegerType>::is_integer and
|
||||
std::numeric_limits<CompatibleNumberIntegerType>::is_signed,
|
||||
std::numeric_limits<CompatibleNumberIntegerType>::is_integer and
|
||||
std::numeric_limits<CompatibleNumberIntegerType>::is_signed,
|
||||
CompatibleNumberIntegerType>::type
|
||||
= 0>
|
||||
basic_json(const CompatibleNumberIntegerType val) noexcept
|
||||
@ -1344,7 +1344,7 @@ class basic_json
|
||||
|
||||
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.
|
||||
|
||||
@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)
|
||||
: m_type(value_t::number_unsigned), m_value(val)
|
||||
{}
|
||||
|
||||
|
||||
/*!
|
||||
@brief create an unsigned number (implicit)
|
||||
|
||||
Create an unsigned number JSON value with a given content. This constructor
|
||||
allows any type that can be used to construct values of type @ref
|
||||
number_unsigned_t. Examples may include the types `unsigned int`, `uint32_t`,
|
||||
or `unsigned short`.
|
||||
number_unsigned_t. Examples may include the types `unsigned int`,
|
||||
`uint32_t`, or `unsigned short`.
|
||||
|
||||
@tparam CompatibleNumberUnsignedType an integer type which is compatible to
|
||||
@ref number_unsigned_t.
|
||||
@ -1386,13 +1386,13 @@ class basic_json
|
||||
|
||||
@since version 2.0.0
|
||||
*/
|
||||
template<typename CompatibleNumberUnsignedType, typename
|
||||
std::enable_if<
|
||||
std::is_constructible<number_unsigned_t, CompatibleNumberUnsignedType>::value and
|
||||
std::numeric_limits<CompatibleNumberUnsignedType>::is_integer and
|
||||
!std::numeric_limits<CompatibleNumberUnsignedType>::is_signed,
|
||||
CompatibleNumberUnsignedType>::type
|
||||
= 0>
|
||||
template < typename CompatibleNumberUnsignedType, typename
|
||||
std::enable_if <
|
||||
std::is_constructible<number_unsigned_t, CompatibleNumberUnsignedType>::value and
|
||||
std::numeric_limits<CompatibleNumberUnsignedType>::is_integer and
|
||||
!std::numeric_limits<CompatibleNumberUnsignedType>::is_signed,
|
||||
CompatibleNumberUnsignedType >::type
|
||||
= 0 >
|
||||
basic_json(const CompatibleNumberUnsignedType val) noexcept
|
||||
: m_type(value_t::number_unsigned),
|
||||
m_value(static_cast<number_unsigned_t>(val))
|
||||
@ -1781,7 +1781,7 @@ class basic_json
|
||||
m_value.number_integer = first.m_object->m_value.number_integer;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
case value_t::number_unsigned:
|
||||
{
|
||||
assert(first.m_object != nullptr);
|
||||
@ -1891,7 +1891,7 @@ class basic_json
|
||||
m_value = other.m_value.number_integer;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
case value_t::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
|
||||
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
|
||||
@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
|
||||
|
||||
@since version 1.0.0
|
||||
@ -2198,10 +2199,10 @@ class basic_json
|
||||
/*!
|
||||
@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.
|
||||
|
||||
@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.
|
||||
|
||||
@complexity Constant.
|
||||
@ -2210,7 +2211,8 @@ class basic_json
|
||||
JSON types.,is_number_integer}
|
||||
|
||||
@sa @ref is_number() -- check if value is a number
|
||||
@sa @ref is_number_unsigned() -- check if value is an unsigned integer number
|
||||
@sa @ref is_number_unsigned() -- check if value is an unsigned integer
|
||||
number
|
||||
@sa @ref is_number_float() -- check if value is a floating-point number
|
||||
|
||||
@since version 1.0.0
|
||||
@ -2219,19 +2221,19 @@ class basic_json
|
||||
{
|
||||
return m_type == value_t::number_integer or m_type == value_t::number_unsigned;
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
@brief return whether value is an unsigned integer number
|
||||
|
||||
This function returns true iff the JSON value is an unsigned integer number.
|
||||
This excludes floating-point and (signed) integer values.
|
||||
This function returns true iff the JSON value is an unsigned integer
|
||||
number. This excludes floating-point and (signed) integer values.
|
||||
|
||||
@return `true` if type is an unsigned integer number, `false` otherwise.
|
||||
|
||||
@complexity Constant.
|
||||
|
||||
@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
|
||||
@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_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
|
||||
*/
|
||||
@ -2525,7 +2528,7 @@ class basic_json
|
||||
{
|
||||
return static_cast<T>(m_value.number_integer);
|
||||
}
|
||||
|
||||
|
||||
case value_t::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;
|
||||
}
|
||||
|
||||
|
||||
/// get a pointer to the value (unsigned number)
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
/// get a pointer to the value (floating-point number)
|
||||
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.
|
||||
|
||||
@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.
|
||||
|
||||
@return pointer to the internally stored JSON value if the requested
|
||||
@ -2776,7 +2779,7 @@ class basic_json
|
||||
state.
|
||||
|
||||
@tparam PointerType pointer type; must be a pointer to @ref array_t, @ref
|
||||
object_t, @ref string_t, @ref boolean_t, @ref number_integer_t,
|
||||
object_t, @ref string_t, @ref boolean_t, @ref number_integer_t,
|
||||
@ref number_unsigned_t, or @ref number_float_t.
|
||||
|
||||
@return pointer to the internally stored JSON value if the requested
|
||||
@ -2895,14 +2898,14 @@ class basic_json
|
||||
|
||||
@since version 1.0.0
|
||||
*/
|
||||
template<typename ValueType, typename
|
||||
std::enable_if<
|
||||
not std::is_pointer<ValueType>::value
|
||||
and not std::is_same<ValueType, typename string_t::value_type>::value
|
||||
template < typename ValueType, typename
|
||||
std::enable_if <
|
||||
not std::is_pointer<ValueType>::value
|
||||
and not std::is_same<ValueType, typename string_t::value_type>::value
|
||||
#ifndef _MSC_VER // Fix for issue #167 operator<< abiguity under VS2015
|
||||
and not std::is_same<ValueType, std::initializer_list<typename string_t::value_type>>::value
|
||||
and not std::is_same<ValueType, std::initializer_list<typename string_t::value_type>>::value
|
||||
#endif
|
||||
, int>::type = 0>
|
||||
, int >::type = 0 >
|
||||
operator ValueType() 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
|
||||
|
||||
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.
|
||||
|
||||
@param[in] source the value to cast from
|
||||
@param[in] source the value to cast from
|
||||
|
||||
@param[out] dest the value to cast to
|
||||
|
||||
@return @a true if the cast was performed without error, @a false otherwise
|
||||
*/
|
||||
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);
|
||||
return (source == static_cast<T_A>(dest));
|
||||
@ -7409,74 +7412,101 @@ class basic_json
|
||||
/*!
|
||||
@brief return number value for number tokens
|
||||
|
||||
This function translates the last token into the most appropriate
|
||||
number type (either integer, unsigned integer or floating point),
|
||||
which is passed back to the caller via the result parameter. The pointer
|
||||
@a m_start points to the beginning of the parsed number. We first examine
|
||||
This function translates the last token into the most appropriate
|
||||
number type (either integer, unsigned integer or floating point), which
|
||||
is passed back to the caller via the result parameter. The pointer @a
|
||||
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
|
||||
this pointer to either @a std::strtoull (if positive) or @a std::strtoll
|
||||
(if negative), both of which set @a endptr to the first character past the
|
||||
converted number. If this pointer is not the same as @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
|
||||
inputs like "12e3" will be incorrectly read as 12. Numbers that are too
|
||||
this pointer to either @a std::strtoull (if positive) or @a
|
||||
std::strtoll (if negative), both of which set @a endptr to the first
|
||||
character past the converted number. If this pointer is not the same as
|
||||
@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
|
||||
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
|
||||
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,
|
||||
which returns @a false if the cast could not be peformed without error.
|
||||
number_integer_t/@ref number_unsigned_t using the helper function @ref
|
||||
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
|
||||
error) the pointer is passed to @a std:strtod, which also sets @a endptr to the
|
||||
first character past the converted number. The resulting @ref number_float_t
|
||||
is then cast to a @ref number_integer_t/@ref number_unsigned_t using
|
||||
@ref attempt_cast and if no error occurs is 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.
|
||||
error) the pointer is passed to @a std:strtod, which also sets @a
|
||||
endptr to the first character past the converted number. The resulting
|
||||
@ref number_float_t is then cast to a @ref number_integer_t/@ref
|
||||
number_unsigned_t using @ref attempt_cast and if no error occurs is
|
||||
stored in that form, otherwise it is stored as a @ref number_float_t.
|
||||
|
||||
@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.
|
||||
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 conversion read past the current token. The latter case needs to
|
||||
be treated by the caller function.
|
||||
*/
|
||||
void get_number(basic_json& result) const
|
||||
{
|
||||
typename string_t::value_type* endptr;
|
||||
assert(m_start != nullptr);
|
||||
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) != '-')
|
||||
{
|
||||
// Positive, parse with strtoull and attempt cast to number_unsigned_t
|
||||
if (attempt_cast(std::strtoull(reinterpret_cast<typename string_t::const_pointer>(m_start), &endptr, 10), result.m_value.number_unsigned))
|
||||
// positive, parse with strtoull and attempt cast to
|
||||
// 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;
|
||||
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
|
||||
{
|
||||
// Negative, parse with strtoll and attempt cast to number_integer_t
|
||||
if (attempt_cast(std::strtoll(reinterpret_cast<typename string_t::const_pointer>(m_start), &endptr, 10), result.m_value.number_unsigned))
|
||||
// Negative, parse with strtoll and attempt cast to
|
||||
// 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;
|
||||
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
|
||||
if (reinterpret_cast<lexer_char_t*>(endptr) != m_cursor || errno == ERANGE) result.m_type = value_t::number_float;
|
||||
// check the end of the number was reached and no range error
|
||||
// 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)
|
||||
{
|
||||
// Either the number won't fit in an integer (range error from strtoull/strtoll or overflow on cast) or there was
|
||||
// something else after the number, which could be an exponent
|
||||
|
||||
// Parse with strtod
|
||||
// either the number won't fit in an integer (range error from
|
||||
// strtoull/strtoll or overflow on cast) or there was something
|
||||
// else after the number, which could be an exponent
|
||||
|
||||
// parse with strtod
|
||||
result.m_value.number_float = str_to_float_t(static_cast<number_float_t*>(nullptr), &endptr);
|
||||
|
||||
// Anything after the number is an error
|
||||
if(reinterpret_cast<lexer_char_t*>(endptr) != m_cursor)
|
||||
// anything after the number is an error
|
||||
if (reinterpret_cast<lexer_char_t*>(endptr) != m_cursor)
|
||||
{
|
||||
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
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user