mirror of
https://github.com/nlohmann/json.git
synced 2026-10-15 10:47:13 +00:00
Allow the same type for number_integer_t and number_unsigned_t
basic_json did not compile with NumberUnsignedType == NumberIntegerType because overloads on both types collided. Such a basic_json now stores every integer as number_integer: the colliding overloads take a placeholder type, unsigned C++ integers are converted to number_integer_t, and value_t::number_unsigned maps to number_integer. Also fixes two problems this configuration would hit: the unsigned integer parser accepted values that wrap around to negative numbers, and dump() overflowed when computing the absolute value of the minimum. A repeated NumberFloatType gets a static_assert. Refs #2573 Signed-off-by: Niels Lohmann <mail@nlohmann.me>
This commit is contained in:
13 files changed
+430
-85
No files matched your search
@@ -500,8 +500,22 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
"NumberUnsignedType must be at least as wide as NumberIntegerType, "
|
||||
"because it has to hold the absolute value of every NumberIntegerType value");
|
||||
|
||||
// NumberUnsignedType may be the same type as NumberIntegerType (#2573), but
|
||||
// a repeated NumberFloatType would give overloads that collide, so it gets
|
||||
// a readable diagnostic instead.
|
||||
static_assert(!std::is_same<NumberFloatType, NumberIntegerType>::value && !std::is_same<NumberFloatType, NumberUnsignedType>::value,
|
||||
"NumberFloatType must be a different type than NumberIntegerType and NumberUnsignedType");
|
||||
|
||||
private:
|
||||
|
||||
/// the kind a value of kind @a t is stored as: if number_unsigned_t is the
|
||||
/// same type as number_integer_t, every integer is stored as number_integer
|
||||
/// (#2573); every other kind is stored as itself
|
||||
static constexpr value_t stored_kind(const value_t t) noexcept
|
||||
{
|
||||
return (std::is_same<number_integer_t, number_unsigned_t>::value && t == value_t::number_unsigned) ? value_t::number_integer : t;
|
||||
}
|
||||
|
||||
/// helper for exception-safe object creation
|
||||
template<typename T, typename... Args>
|
||||
JSON_HEDLEY_RETURNS_NON_NULL
|
||||
@@ -575,8 +589,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
json_value(boolean_t v) noexcept : boolean(v) {}
|
||||
/// constructor for numbers (integer)
|
||||
json_value(number_integer_t v) noexcept : number_integer(v) {}
|
||||
/// constructor for numbers (unsigned)
|
||||
json_value(number_unsigned_t v) noexcept : number_unsigned(v) {}
|
||||
/// constructor for numbers (unsigned); takes a placeholder if number_unsigned_t is number_integer_t
|
||||
json_value(detail::number_unsigned_overload_t<basic_json> v) noexcept : number_unsigned(v) {}
|
||||
/// constructor for numbers (floating-point)
|
||||
json_value(number_float_t v) noexcept : number_float(v) {}
|
||||
/// constructor for empty values of a given type
|
||||
@@ -2181,7 +2195,7 @@ public:
|
||||
/// @brief create an empty value with a given type
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/basic_json/
|
||||
basic_json(const value_t v)
|
||||
: m_data(v)
|
||||
: m_data(stored_kind(v))
|
||||
{
|
||||
assert_invariant();
|
||||
}
|
||||
@@ -2262,7 +2276,7 @@ public:
|
||||
{
|
||||
convert_leaf(val);
|
||||
}
|
||||
JSON_ASSERT(m_data.m_type == val.type());
|
||||
JSON_ASSERT(m_data.m_type == stored_kind(val.type()));
|
||||
|
||||
set_parents();
|
||||
assert_invariant();
|
||||
@@ -2847,14 +2861,16 @@ public:
|
||||
return m_data.m_type == value_t::number_integer ? &m_data.m_value.number_integer : nullptr;
|
||||
}
|
||||
|
||||
/// get a pointer to the value (unsigned number)
|
||||
number_unsigned_t* get_impl_ptr(number_unsigned_t* /*unused*/) noexcept
|
||||
/// get a pointer to the value (unsigned number); takes a placeholder if
|
||||
/// number_unsigned_t is number_integer_t (the integer overload handles it then)
|
||||
number_unsigned_t* get_impl_ptr(detail::number_unsigned_overload_t<basic_json>* /*unused*/) noexcept
|
||||
{
|
||||
return is_number_unsigned() ? &m_data.m_value.number_unsigned : nullptr;
|
||||
}
|
||||
|
||||
/// get a pointer to the value (unsigned number)
|
||||
constexpr const number_unsigned_t* get_impl_ptr(const number_unsigned_t* /*unused*/) const noexcept
|
||||
/// get a pointer to the value (unsigned number); takes a placeholder if
|
||||
/// number_unsigned_t is number_integer_t (the integer overload handles it then)
|
||||
constexpr const number_unsigned_t* get_impl_ptr(const detail::number_unsigned_overload_t<basic_json>* /*unused*/) const noexcept
|
||||
{
|
||||
return is_number_unsigned() ? &m_data.m_value.number_unsigned : nullptr;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user