#ifndef BOOST_CHARCONV_DETAIL_TO_CHARS_FLOAT_IMPL_HPP
#define BOOST_CHARCONV_DETAIL_TO_CHARS_FLOAT_IMPL_HPP
#include "float128_impl.hpp"
#include <boost/charconv/detail/apply_sign.hpp>
#include <boost/charconv/detail/integer_search_trees.hpp>
#include <boost/charconv/detail/memcpy.hpp>
#include <boost/charconv/detail/config.hpp>
#include <boost/charconv/detail/dragonbox/floff.hpp>
#include <boost/charconv/detail/bit_layouts.hpp>
#include <boost/charconv/detail/dragonbox/dragonbox.hpp>
#include <boost/charconv/detail/to_chars_integer_impl.hpp>
#include <boost/charconv/detail/to_chars_result.hpp>
#include <boost/charconv/detail/emulated128.hpp>
#include <boost/charconv/detail/fallback_routines.hpp>
#include <boost/charconv/detail/buffer_sizing.hpp>
#include <boost/charconv/config.hpp>
#include <boost/charconv/chars_format.hpp>
#include <system_error>
#include <type_traits>
#include <array>
#include <limits>
#include <utility>
#include <cstring>
#include <cstdio>
#include <cerrno>
#include <cstdint>
#include <climits>
#include <cmath>
#ifdef BOOST_CHARCONV_DEBUG_FIXED
#include <iomanip>
#include <iostream>
#endif
#if (BOOST_CHARCONV_LDBL_BITS == 80 || BOOST_CHARCONV_LDBL_BITS == 128)
# include <boost/charconv/detail/ryu/ryu_generic_128.hpp>
# include <boost/charconv/detail/issignaling.hpp>
#endif
namespace boost {
namespace charconv {
namespace detail {
template <typename Real>
inline to_chars_result to_chars_nonfinite(char* first, char* last, Real value, int classification) noexcept;
#if BOOST_CHARCONV_LDBL_BITS == 128 || defined(BOOST_CHARCONV_HAS_STDFLOAT128) || defined(BOOST_CHARCONV_HAS_FLOAT16) || defined(BOOST_CHARCONV_HAS_BRAINFLOAT16)
template <typename Real>
inline to_chars_result to_chars_nonfinite(char* first, char* last, Real value, int classification) noexcept
{
std::ptrdiff_t offset {};
std::ptrdiff_t buffer_size = last - first;
if (classification == FP_NAN)
{
bool is_negative = false;
const bool is_signaling = issignaling(value);
if (std::signbit(value))
{
is_negative = true;
*first++ = '-';
}
if (is_signaling && buffer_size >= (9 + static_cast<int>(is_negative)))
{
std::memcpy(first, "nan(snan)", 9);
offset = 9 + static_cast<int>(is_negative);
}
else if (is_negative && buffer_size >= 9)
{
std::memcpy(first, "nan(ind)", 8);
offset = 8;
}
else if (!is_negative && !is_signaling && buffer_size >= 3)
{
std::memcpy(first, "nan", 3);
offset = 3;
}
else
{
return { first, std::errc::value_too_large };
}
}
else if (classification == FP_INFINITE)
{
auto sign_bit_value = std::signbit(value);
if (sign_bit_value && buffer_size >= 4)
{
std::memcpy(first, "-inf", 4);
offset = 4;
}
else if (!sign_bit_value && buffer_size >= 3)
{
std::memcpy(first, "inf", 3);
offset = 3;
}
else
{
return { first, std::errc::value_too_large };
}
}
else
{
BOOST_UNREACHABLE_RETURN(first);
}
return { first + offset, std::errc() };
}
#endif
#ifdef BOOST_CHARCONV_HAS_QUADMATH
#if defined(__GNUC__) && __GNUC__ == 5
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wfloat-conversion"
#endif
template <>
inline to_chars_result to_chars_nonfinite<__float128>(char* first, char* last, __float128 value, int classification) noexcept
{
std::ptrdiff_t offset {};
std::ptrdiff_t buffer_size = last - first;
IEEEbinary128 bits;
std::memcpy(&bits, &value, sizeof(value));
const bool is_negative = bits.sign;
if (classification == FP_NAN)
{
const bool is_signaling = issignaling(value);
if (is_negative)
{
*first++ = '-';
}
if (is_signaling && buffer_size >= (9 + static_cast<int>(is_negative)))
{
std::memcpy(first, "nan(snan)", 9);
offset = 9 + static_cast<int>(is_negative);
}
else if (is_negative && buffer_size >= 9)
{
std::memcpy(first, "nan(ind)", 8);
offset = 8;
}
else if (!is_negative && !is_signaling && buffer_size >= 3)
{
std::memcpy(first, "nan", 3);
offset = 3;
}
else
{
return { first, std::errc::value_too_large };
}
}
else if (classification == FP_INFINITE)
{
if (is_negative && buffer_size >= 4)
{
std::memcpy(first, "-inf", 4);
offset = 4;
}
else if (!is_negative && buffer_size >= 3)
{
std::memcpy(first, "inf", 3);
offset = 3;
}
else
{
return { first, std::errc::value_too_large };
}
}
else
{
BOOST_UNREACHABLE_RETURN(first);
}
return { first + offset, std::errc() };
}
#if defined(__GNUC__) && __GNUC__ == 5
# pragma GCC diagnostic pop
#endif
#endif
template <typename Unsigned_Integer, typename Real, typename std::enable_if<!std::is_same<Unsigned_Integer, uint128>::value, bool>::type = true>
Unsigned_Integer convert_value(Real value) noexcept
{
Unsigned_Integer temp;
std::memcpy(&temp, &value, sizeof(Real));
return temp;
}
template <typename Unsigned_Integer, typename Real, typename std::enable_if<std::is_same<Unsigned_Integer, uint128>::value, bool>::type = true>
Unsigned_Integer convert_value(Real value) noexcept
{
trivial_uint128 trivial_bits; std::memcpy(&trivial_bits, &value, sizeof(Real));
Unsigned_Integer temp {trivial_bits};
return temp;
}
#ifdef BOOST_MSVC
# pragma warning(push)
# pragma warning(disable: 4127)
#endif
template <typename Real, typename Unsigned_Integer>
inline std::uint64_t extract_exp(Real, Unsigned_Integer uint_value, int significand_bits) noexcept
{
return static_cast<std::uint64_t>(uint_value >> significand_bits);
}
#if BOOST_CHARCONV_LDBL_BITS == 80
template <>
inline std::uint64_t extract_exp<long double, uint128>(long double, uint128 uint_value, int) noexcept
{
constexpr auto exp_mask = uint128{UINT64_C(0x7FFF), UINT64_C(0)};
auto exponent = uint_value & exp_mask;
return exponent.high;
}
#endif
template <typename Real>
to_chars_result to_chars_hex(char* first, char* last, Real value, int precision) noexcept
{
const std::ptrdiff_t buffer_size = last - first;
auto real_precision = get_real_precision<Real>(precision);
if (precision != -1)
{
real_precision = precision;
}
if (buffer_size < real_precision || first > last)
{
return {last, std::errc::value_too_large};
}
using type_layout =
#ifdef BOOST_CHARCONV_HAS_FLOAT16
typename std::conditional<std::is_same<Real, std::float16_t>::value, ieee754_binary16,
#endif
#ifdef BOOST_CHARCONV_HAS_BRAINFLOAT16
typename std::conditional<std::is_same<Real, std::bfloat16_t>::value, brainfloat16,
#endif
typename std::conditional<std::is_same<Real, float>::value, ieee754_binary32,
typename std::conditional<std::is_same<Real, double>::value, ieee754_binary64,
#ifdef BOOST_CHARCONV_HAS_QUADMATH
typename std::conditional<std::is_same<Real, __float128>::value, ieee754_binary128,
#endif
#if BOOST_CHARCONV_LDBL_BITS == 128
ieee754_binary128
#elif BOOST_CHARCONV_LDBL_BITS == 80
ieee754_binary80
#else
ieee754_binary64
#endif
#ifdef BOOST_CHARCONV_HAS_QUADMATH
>::type
#endif
>::type>::type
#ifdef BOOST_CHARCONV_HAS_FLOAT16
>::type
#endif
#ifdef BOOST_CHARCONV_HAS_BRAINFLOAT16
>::type
#endif
;
using Unsigned_Integer =
typename std::conditional<sizeof(Real) == sizeof(std::uint16_t), std::uint16_t,
typename std::conditional<std::is_same<Real, float>::value, std::uint32_t,
typename std::conditional<std::is_same<Real, double>::value, std::uint64_t, uint128>::type>::type>::type;
Unsigned_Integer uint_value {convert_value<Unsigned_Integer>(value)};
const Unsigned_Integer denorm_mask = (Unsigned_Integer(1) << (type_layout::significand_bits)) - 1;
const Unsigned_Integer significand = uint_value & denorm_mask;
std::uint64_t exponent = extract_exp(value, uint_value, type_layout::significand_bits);
BOOST_IF_CONSTEXPR (!(std::is_same<Real, float>::value || std::is_same<Real, double>::value
#if BOOST_CHARCONV_LDBL_BITS == 80
|| std::is_same<Real, long double>::value
#endif
#ifdef BOOST_CHARCONV_HAS_FLOAT16
|| std::is_same<Real, std::float16_t>::value
#endif
#ifdef BOOST_CHARCONV_HAS_BRAINFLOAT16
|| std::is_same<Real, std::bfloat16_t>::value
#endif
))
{
exponent += 2;
}
constexpr auto hex_precision =
#ifdef BOOST_CHARCONV_HAS_FLOAT16
std::is_same<Real, std::float16_t>::value ? 3 :
#endif
#ifdef BOOST_CHARCONV_HAS_BRAINFLOAT16
std::is_same<Real, std::bfloat16_t>::value ? 2 :
#endif
std::is_same<Real, float>::value ? 6 :
std::is_same<Real, double>::value ? 13
#if BOOST_CHARCONV_LDBL_BITS == 80
: std::is_same<Real, long double>::value ? 15
#endif
: 28;
constexpr auto nibble_bits = CHAR_BIT / 2;
constexpr auto hex_bits = hex_precision * nibble_bits;
const Unsigned_Integer hex_mask = (static_cast<Unsigned_Integer>(1) << hex_bits) - 1;
Unsigned_Integer aligned_significand;
BOOST_IF_CONSTEXPR (std::is_same<Real, float>::value
#ifdef BOOST_CHARCONV_HAS_BRAINFLOAT16
|| std::is_same<Real, std::bfloat16_t>::value
#endif
)
{
aligned_significand = significand << 1;
}
#ifdef BOOST_CHARCONV_HAS_FLOAT16
else BOOST_IF_CONSTEXPR (std::is_same<Real, std::float16_t>::value)
{
aligned_significand = significand << 2; }
#endif
else
{
aligned_significand = significand;
}
std::int64_t unbiased_exponent;
if (exponent == 0 && significand != 0)
{
unbiased_exponent = 1 + type_layout::exponent_bias;
}
else
{
aligned_significand |= static_cast<Unsigned_Integer>(1) << hex_bits;
unbiased_exponent = exponent + type_layout::exponent_bias;
}
BOOST_IF_CONSTEXPR (std::is_same<Real, float>::value)
{
if (unbiased_exponent > 127)
{
unbiased_exponent -= 256;
}
}
else BOOST_IF_CONSTEXPR (std::is_same<Real, double>::value)
{
if (unbiased_exponent > 1023)
{
unbiased_exponent -= 2048;
}
}
else BOOST_IF_CONSTEXPR (std::is_same<Real, long double>::value)
{
#if BOOST_CHARCONV_LDBL_BITS == 80
while (unbiased_exponent > 16383)
{
unbiased_exponent -= 32768;
}
unbiased_exponent -= 3;
#else
while (unbiased_exponent > 16383)
{
unbiased_exponent -= 32768;
}
#endif
}
#ifdef BOOST_CHARCONV_HAS_FLOAT16
else BOOST_IF_CONSTEXPR (std::is_same<Real, std::float16_t>::value)
{
if (unbiased_exponent > 15)
{
unbiased_exponent -= 32;
}
}
#endif
#ifdef BOOST_CHARCONV_HAS_BRAINFLOAT16
else BOOST_IF_CONSTEXPR (std::is_same<Real, std::bfloat16_t>::value)
{
if (unbiased_exponent > 127)
{
unbiased_exponent -= 256;
}
}
#endif
else
{
while (unbiased_exponent > 16383)
{
unbiased_exponent -= 32768;
}
}
const std::uint32_t abs_unbiased_exponent = unbiased_exponent < 0 ? static_cast<std::uint32_t>(-unbiased_exponent) :
static_cast<std::uint32_t>(unbiased_exponent);
const std::ptrdiff_t total_length = total_buffer_length(real_precision, abs_unbiased_exponent, (value < 0));
if (total_length > buffer_size)
{
return {last, std::errc::value_too_large};
}
if (real_precision < hex_precision)
{
const int lost_bits = (hex_precision - real_precision) * nibble_bits;
const Unsigned_Integer lsb_bit = aligned_significand;
const Unsigned_Integer round_bit = aligned_significand << 1;
const Unsigned_Integer tail_bit = round_bit - 1;
const Unsigned_Integer round = round_bit & (tail_bit | lsb_bit) & (static_cast<Unsigned_Integer>(1) << lost_bits);
aligned_significand += round;
}
if (value < 0)
{
*first++ = '-';
}
#if BOOST_CHARCONV_LDBL_BITS == 80
std::uint32_t leading_nibble;
BOOST_IF_CONSTEXPR (std::is_same<Real, long double>::value)
{
leading_nibble = static_cast<std::uint32_t>(significand >> hex_bits);
}
else
{
leading_nibble = static_cast<std::uint32_t>(aligned_significand >> hex_bits);
}
#else
const auto leading_nibble = static_cast<std::uint32_t>(aligned_significand >> hex_bits);
#endif
BOOST_CHARCONV_ASSERT(leading_nibble < 16);
*first++ = digit_table[leading_nibble];
aligned_significand &= hex_mask;
if (real_precision > 0)
{
*first++ = '.';
std::int32_t remaining_bits = hex_bits;
while (true)
{
remaining_bits -= nibble_bits;
const auto current_nibble = static_cast<std::uint32_t>(aligned_significand >> remaining_bits);
*first++ = digit_table[current_nibble];
--real_precision;
if (real_precision == 0)
{
break;
}
else if (remaining_bits == 0)
{
if (precision != -1)
{
std::memset(first, '0', static_cast<std::size_t>(real_precision));
first += real_precision;
}
break;
}
aligned_significand &= (static_cast<Unsigned_Integer>(1) << remaining_bits) - 1;
}
}
if (precision == -1)
{
--first;
while (*first == '0')
{
--first;
}
if (*first != '.')
{
++first;
}
}
*first++ = 'p';
if (unbiased_exponent < 0)
{
*first++ = '-';
}
else
{
*first++ = '+';
}
return to_chars_int(first, last, abs_unbiased_exponent);
}
#ifdef BOOST_MSVC
# pragma warning(pop)
#endif
template <typename Real>
to_chars_result to_chars_fixed_impl(char* first, char* last, Real value, chars_format fmt = chars_format::general, int precision = -1) noexcept
{
const std::ptrdiff_t buffer_size = last - first;
auto real_precision = get_real_precision<Real>(precision);
if (buffer_size < real_precision || first > last)
{
return {last, std::errc::value_too_large};
}
auto abs_value = std::abs(value);
auto value_struct = boost::charconv::detail::to_decimal(value);
if (value_struct.is_negative)
{
*first++ = '-';
}
if (value_struct.significand == 0)
{
*first++ = '0';
if (precision > -1)
{
*first++ = '.';
std::memset(first, '0', static_cast<std::size_t>(precision));
first += precision;
}
return {first, std::errc()};
}
const int starting_num_digits = num_digits(value_struct.significand);
int num_dig = starting_num_digits;
if (precision != -1)
{
while (num_dig > precision + 2)
{
value_struct.significand /= 10;
++value_struct.exponent;
--num_dig;
}
if (num_dig == precision + 2)
{
const auto trailing_dig = value_struct.significand % 10;
value_struct.significand /= 10;
++value_struct.exponent;
--num_dig;
if (trailing_dig >= 5)
{
++value_struct.significand;
}
}
if (fmt == chars_format::general)
{
while (value_struct.significand % 10 == 0)
{
value_struct.significand /= 10;
++value_struct.exponent;
--num_dig;
}
}
}
const std::ptrdiff_t total_length = total_buffer_length(num_dig, value_struct.exponent, (value < 0));
if (total_length > buffer_size)
{
return {last, std::errc::value_too_large};
}
if (abs_value < 1)
{
if (-value_struct.exponent - starting_num_digits + 2 > (last - first))
{
return {last, std::errc::value_too_large};
}
std::memcpy(first, "0.", 2U);
std::memset(first + 2, '0', -value_struct.exponent - starting_num_digits);
first += 2 - value_struct.exponent - starting_num_digits;
}
auto r = to_chars_integer_impl(first, last, value_struct.significand);
if (r.ec != std::errc())
{
return r;
}
if (abs_value >= 1)
{
if (value_struct.exponent < 0 && -value_struct.exponent < buffer_size)
{
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;
}
if (value_struct.exponent > 0)
{
const auto zeros_to_append = static_cast<std::size_t>(value_struct.exponent);
if (zeros_to_append > static_cast<std::size_t>(last - r.ptr))
{
return {last, std::errc::value_too_large};
}
std::memset(r.ptr, '0', zeros_to_append);
r.ptr += zeros_to_append;
}
}
return { r.ptr, std::errc() };
}
template <typename Real>
to_chars_result to_chars_float_impl(char* first, char* last, Real value, chars_format fmt, int precision) noexcept
{
using Unsigned_Integer = typename std::conditional<std::is_same<Real, double>::value, std::uint64_t, std::uint32_t>::type;
if (first >= last)
{
return {last, std::errc::value_too_large};
}
auto abs_value = std::abs(value);
constexpr auto max_fractional_value = std::is_same<Real, double>::value ? static_cast<Real>(1e16) : static_cast<Real>(1e7);
constexpr auto max_value = static_cast<Real>((std::numeric_limits<Unsigned_Integer>::max)());
if (precision == -1)
{
if (fmt == boost::charconv::chars_format::general)
{
if (abs_value >= 1 && abs_value < max_fractional_value)
{
return to_chars_fixed_impl(first, last, value, fmt, precision);
}
else if (abs_value >= max_fractional_value && abs_value < max_value)
{
if (value < 0)
{
*first++ = '-';
}
return to_chars_integer_impl(first, last, static_cast<std::uint64_t>(abs_value));
}
else
{
return boost::charconv::detail::dragonbox_to_chars(value, first, last, fmt);
}
}
else if (fmt == boost::charconv::chars_format::scientific)
{
return boost::charconv::detail::dragonbox_to_chars(value, first, last, fmt);
}
else if (fmt == boost::charconv::chars_format::fixed)
{
return to_chars_fixed_impl(first, last, value, fmt, precision);
}
}
else
{
if (fmt != boost::charconv::chars_format::hex)
{
if (fmt == boost::charconv::chars_format::general)
{
constexpr int max_output_length = std::is_same<Real, double>::value ? 773 : 117;
constexpr int max_precision = std::is_same<Real, double>::value ? 767 : 112;
if (precision > max_precision)
{
precision = max_precision;
}
char temp_buffer[max_output_length];
auto result = boost::charconv::detail::floff<boost::charconv::detail::main_cache_full,
boost::charconv::detail::extended_cache_long>(value, precision,
temp_buffer,
temp_buffer + max_output_length,
fmt);
auto output_size = static_cast<std::size_t>(result.ptr - temp_buffer);
if (static_cast<std::size_t>(last - first) < output_size)
{
return {last, std::errc::value_too_large};
}
std::memcpy(first, temp_buffer, output_size);
return {first + output_size, std::errc()};
}
return boost::charconv::detail::floff<boost::charconv::detail::main_cache_full,
boost::charconv::detail::extended_cache_long>(value, precision,
first, last, fmt);
}
}
const int classification = std::fpclassify(value);
switch (classification)
{
case FP_INFINITE:
case FP_NAN:
return boost::charconv::detail::dragonbox_to_chars(value, first, last, chars_format::general);
case FP_ZERO:
if (std::signbit(value))
{
*first++ = '-';
}
std::memcpy(first, "0p+0", 4); return {first + 4, std::errc()};
default:
(void)precision;
}
return boost::charconv::detail::to_chars_hex(first, last, value, precision);
}
#if (BOOST_CHARCONV_LDBL_BITS == 80 || BOOST_CHARCONV_LDBL_BITS == 128) && !defined(BOOST_CHARCONV_LDBL_IS_FLOAT128)
template <>
to_chars_result to_chars_float_impl(char* first, char* last, long double value, 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)
{
return boost::charconv::detail::to_chars_nonfinite(first, last, value, classification);
}
#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
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};
}
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);
if (num_chars > 0)
{
return { first + num_chars, std::errc() };
}
}
else if (fmt == boost::charconv::chars_format::hex)
{
return boost::charconv::detail::to_chars_hex(first, last, value, precision);
}
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 };
}
}
return boost::charconv::detail::to_chars_printf_impl(first, last, value, fmt, precision);
}
#endif
#ifdef BOOST_CHARCONV_HAS_QUADMATH
template <>
to_chars_result to_chars_float_impl(char* first, char* last, __float128 value, chars_format fmt, int precision) noexcept
{
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);
}
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);
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)
{
return boost::charconv::detail::to_chars_hex(first, last, value, precision);
}
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;
return boost::charconv::detail::to_chars_printf_impl(first, last, value, fmt, precision);
}
#endif
#if defined(BOOST_CHARCONV_HAS_FLOAT16) || defined(BOOST_CHARCONV_HAS_BRAINFLOAT16)
template <typename T>
to_chars_result to_chars_16_bit_float_impl(char* first, char* last, T value, chars_format fmt, int precision) noexcept
{
const auto classification = std::fpclassify(value);
if (classification == FP_NAN || classification == FP_INFINITE)
{
return boost::charconv::detail::to_chars_nonfinite(first, last, value, classification);
}
const std::ptrdiff_t buffer_size = last - first;
auto real_precision = boost::charconv::detail::get_real_precision<T>(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::float16_t_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 if (fmt == boost::charconv::chars_format::hex)
{
return boost::charconv::detail::to_chars_hex(first, last, value, precision);
}
else if (fmt == boost::charconv::chars_format::fixed)
{
const auto fd128 = boost::charconv::detail::ryu::float16_t_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 };
}
}
return boost::charconv::detail::to_chars_printf_impl(first, last, value, fmt, precision);
}
#endif
} } }
#endif