Skip to content

Commit

Permalink
Merge pull request #71 from cppalliance/sign-comp
Browse files Browse the repository at this point in the history
Fix signed-unsigned conversions
  • Loading branch information
mborland authored Aug 14, 2023
2 parents ba0a7e4 + 38cfa0e commit 2ae9e5a
Show file tree
Hide file tree
Showing 14 changed files with 89 additions and 63 deletions.
2 changes: 1 addition & 1 deletion include/boost/charconv/detail/compute_float64.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ inline double compute_float64(std::int64_t power, std::uint64_t i, bool negative
}

significand &= ~(UINT64_C(1) << 52);
const std::uint64_t real_exponent = exponent - leading_zeros;
const auto real_exponent = static_cast<std::uint64_t>(exponent - leading_zeros);

// We have to check that real_exponent is in range, otherwise fail
if (BOOST_UNLIKELY((real_exponent < 1) || (real_exponent > 2046)))
Expand Down
6 changes: 4 additions & 2 deletions include/boost/charconv/detail/dragonbox/dragonbox_common.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -302,9 +302,11 @@ struct signed_significand_bits
// Some simple utilities for constexpr computation.
////////////////////////////////////////////////////////////////////////////////////////

template <class Int>
BOOST_CHARCONV_CXX14_CONSTEXPR Int compute_power(Int a, unsigned exp) noexcept
template <class Int, class Int2>
BOOST_CHARCONV_CXX14_CONSTEXPR Int compute_power(Int a, Int2 exp) noexcept
{
BOOST_CHARCONV_ASSERT(exp >= 0);

Int res = 1;
while (exp > 0)
{
Expand Down
57 changes: 38 additions & 19 deletions include/boost/charconv/detail/dragonbox/floff.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -176,18 +176,18 @@ struct fixed_point_calculator
switch (number_of_blocks)
{
case 3:
mul_result = umul128(blocks_ptr[2], multiplier);
mul_result = umul128(blocks_ptr[2], static_cast<std::uint64_t>(multiplier));
carry = mul_result.high;
BOOST_FALLTHROUGH;

case 2:
mul_result = umul128(blocks_ptr[1], multiplier);
mul_result = umul128(blocks_ptr[1], static_cast<std::uint64_t>(multiplier));
mul_result += carry;
carry = mul_result.high;
BOOST_FALLTHROUGH;

case 1:
mul_result = umul128(blocks_ptr[0], multiplier);
mul_result = umul128(blocks_ptr[0], static_cast<std::uint64_t>(multiplier));
mul_result += carry;
return static_cast<MultiplierType>(mul_result.high);

Expand All @@ -196,11 +196,11 @@ struct fixed_point_calculator
}
}

auto mul_result = umul128(blocks_ptr[number_of_blocks - 1], multiplier);
auto mul_result = umul128(blocks_ptr[number_of_blocks - 1], static_cast<std::uint64_t>(multiplier));
auto carry = mul_result.high;
for (std::size_t i = 1; i < number_of_blocks; ++i)
{
mul_result = umul128(blocks_ptr[number_of_blocks - i - 1], multiplier);
mul_result = umul128(blocks_ptr[number_of_blocks - i - 1], static_cast<std::uint64_t>(multiplier));
mul_result += carry;
carry = mul_result.high;
}
Expand Down Expand Up @@ -361,7 +361,7 @@ BOOST_FORCEINLINE std::uint8_t load_extended_cache(CacheBlockType* blocks_ptr, i
std::memset(blocks_ptr, 0, number_of_leading_zero_blocks * sizeof(CacheBlockType));
}

start_bit_index += number_of_leading_zero_blocks * static_cast<int>(ExtendedCache::cache_bits_unit);
start_bit_index += static_cast<int>(number_of_leading_zero_blocks * ExtendedCache::cache_bits_unit);

const auto src_start_block_index =
static_cast<int>(static_cast<std::uint32_t>(src_start_bit_index) /
Expand All @@ -370,7 +370,7 @@ BOOST_FORCEINLINE std::uint8_t load_extended_cache(CacheBlockType* blocks_ptr, i
const auto src_start_block_bit_index =
src_start_block_index * static_cast<int>(ExtendedCache::cache_bits_unit);

first_cache_block_index = src_start_block_index;
first_cache_block_index = static_cast<std::uint32_t>(src_start_block_index);

if (start_bit_index < src_start_block_bit_index)
{
Expand Down Expand Up @@ -404,8 +404,8 @@ BOOST_FORCEINLINE std::uint8_t load_extended_cache(CacheBlockType* blocks_ptr, i
// If the request window goes further than the right boundary of the source window,
if (end_bit_index > src_end_bit_index)
{
const auto number_of_trailing_zero_blocks =
static_cast<std::uint8_t>(end_bit_index - src_end_bit_index / ExtendedCache::cache_bits_unit);
const std::uint8_t number_of_trailing_zero_blocks =
static_cast<std::uint8_t>(end_bit_index - src_end_bit_index) / ExtendedCache::cache_bits_unit;
excessive_bits_to_right = static_cast<std::uint32_t>(end_bit_index - src_end_bit_index) %
static_cast<std::uint32_t>(ExtendedCache::cache_bits_unit);

Expand Down Expand Up @@ -493,8 +493,8 @@ BOOST_FORCEINLINE std::uint8_t load_extended_cache(CacheBlockType* blocks_ptr, i
// To compute ceil(2^Q * x / D), we need to check if
// 2^Q * x / D = 2^(Q + e + k - eta - 1) * 5^(k - eta) is an integer or not.
if (k < ExtendedCache::segment_length ||
e + k + cache_block_count * static_cast<int>(ExtendedCache::cache_bits_unit) -
excessive_bits_to_right <
e + k + static_cast<int>(cache_block_count * ExtendedCache::cache_bits_unit) -
static_cast<int>(excessive_bits_to_right) <
ExtendedCache::segment_length + 1) {
blocks_ptr[cache_block_count - 1] += (CacheBlockType(1) << excessive_bits_to_right);
BOOST_CHARCONV_ASSERT(blocks_ptr[cache_block_count - 1] != 0);
Expand Down Expand Up @@ -545,6 +545,17 @@ BOOST_INLINE_VARIABLE constexpr uconst<9> uconst9;
BOOST_INLINE_VARIABLE constexpr uconst<14> uconst14;
BOOST_INLINE_VARIABLE constexpr uconst<16> uconst16;

#ifdef __clang__
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wsign-conversion"
#elif defined(__GNUC__)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wsign-conversion"
#elif defined(BOOST_MSVC)
# pragma warning(push)
# pragma warning(disable: 4365 4267)
#endif

template <unsigned digits, bool dummy = (digits <= 9)>
struct uint_with_known_number_of_digits;

Expand Down Expand Up @@ -647,6 +658,14 @@ static BOOST_FORCEINLINE bool check_rounding_condition_subsegment_boundary_with_
((current_digits & 1) != 0 || has_further_digits(args...));
}

#ifdef __clang__
# pragma clang diagnostic pop
#elif defined(__GNUC__)
# pragma GCC diagnostic pop
#elif defined(BOOST_MSVC)
# pragma warning(pop)
#endif

#ifdef BOOST_MSVC
# pragma warning(push)
# pragma warning(disable: 4307) // MSVC 14.1 emits warnings for uint64_t constants
Expand Down Expand Up @@ -1362,7 +1381,7 @@ BOOST_CHARCONV_SAFEBUFFERS char* floff(const double x, const int precision, char
else
{
std::memcpy(buffer, "0.", 2); // NOLINT : Specifically not null-terminating
std::memset(buffer + 2, '0', precision); // NOLINT : Specifically not null-terminating
std::memset(buffer + 2, '0', static_cast<std::size_t>(precision)); // NOLINT : Specifically not null-terminating
std::memcpy(buffer + 2 + precision, "e+00", 2); // NOLINT : Specifically not null-terminating
return buffer + precision + 4;
}
Expand Down Expand Up @@ -2240,7 +2259,7 @@ BOOST_CHARCONV_SAFEBUFFERS char* floff(const double x, const int precision, char
// Convert subsegment into fixed-point fractional form where the
// integer part is of one digit. The integer part is ignored.
// 42949673 = ceil(2^32/10^2)
auto prod = subsegment * UINT64_C(42949673);
auto prod = static_cast<std::uint64_t>(subsegment) * UINT64_C(42949673);

if (remaining_digits == 1)
{
Expand Down Expand Up @@ -2278,7 +2297,7 @@ BOOST_CHARCONV_SAFEBUFFERS char* floff(const double x, const int precision, char
// Convert subsegment into fixed-point fractional form where the
// integer part is of two digits. The integer part is ignored.
// 429496730 = ceil(2^32/10^1)
auto prod = subsegment * UINT64_C(429496730);
auto prod = static_cast<std::uint64_t>(subsegment) * UINT64_C(429496730);
prod = static_cast<std::uint32_t>(prod) * UINT64_C(10);
const auto next_digits = static_cast<std::uint32_t>(prod >> 32);

Expand Down Expand Up @@ -3736,7 +3755,7 @@ BOOST_CHARCONV_SAFEBUFFERS char* floff(const double x, const int precision, char
fill_remaining_digits_with_0s:
if (fmt != boost::charconv::chars_format::general)
{
std::memset(buffer, '0', remaining_digits);
std::memset(buffer, '0', static_cast<std::size_t>(remaining_digits));
buffer += remaining_digits;
}

Expand Down Expand Up @@ -3773,15 +3792,15 @@ BOOST_CHARCONV_SAFEBUFFERS char* floff(const double x, const int precision, char
// 6554 = ceil(2^16 / 10)
auto prod = static_cast<std::uint32_t>(decimal_exponent) * UINT32_C(6554);
auto d1 = prod >> 16;
prod = static_cast<std::uint16_t>(prod) * UINT32_C(5); // * 10
prod = static_cast<std::uint16_t>(prod) * UINT16_C(5); // * 10
auto d2 = prod >> 15; // >> 16
print_2_digits(d1, buffer);
print_1_digit(d2, buffer + 2);
buffer += 3;
}
else
{
print_2_digits(decimal_exponent, buffer);
print_2_digits(static_cast<std::uint32_t>(decimal_exponent), buffer);
buffer += 2;
}

Expand Down Expand Up @@ -3852,7 +3871,7 @@ BOOST_CHARCONV_SAFEBUFFERS char* floff(const double x, const int precision, char
}

++*(first_9_pos - 1);
std::memset(first_9_pos, '0', buffer - first_9_pos);
std::memset(first_9_pos, '0', static_cast<std::size_t>(buffer - first_9_pos));

goto insert_decimal_dot;
}
Expand All @@ -3866,7 +3885,7 @@ BOOST_CHARCONV_SAFEBUFFERS char* floff(const double x, const int precision, char

// Nolint is applied to the following two calls since we know they are not supposed to be null terminated
std::memcpy(buffer_starting_pos, "1.", 2); // NOLINT
std::memset(buffer_starting_pos + 2, '0', buffer - buffer_starting_pos - 2); // NOLINT
std::memset(buffer_starting_pos + 2, '0', static_cast<std::size_t>(buffer - buffer_starting_pos - 2)); // NOLINT

goto print_exponent_and_return;
}
Expand Down
2 changes: 1 addition & 1 deletion include/boost/charconv/detail/from_chars_float_impl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ inline from_chars_result from_chars_strtod(const char* first, const char* last,
// If the string to be parsed does not fit into the 1024 byte static buffer than we have to allocate a buffer.
// malloc is used here because it does not throw on allocation failure.

char* buffer = static_cast<char*>(std::malloc(last - first + 1));
char* buffer = static_cast<char*>(std::malloc(static_cast<std::size_t>(last - first + 1)));
if (buffer == nullptr)
{
return {first, std::errc::not_enough_memory};
Expand Down
2 changes: 1 addition & 1 deletion include/boost/charconv/detail/from_chars_integer_impl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ BOOST_CXX14_CONSTEXPR from_chars_result from_chars_integer_impl(const char* firs
{
if (is_negative)
{
value = -(static_cast<Unsigned_Integer>(value));
value = static_cast<Integer>(-(static_cast<Unsigned_Integer>(value)));
}
}

Expand Down
13 changes: 7 additions & 6 deletions include/boost/charconv/detail/parser.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ inline from_chars_result parser(const char* first, const char* last, bool& sign,
}
if (dot_position != 0 || fractional)
{
exponent = static_cast<Integer>(dot_position) - i + extra_zeros + leading_zero_powers;
exponent = static_cast<Integer>(dot_position - i) + extra_zeros + leading_zero_powers;
}
else
{
Expand Down Expand Up @@ -252,7 +252,7 @@ inline from_chars_result parser(const char* first, const char* last, bool& sign,
return {first, std::errc::invalid_argument};
}

exponent = i - 1;
exponent = static_cast<Integer>(i - 1);
std::size_t offset = i;
bool round = false;
// If more digits are present than representable in the significand of the target type
Expand Down Expand Up @@ -303,7 +303,7 @@ inline from_chars_result parser(const char* first, const char* last, bool& sign,
// Finally we get the exponent
constexpr std::size_t exponent_buffer_size = 6; // Float128 min exp is −16382
char exponent_buffer[exponent_buffer_size] {};
Integer significand_digits = i;
const auto significand_digits = i;
i = 0;

// Get the sign first
Expand Down Expand Up @@ -343,7 +343,7 @@ inline from_chars_result parser(const char* first, const char* last, bool& sign,
{
if (fractional)
{
exponent = static_cast<Integer>(dot_position) - significand_digits;
exponent = static_cast<Integer>(dot_position - significand_digits);
}
else
{
Expand Down Expand Up @@ -371,17 +371,18 @@ inline from_chars_result parser(const char* first, const char* last, bool& sign,
if (fmt == chars_format::hex)
{
// In hex the number of digits parsed is possibly less than the number of digits in base10
exponent -= num_digits(significand) - dot_position;
exponent -= num_digits(significand) - static_cast<Integer>(dot_position);
}
else
{
exponent -= significand_digits - dot_position;
exponent -= static_cast<Integer>(significand_digits - dot_position);
}
}
else
{
exponent += extra_zeros;
}

return {next, std::errc()};
}
}
Expand Down
25 changes: 14 additions & 11 deletions include/boost/charconv/detail/to_chars_integer_impl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -106,12 +106,12 @@ BOOST_CHARCONV_CONSTEXPR to_chars_result to_chars_integer_impl(char* first, char
}
else
{
unsigned_value = value;
unsigned_value = static_cast<Unsigned_Integer>(value);
}
}
else
{
unsigned_value = value;
unsigned_value = static_cast<Unsigned_Integer>(value);
}

// If the type is less than 32 bits we can use this without change
Expand Down Expand Up @@ -139,7 +139,8 @@ BOOST_CHARCONV_CONSTEXPR to_chars_result to_chars_integer_impl(char* first, char
*first++ = '-';
}

boost::charconv::detail::memcpy(first, buffer + (sizeof(buffer) - converted_value_digits), converted_value_digits);
boost::charconv::detail::memcpy(first, buffer + (sizeof(buffer) - static_cast<unsigned>(converted_value_digits)),
static_cast<std::size_t>(converted_value_digits));
}
else if (std::numeric_limits<Integer>::digits <= std::numeric_limits<std::uint64_t>::digits ||
static_cast<std::uint64_t>(unsigned_value) <= (std::numeric_limits<std::uint64_t>::max)())
Expand All @@ -165,7 +166,8 @@ BOOST_CHARCONV_CONSTEXPR to_chars_result to_chars_integer_impl(char* first, char
const int first_value_chars = num_digits(x);

decompose32(x, buffer);
boost::charconv::detail::memcpy(first, buffer + (sizeof(buffer) - first_value_chars), first_value_chars);
boost::charconv::detail::memcpy(first, buffer + (sizeof(buffer) - static_cast<unsigned>(first_value_chars)),
static_cast<std::size_t>(first_value_chars));

decompose32(y, buffer);
boost::charconv::detail::memcpy(first + first_value_chars, buffer + 1, sizeof(buffer) - 1);
Expand Down Expand Up @@ -240,13 +242,13 @@ BOOST_CHARCONV_CONSTEXPR to_chars_result to_chars_128integer_impl(char* first, c
}
else
{
unsigned_value = value;
unsigned_value = static_cast<Unsigned_Integer>(value);
}
}
else
#endif
{
unsigned_value = value;
unsigned_value = static_cast<Unsigned_Integer>(value);
}

auto converted_value = static_cast<Unsigned_Integer>(unsigned_value);
Expand Down Expand Up @@ -284,8 +286,8 @@ BOOST_CHARCONV_CONSTEXPR to_chars_result to_chars_128integer_impl(char* first, c
}

--i;
boost::charconv::detail::memcpy(first, buffer[i] + 10 - num_chars[i], num_chars[i]);
std::size_t offset = num_chars[i];
auto offset = static_cast<std::size_t>(num_chars[i]);
boost::charconv::detail::memcpy(first, buffer[i] + 10 - offset, offset);

while (i > 0)
{
Expand Down Expand Up @@ -327,12 +329,12 @@ BOOST_CHARCONV_CONSTEXPR to_chars_result to_chars_integer_impl(char* first, char
}
else
{
unsigned_value = value;
unsigned_value = static_cast<Unsigned_Integer>(value);
}
}
else
{
unsigned_value = value;
unsigned_value = static_cast<Unsigned_Integer>(value);
}

constexpr Unsigned_Integer zero = 48U; // Char for '0'
Expand Down Expand Up @@ -400,7 +402,8 @@ BOOST_CHARCONV_CONSTEXPR to_chars_result to_chars_integer_impl(char* first, char
return {last, std::errc::result_out_of_range};
}

boost::charconv::detail::memcpy(first, buffer + (buffer_size - num_chars), num_chars);
boost::charconv::detail::memcpy(first, buffer + (buffer_size - static_cast<unsigned long>(num_chars)),
static_cast<std::size_t>(num_chars));

return {first + num_chars, std::errc()};
}
Expand Down
3 changes: 2 additions & 1 deletion include/boost/charconv/to_chars.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -455,7 +455,8 @@ to_chars_result to_chars_float_impl(char* first, char* last, Real value, chars_f
// Bounds check
if (value_struct.exponent < 0 && -value_struct.exponent < buffer_size)
{
std::memmove(r.ptr + value_struct.exponent + 1, r.ptr + value_struct.exponent, -value_struct.exponent);
std::memmove(r.ptr + value_struct.exponent + 1, r.ptr + value_struct.exponent,
static_cast<std::size_t>(-value_struct.exponent));
std::memset(r.ptr + value_struct.exponent, '.', 1);
++r.ptr;
}
Expand Down
Loading

0 comments on commit 2ae9e5a

Please sign in to comment.