diff --git a/include/nlohmann/detail/output/serializer.hpp b/include/nlohmann/detail/output/serializer.hpp index e6811ceb..0a4ddbda 100644 --- a/include/nlohmann/detail/output/serializer.hpp +++ b/include/nlohmann/detail/output/serializer.hpp @@ -630,7 +630,7 @@ class serializer if (is_negative) { *buffer_ptr = '-'; - abs_value = static_cast(std::abs(static_cast(x))); + abs_value = remove_sign(x); // account one more byte for the minus sign n_chars = 1 + count_digits(abs_value); @@ -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::max)()); + return static_cast(-(x + 1)) + 1; + } + private: /// the output of the serializer output_adapter_t o = nullptr; diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 2a32a829..a9f00a94 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -14264,7 +14264,7 @@ class serializer if (is_negative) { *buffer_ptr = '-'; - abs_value = static_cast(std::abs(static_cast(x))); + abs_value = remove_sign(x); // account one more byte for the minus sign n_chars = 1 + count_digits(abs_value); @@ -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::max)()); + return static_cast(-(x + 1)) + 1; + } + private: /// the output of the serializer output_adapter_t o = nullptr;