Skip to content

Commit

Permalink
Merge pull request #168 from boostorg/166.2
Browse files Browse the repository at this point in the history
Fix for issue #166 negative precision
  • Loading branch information
mborland authored Feb 22, 2024
2 parents 1e8e3a7 + 340a72e commit 317e04f
Show file tree
Hide file tree
Showing 5 changed files with 326 additions and 129 deletions.
43 changes: 34 additions & 9 deletions include/boost/charconv/to_chars.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,36 +78,61 @@ BOOST_CHARCONV_CONSTEXPR to_chars_result to_chars(char* first, char* last, boost
//----------------------------------------------------------------------------------------------------------------------

BOOST_CHARCONV_DECL to_chars_result to_chars(char* first, char* last, float value,
chars_format fmt = chars_format::general, int precision = -1 ) noexcept;
chars_format fmt = chars_format::general) noexcept;
BOOST_CHARCONV_DECL to_chars_result to_chars(char* first, char* last, double value,
chars_format fmt = chars_format::general) noexcept;
BOOST_CHARCONV_DECL to_chars_result to_chars(char* first, char* last, long double value,
chars_format fmt = chars_format::general) noexcept;

BOOST_CHARCONV_DECL to_chars_result to_chars(char* first, char* last, float value,
chars_format fmt, int precision) noexcept;
BOOST_CHARCONV_DECL to_chars_result to_chars(char* first, char* last, double value,
chars_format fmt = chars_format::general, int precision = -1 ) noexcept;
chars_format fmt, int precision) noexcept;
BOOST_CHARCONV_DECL to_chars_result to_chars(char* first, char* last, long double value,
chars_format fmt = chars_format::general, int precision = -1 ) noexcept;
chars_format fmt, int precision) noexcept;

#ifdef BOOST_CHARCONV_HAS_FLOAT128
BOOST_CHARCONV_DECL to_chars_result to_chars(char* first, char* last, __float128 value,
chars_format fmt = chars_format::general, int precision = -1 ) noexcept;
chars_format fmt = chars_format::general) noexcept;

BOOST_CHARCONV_DECL to_chars_result to_chars(char* first, char* last, __float128 value,
chars_format fmt, int precision) noexcept;
#endif

#ifdef BOOST_CHARCONV_HAS_FLOAT16
BOOST_CHARCONV_DECL to_chars_result to_chars(char* first, char* last, std::float16_t value,
chars_format fmt = chars_format::general) noexcept;

BOOST_CHARCONV_DECL to_chars_result to_chars(char* first, char* last, std::float16_t value,
chars_format fmt = chars_format::general, int precision = -1 ) noexcept;
chars_format fmt, int precision) noexcept;
#endif
#ifdef BOOST_CHARCONV_HAS_FLOAT32
BOOST_CHARCONV_DECL to_chars_result to_chars(char* first, char* last, std::float32_t value,
chars_format fmt = chars_format::general) noexcept;

BOOST_CHARCONV_DECL to_chars_result to_chars(char* first, char* last, std::float32_t value,
chars_format fmt = chars_format::general, int precision = -1 ) noexcept;
chars_format fmt, int precision) noexcept;
#endif
#ifdef BOOST_CHARCONV_HAS_FLOAT64
BOOST_CHARCONV_DECL to_chars_result to_chars(char* first, char* last, std::float64_t value,
chars_format fmt = chars_format::general) noexcept;

BOOST_CHARCONV_DECL to_chars_result to_chars(char* first, char* last, std::float64_t value,
chars_format fmt = chars_format::general, int precision = -1 ) noexcept;
chars_format fmt, int precision) noexcept;
#endif
#if defined(BOOST_CHARCONV_HAS_STDFLOAT128) && defined(BOOST_CHARCONV_HAS_FLOAT128)
BOOST_CHARCONV_DECL to_chars_result to_chars(char* first, char* last, std::float128_t value,
chars_format fmt = chars_format::general, int precision = -1 ) noexcept;
chars_format fmt = chars_format::general) noexcept;

BOOST_CHARCONV_DECL to_chars_result to_chars(char* first, char* last, std::float128_t value,
chars_format fmt, int precision) noexcept;
#endif
#ifdef BOOST_CHARCONV_HAS_BRAINFLOAT16
BOOST_CHARCONV_DECL to_chars_result to_chars(char* first, char* last, std::bfloat16_t value,
chars_format fmt = chars_format::general) noexcept;

BOOST_CHARCONV_DECL to_chars_result to_chars(char* first, char* last, std::bfloat16_t value,
chars_format fmt = chars_format::general, int precision = -1 ) noexcept;
chars_format fmt, int precision) noexcept;
#endif

} // namespace charconv
Expand Down
229 changes: 110 additions & 119 deletions src/to_chars.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -548,95 +548,76 @@ namespace boost { namespace charconv { namespace detail { namespace to_chars_det

}}}} // Namespaces

boost::charconv::to_chars_result boost::charconv::to_chars(char* first, char* last, float value,
boost::charconv::chars_format fmt) noexcept
{
return boost::charconv::detail::to_chars_float_impl(first, last, value, fmt, -1);
}

boost::charconv::to_chars_result boost::charconv::to_chars(char* first, char* last, float value,
boost::charconv::chars_format fmt, int precision) noexcept
{
if (precision < 0)
{
precision = 6;
}

return boost::charconv::detail::to_chars_float_impl(first, last, value, fmt, precision);
}

boost::charconv::to_chars_result boost::charconv::to_chars(char* first, char* last, double value,
boost::charconv::chars_format fmt) noexcept
{
return boost::charconv::detail::to_chars_float_impl(first, last, value, fmt, -1);
}

boost::charconv::to_chars_result boost::charconv::to_chars(char* first, char* last, double value,
boost::charconv::chars_format fmt, int precision) noexcept
{
if (precision < 0)
{
precision = 6;
}

return boost::charconv::detail::to_chars_float_impl(first, last, value, fmt, precision);
}

#if BOOST_CHARCONV_LDBL_BITS == 64 || defined(BOOST_MSVC)

boost::charconv::to_chars_result boost::charconv::to_chars(char* first, char* last, long double value,
boost::charconv::chars_format fmt, int precision) noexcept
boost::charconv::chars_format fmt) noexcept
{
return boost::charconv::detail::to_chars_float_impl(first, last, static_cast<double>(value), fmt, precision);
return boost::charconv::detail::to_chars_float_impl(first, last, static_cast<double>(value), fmt, -1);
}

#elif (BOOST_CHARCONV_LDBL_BITS == 80 || BOOST_CHARCONV_LDBL_BITS == 128)

boost::charconv::to_chars_result boost::charconv::to_chars(char* first, char* last, long double value,
boost::charconv::chars_format fmt, int precision) noexcept
{
static_assert(std::numeric_limits<long double>::is_iec559, "Long double must be IEEE 754 compliant");

const auto classification = std::fpclassify(value);
#if BOOST_CHARCONV_LDBL_BITS == 128
if (classification == FP_NAN || classification == FP_INFINITE)
if (precision < 0)
{
return boost::charconv::detail::to_chars_nonfinite(first, last, value, classification);
precision = 6;
}
#else
if (classification == FP_NAN || classification == FP_INFINITE)
{
const auto fd128 = boost::charconv::detail::ryu::long_double_to_fd128(value);
const auto num_chars = boost::charconv::detail::ryu::generic_to_chars(fd128, first, last - first, fmt, precision);

if (num_chars > 0)
{
return { first + num_chars, std::errc() };
}
else
{
return {last, std::errc::value_too_large};
}
}
#endif
return boost::charconv::detail::to_chars_float_impl(first, last, static_cast<double>(value), fmt, precision);
}

// Sanity check our bounds
const std::ptrdiff_t buffer_size = last - first;
auto real_precision = boost::charconv::detail::get_real_precision<long double>(precision);
if (buffer_size < real_precision || first > last)
{
return {last, std::errc::value_too_large};
}
#elif (BOOST_CHARCONV_LDBL_BITS == 80 || BOOST_CHARCONV_LDBL_BITS == 128)

if (fmt == boost::charconv::chars_format::general || fmt == boost::charconv::chars_format::scientific)
{
const auto fd128 = boost::charconv::detail::ryu::long_double_to_fd128(value);
const auto num_chars = boost::charconv::detail::ryu::generic_to_chars(fd128, first, last - first, fmt, precision);
boost::charconv::to_chars_result boost::charconv::to_chars(char* first, char* last, long double value,
boost::charconv::chars_format fmt) noexcept
{
return boost::charconv::detail::to_chars_float_impl(first, last, value, fmt, -1);
}

if (num_chars > 0)
{
return { first + num_chars, std::errc() };
}
}
else if (fmt == boost::charconv::chars_format::hex)
boost::charconv::to_chars_result boost::charconv::to_chars(char* first, char* last, long double value,
boost::charconv::chars_format fmt, int precision) noexcept
{
if (precision < 0)
{
return boost::charconv::detail::to_chars_hex(first, last, value, precision);
precision = 6;
}
else if (fmt == boost::charconv::chars_format::fixed)
{
const auto fd128 = boost::charconv::detail::ryu::long_double_to_fd128(value);
const auto num_chars = boost::charconv::detail::ryu::generic_to_chars_fixed(fd128, first, last - first, precision);

if (num_chars > 0)
{
return { first + num_chars, std::errc() };
}
else if (num_chars == -static_cast<int>(std::errc::value_too_large))
{
return { last, std::errc::value_too_large };
}
}

// Fallback to printf methods
return boost::charconv::detail::to_chars_printf_impl(first, last, value, fmt, precision);
return boost::charconv::detail::to_chars_float_impl(first, last, value, fmt, precision);
}

#else
Expand Down Expand Up @@ -681,117 +662,127 @@ boost::charconv::to_chars_result boost::charconv::to_chars( char* first, char* l

#ifdef BOOST_CHARCONV_HAS_FLOAT128

boost::charconv::to_chars_result boost::charconv::to_chars(char* first, char* last, __float128 value, boost::charconv::chars_format fmt, int precision) noexcept
boost::charconv::to_chars_result boost::charconv::to_chars(char* first, char* last, __float128 value, boost::charconv::chars_format fmt) noexcept
{
// Sanity check our bounds
if (first >= last)
{
return {last, std::errc::value_too_large};
}

char* const original_first = first;

if (isnanq(value))
{
return boost::charconv::detail::to_chars_nonfinite(first, last, value, FP_NAN);
}
else if (isinfq(value))
{
return boost::charconv::detail::to_chars_nonfinite(first, last, value, FP_INFINITE);
}

// Sanity check our bounds
const std::ptrdiff_t buffer_size = last - first;
auto real_precision = boost::charconv::detail::get_real_precision<__float128>(precision);
if (buffer_size < real_precision || first > last)
{
return {last, std::errc::value_too_large};
}

if ((fmt == boost::charconv::chars_format::general || fmt == boost::charconv::chars_format::scientific))
{
const auto fd128 = boost::charconv::detail::ryu::float128_to_fd128(value);
const auto num_chars = boost::charconv::detail::ryu::generic_to_chars(fd128, first, last - first, fmt, precision);
return boost::charconv::detail::to_chars_float_impl(first, last, value, fmt, -1);
}

if (num_chars > 0)
{
return { first + num_chars, std::errc() };
}
else if (num_chars == -1)
{
return {last, std::errc::value_too_large};
}
}
else if (fmt == boost::charconv::chars_format::hex)
boost::charconv::to_chars_result boost::charconv::to_chars(char* first, char* last, __float128 value, boost::charconv::chars_format fmt, int precision) noexcept
{
if (precision < 0)
{
return boost::charconv::detail::to_chars_hex(first, last, value, precision);
precision = 6;
}
else if (fmt == boost::charconv::chars_format::fixed)
{
const auto fd128 = boost::charconv::detail::ryu::float128_to_fd128(value);
const auto num_chars = boost::charconv::detail::ryu::generic_to_chars_fixed(fd128, first, last - first, precision);

if (num_chars > 0)
{
return { first + num_chars, std::errc() };
}
else if (num_chars == -static_cast<int>(std::errc::value_too_large))
{
return { last, std::errc::value_too_large };
}
}

first = original_first;
// Fallback to printf
return boost::charconv::detail::to_chars_printf_impl(first, last, value, fmt, precision);
return boost::charconv::detail::to_chars_float_impl(first, last, value, fmt, precision);
}

#endif

#ifdef BOOST_CHARCONV_HAS_FLOAT16

boost::charconv::to_chars_result boost::charconv::to_chars(char* first, char* last, std::float16_t value,
boost::charconv::chars_format fmt) noexcept
{
return boost::charconv::detail::to_chars_float_impl(first, last, static_cast<float>(value), fmt, -1);
}

boost::charconv::to_chars_result boost::charconv::to_chars(char* first, char* last, std::float16_t value,
boost::charconv::chars_format fmt, int precision) noexcept
{
if (precision < 0)
{
precision = 6;
}

return boost::charconv::detail::to_chars_float_impl(first, last, static_cast<float>(value), fmt, precision);
}
#endif

#ifdef BOOST_CHARCONV_HAS_FLOAT32

boost::charconv::to_chars_result boost::charconv::to_chars(char* first, char* last, std::float32_t value,
boost::charconv::chars_format fmt) noexcept
{
return boost::charconv::detail::to_chars_float_impl(first, last, static_cast<float>(value), fmt, -1);
}

boost::charconv::to_chars_result boost::charconv::to_chars(char* first, char* last, std::float32_t value,
boost::charconv::chars_format fmt, int precision) noexcept
{
static_assert(std::numeric_limits<std::float32_t>::digits == FLT_MANT_DIG &&
std::numeric_limits<std::float32_t>::min_exponent == FLT_MIN_EXP,
"float and std::float32_t are not the same layout like they should be");

if (precision < 0)
{
precision = 6;
}

return boost::charconv::detail::to_chars_float_impl(first, last, static_cast<float>(value), fmt, precision);
}
#endif

#ifdef BOOST_CHARCONV_HAS_FLOAT64

boost::charconv::to_chars_result boost::charconv::to_chars(char* first, char* last, std::float64_t value,
boost::charconv::chars_format fmt) noexcept
{
return boost::charconv::detail::to_chars_float_impl(first, last, static_cast<double>(value), fmt, -1);
}

boost::charconv::to_chars_result boost::charconv::to_chars(char* first, char* last, std::float64_t value,
boost::charconv::chars_format fmt, int precision) noexcept
{
static_assert(std::numeric_limits<std::float64_t>::digits == DBL_MANT_DIG &&
std::numeric_limits<std::float64_t>::min_exponent == DBL_MIN_EXP,
"double and std::float64_t are not the same layout like they should be");


if (precision < 0)
{
precision = 6;
}

return boost::charconv::detail::to_chars_float_impl(first, last, static_cast<double>(value), fmt, precision);
}
#endif

#if defined(BOOST_CHARCONV_HAS_STDFLOAT128) && defined(BOOST_CHARCONV_HAS_FLOAT128)

boost::charconv::to_chars_result boost::charconv::to_chars(char* first, char* last, std::float128_t value,
boost::charconv::chars_format fmt) noexcept
{
return boost::charconv::detail::to_chars_float_impl(first, last, static_cast<__float128>(value), fmt, -1);
}

boost::charconv::to_chars_result boost::charconv::to_chars(char* first, char* last, std::float128_t value,
boost::charconv::chars_format fmt, int precision) noexcept
{
return boost::charconv::to_chars(first, last, static_cast<__float128>(value), fmt, precision);
if (precision < 0)
{
precision = 6;
}

return boost::charconv::detail::to_chars_float_impl(first, last, static_cast<__float128>(value), fmt, precision);
}
#endif

#ifdef BOOST_CHARCONV_HAS_BRAINFLOAT16

boost::charconv::to_chars_result boost::charconv::to_chars(char* first, char* last, std::bfloat16_t value,
boost::charconv::chars_format fmt) noexcept
{
return boost::charconv::detail::to_chars_float_impl(first, last, static_cast<float>(value), fmt, -1);
}

boost::charconv::to_chars_result boost::charconv::to_chars(char* first, char* last, std::bfloat16_t value,
boost::charconv::chars_format fmt, int precision) noexcept
{
if (precision < 0)
{
precision = 6;
}

return boost::charconv::detail::to_chars_float_impl(first, last, static_cast<float>(value), fmt, precision);
}
#endif
Loading

0 comments on commit 317e04f

Please sign in to comment.