Skip to content

Commit

Permalink
Merge pull request #1722 from t-b/fix-int64-min-issue
Browse files Browse the repository at this point in the history
Fix int64 min issue
  • Loading branch information
nlohmann authored Sep 10, 2019
2 parents a6bd798 + 8067c3c commit 06ccd43
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 2 deletions.
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
{
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 @@ -14267,7 +14267,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 @@ -14448,6 +14448,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));
}
}

0 comments on commit 06ccd43

Please sign in to comment.