Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix int64 min issue #1722

Merged
merged 3 commits into from
Sep 10, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 27 additions & 1 deletion include/nlohmann/detail/output/serializer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -630,7 +630,7 @@ class serializer
if (is_negative)
{
*buffer_ptr = '-';
abs_value = static_cast<number_unsigned_t>(std::abs(static_cast<std::intmax_t>(x)));
abs_value = remove_sign(x);

// account one more byte for the minus sign
n_chars = 1 + count_digits(abs_value);
Expand Down Expand Up @@ -811,6 +811,32 @@ class serializer
return state;
}

/*
* Overload to make the compiler happy while it is instantiating
* dump_integer for number_unsigned_t.
* Must never be called.
*/
number_unsigned_t remove_sign(number_unsigned_t x)
{
assert(false); // LCOV_EXCL_LINE
return x; // LCOV_EXCL_LINE
}

/*
* Helper function for dump_integer
*
* This function takes a negative signed integer and returns its absolute
* value as unsigned integer. The plus/minus shuffling is necessary as we can
* not directly remove the sign of an arbitrary signed integer as the
* absolute values of INT_MIN and INT_MAX are usually not the same. See
* #1708 for details.
*/
inline number_unsigned_t remove_sign(number_integer_t x) noexcept
t-b marked this conversation as resolved.
Show resolved Hide resolved
{
assert(x < 0 and x < (std::numeric_limits<number_integer_t>::max)());
return static_cast<number_unsigned_t>(-(x + 1)) + 1;
}

private:
/// the output of the serializer
output_adapter_t<char> o = nullptr;
Expand Down
28 changes: 27 additions & 1 deletion single_include/nlohmann/json.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -14264,7 +14264,7 @@ class serializer
if (is_negative)
{
*buffer_ptr = '-';
abs_value = static_cast<number_unsigned_t>(std::abs(static_cast<std::intmax_t>(x)));
abs_value = remove_sign(x);

// account one more byte for the minus sign
n_chars = 1 + count_digits(abs_value);
Expand Down Expand Up @@ -14445,6 +14445,32 @@ class serializer
return state;
}

/*
* Overload to make the compiler happy while it is instantiating
* dump_integer for number_unsigned_t.
* Must never be called.
*/
number_unsigned_t remove_sign(number_unsigned_t x)
{
assert(false); // LCOV_EXCL_LINE
return x; // LCOV_EXCL_LINE
}

/*
* Helper function for dump_integer
*
* This function takes a negative signed integer and returns its absolute
* value as unsigned integer. The plus/minus shuffling is necessary as we can
* not directly remove the sign of an arbitrary signed integer as the
* absolute values of INT_MIN and INT_MAX are usually not the same. See
* #1708 for details.
*/
inline number_unsigned_t remove_sign(number_integer_t x) noexcept
{
assert(x < 0 and x < (std::numeric_limits<number_integer_t>::max)());
return static_cast<number_unsigned_t>(-(x + 1)) + 1;
}

private:
/// the output of the serializer
output_adapter_t<char> o = nullptr;
Expand Down
7 changes: 7 additions & 0 deletions test/src/unit-regression.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1802,6 +1802,13 @@ TEST_CASE("regression tests")
json j = json::parse("[-9223372036854775808]");
CHECK(j.dump() == "[-9223372036854775808]");
}

SECTION("issue #1708 - minimum value of int64_t can be outputted")
{
constexpr auto smallest = (std::numeric_limits<int64_t>::min)();
json j = smallest;
CHECK(j.dump() == std::to_string(smallest));
}
}

#if not defined(JSON_NOEXCEPTION)
Expand Down
17 changes: 17 additions & 0 deletions test/src/unit-serialization.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -189,3 +189,20 @@ TEST_CASE("serialization")
test("[3,\"false\",false]", "[3,\\\"false\\\",false]");
}
}

TEST_CASE_TEMPLATE("serialization for extreme integer values", T, int32_t, uint32_t, int64_t, uint64_t)
{
SECTION("minimum")
{
constexpr auto minimum = (std::numeric_limits<T>::min)();
json j = minimum;
CHECK(j.dump() == std::to_string(minimum));
}

SECTION("maximum")
{
constexpr auto maximum = (std::numeric_limits<T>::max)();
json j = maximum;
CHECK(j.dump() == std::to_string(maximum));
}
}