mirror of
https://github.com/fmtlib/fmt.git
synced 2025-07-31 03:07:36 +02:00
Reduce usage of float_specs
This commit is contained in:
@ -2400,15 +2400,13 @@ FMT_CONSTEXPR auto parse_align(const Char* begin, const Char* end,
|
|||||||
enum class float_format : unsigned char {
|
enum class float_format : unsigned char {
|
||||||
general, // General: exponent notation or fixed point based on magnitude.
|
general, // General: exponent notation or fixed point based on magnitude.
|
||||||
exp, // Exponent notation with the default precision of 6, e.g. 1.2e-3.
|
exp, // Exponent notation with the default precision of 6, e.g. 1.2e-3.
|
||||||
fixed, // Fixed point with the default precision of 6, e.g. 0.0012.
|
fixed // Fixed point with the default precision of 6, e.g. 0.0012.
|
||||||
hex
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct float_specs {
|
struct float_specs {
|
||||||
int precision;
|
int precision;
|
||||||
float_format format : 8;
|
float_format format : 8;
|
||||||
sign_t sign : 8;
|
sign_t sign : 8;
|
||||||
bool upper : 1;
|
|
||||||
bool locale : 1;
|
bool locale : 1;
|
||||||
bool binary32 : 1;
|
bool binary32 : 1;
|
||||||
bool showpoint : 1;
|
bool showpoint : 1;
|
||||||
@ -2428,34 +2426,26 @@ FMT_CONSTEXPR inline auto parse_float_type_spec(const format_specs& specs)
|
|||||||
break;
|
break;
|
||||||
case presentation_type::exp:
|
case presentation_type::exp:
|
||||||
result.format = float_format::exp;
|
result.format = float_format::exp;
|
||||||
result.upper = specs.upper;
|
|
||||||
result.showpoint |= specs.precision != 0;
|
result.showpoint |= specs.precision != 0;
|
||||||
break;
|
break;
|
||||||
case presentation_type::fixed:
|
case presentation_type::fixed:
|
||||||
result.format = float_format::fixed;
|
result.format = float_format::fixed;
|
||||||
result.upper = specs.upper;
|
|
||||||
result.showpoint |= specs.precision != 0;
|
result.showpoint |= specs.precision != 0;
|
||||||
break;
|
break;
|
||||||
case presentation_type::general:
|
case presentation_type::general:
|
||||||
result.upper = specs.upper;
|
|
||||||
result.format = float_format::general;
|
result.format = float_format::general;
|
||||||
break;
|
break;
|
||||||
case presentation_type::hexfloat:
|
|
||||||
result.format = float_format::hex;
|
|
||||||
result.upper = specs.upper;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Char, typename OutputIt>
|
template <typename Char, typename OutputIt>
|
||||||
FMT_CONSTEXPR20 auto write_nonfinite(OutputIt out, bool isnan,
|
FMT_CONSTEXPR20 auto write_nonfinite(OutputIt out, bool isnan,
|
||||||
format_specs specs,
|
format_specs specs, sign_t sign)
|
||||||
const float_specs& fspecs) -> OutputIt {
|
-> OutputIt {
|
||||||
auto str =
|
auto str =
|
||||||
isnan ? (fspecs.upper ? "NAN" : "nan") : (fspecs.upper ? "INF" : "inf");
|
isnan ? (specs.upper ? "NAN" : "nan") : (specs.upper ? "INF" : "inf");
|
||||||
constexpr size_t str_size = 3;
|
constexpr size_t str_size = 3;
|
||||||
auto sign = fspecs.sign;
|
|
||||||
auto size = str_size + (sign ? 1 : 0);
|
auto size = str_size + (sign ? 1 : 0);
|
||||||
// Replace '0'-padding with space for non-finite values.
|
// Replace '0'-padding with space for non-finite values.
|
||||||
const bool is_zero_fill =
|
const bool is_zero_fill =
|
||||||
@ -2612,7 +2602,7 @@ FMT_CONSTEXPR20 auto do_write_float(OutputIt out, const DecimalFP& f,
|
|||||||
if (abs_output_exp >= 100) exp_digits = abs_output_exp >= 1000 ? 4 : 3;
|
if (abs_output_exp >= 100) exp_digits = abs_output_exp >= 1000 ? 4 : 3;
|
||||||
|
|
||||||
size += to_unsigned((decimal_point ? 1 : 0) + 2 + exp_digits);
|
size += to_unsigned((decimal_point ? 1 : 0) + 2 + exp_digits);
|
||||||
char exp_char = fspecs.upper ? 'E' : 'e';
|
char exp_char = specs.upper ? 'E' : 'e';
|
||||||
auto write = [=](iterator it) {
|
auto write = [=](iterator it) {
|
||||||
if (sign) *it++ = detail::sign<Char>(sign);
|
if (sign) *it++ = detail::sign<Char>(sign);
|
||||||
// Insert a decimal point after the first digit and add an exponent.
|
// Insert a decimal point after the first digit and add an exponent.
|
||||||
@ -3152,8 +3142,8 @@ FMT_CONSTEXPR20 inline void format_dragon(basic_fp<uint128_t> value,
|
|||||||
|
|
||||||
// Formats a floating-point number using the hexfloat format.
|
// Formats a floating-point number using the hexfloat format.
|
||||||
template <typename Float, FMT_ENABLE_IF(!is_double_double<Float>::value)>
|
template <typename Float, FMT_ENABLE_IF(!is_double_double<Float>::value)>
|
||||||
FMT_CONSTEXPR20 void format_hexfloat(Float value, int precision,
|
FMT_CONSTEXPR20 void format_hexfloat(Float value, format_specs specs,
|
||||||
float_specs specs, buffer<char>& buf) {
|
buffer<char>& buf) {
|
||||||
// float is passed as double to reduce the number of instantiations and to
|
// float is passed as double to reduce the number of instantiations and to
|
||||||
// simplify implementation.
|
// simplify implementation.
|
||||||
static_assert(!std::is_same<Float, float>::value, "");
|
static_assert(!std::is_same<Float, float>::value, "");
|
||||||
@ -3181,8 +3171,8 @@ FMT_CONSTEXPR20 void format_hexfloat(Float value, int precision,
|
|||||||
if (leading_xdigit > 1) f.e -= (32 - countl_zero(leading_xdigit) - 1);
|
if (leading_xdigit > 1) f.e -= (32 - countl_zero(leading_xdigit) - 1);
|
||||||
|
|
||||||
int print_xdigits = num_xdigits - 1;
|
int print_xdigits = num_xdigits - 1;
|
||||||
if (precision >= 0 && print_xdigits > precision) {
|
if (specs.precision >= 0 && print_xdigits > specs.precision) {
|
||||||
const int shift = ((print_xdigits - precision - 1) * 4);
|
const int shift = ((print_xdigits - specs.precision - 1) * 4);
|
||||||
const auto mask = carrier_uint(0xF) << shift;
|
const auto mask = carrier_uint(0xF) << shift;
|
||||||
const auto v = static_cast<uint32_t>((f.f & mask) >> shift);
|
const auto v = static_cast<uint32_t>((f.f & mask) >> shift);
|
||||||
|
|
||||||
@ -3201,7 +3191,7 @@ FMT_CONSTEXPR20 void format_hexfloat(Float value, int precision,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
print_xdigits = precision;
|
print_xdigits = specs.precision;
|
||||||
}
|
}
|
||||||
|
|
||||||
char xdigits[num_bits<carrier_uint>() / 4];
|
char xdigits[num_bits<carrier_uint>() / 4];
|
||||||
@ -3214,10 +3204,10 @@ FMT_CONSTEXPR20 void format_hexfloat(Float value, int precision,
|
|||||||
buf.push_back('0');
|
buf.push_back('0');
|
||||||
buf.push_back(specs.upper ? 'X' : 'x');
|
buf.push_back(specs.upper ? 'X' : 'x');
|
||||||
buf.push_back(xdigits[0]);
|
buf.push_back(xdigits[0]);
|
||||||
if (specs.showpoint || print_xdigits > 0 || print_xdigits < precision)
|
if (specs.alt || print_xdigits > 0 || print_xdigits < specs.precision)
|
||||||
buf.push_back('.');
|
buf.push_back('.');
|
||||||
buf.append(xdigits + 1, xdigits + 1 + print_xdigits);
|
buf.append(xdigits + 1, xdigits + 1 + print_xdigits);
|
||||||
for (; print_xdigits < precision; ++print_xdigits) buf.push_back('0');
|
for (; print_xdigits < specs.precision; ++print_xdigits) buf.push_back('0');
|
||||||
|
|
||||||
buf.push_back(specs.upper ? 'P' : 'p');
|
buf.push_back(specs.upper ? 'P' : 'p');
|
||||||
|
|
||||||
@ -3233,9 +3223,9 @@ FMT_CONSTEXPR20 void format_hexfloat(Float value, int precision,
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename Float, FMT_ENABLE_IF(is_double_double<Float>::value)>
|
template <typename Float, FMT_ENABLE_IF(is_double_double<Float>::value)>
|
||||||
FMT_CONSTEXPR20 void format_hexfloat(Float value, int precision,
|
FMT_CONSTEXPR20 void format_hexfloat(Float value, format_specs specs,
|
||||||
float_specs specs, buffer<char>& buf) {
|
buffer<char>& buf) {
|
||||||
format_hexfloat(static_cast<double>(value), precision, specs, buf);
|
format_hexfloat(static_cast<double>(value), specs, buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr auto fractional_part_rounding_thresholds(int index) -> uint32_t {
|
constexpr auto fractional_part_rounding_thresholds(int index) -> uint32_t {
|
||||||
@ -3558,47 +3548,50 @@ FMT_CONSTEXPR20 auto format_float(Float value, int precision, float_specs specs,
|
|||||||
}
|
}
|
||||||
return exp;
|
return exp;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Char, typename OutputIt, typename T>
|
template <typename Char, typename OutputIt, typename T>
|
||||||
FMT_CONSTEXPR20 auto write_float(OutputIt out, T value, format_specs specs,
|
FMT_CONSTEXPR20 auto write_float(OutputIt out, T value, format_specs specs,
|
||||||
locale_ref loc) -> OutputIt {
|
locale_ref loc) -> OutputIt {
|
||||||
float_specs fspecs = parse_float_type_spec(specs);
|
sign_t sign = specs.sign;
|
||||||
fspecs.sign = specs.sign;
|
|
||||||
if (detail::signbit(value)) { // value < 0 is false for NaN so use signbit.
|
if (detail::signbit(value)) { // value < 0 is false for NaN so use signbit.
|
||||||
fspecs.sign = sign::minus;
|
sign = sign::minus;
|
||||||
value = -value;
|
value = -value;
|
||||||
} else if (fspecs.sign == sign::minus) {
|
} else if (sign == sign::minus) {
|
||||||
fspecs.sign = sign::none;
|
sign = sign::none;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!detail::isfinite(value))
|
if (!detail::isfinite(value))
|
||||||
return write_nonfinite<Char>(out, detail::isnan(value), specs, fspecs);
|
return write_nonfinite<Char>(out, detail::isnan(value), specs, sign);
|
||||||
|
|
||||||
if (specs.align == align::numeric && fspecs.sign) {
|
if (specs.align == align::numeric && sign) {
|
||||||
auto it = reserve(out, 1);
|
auto it = reserve(out, 1);
|
||||||
*it++ = detail::sign<Char>(fspecs.sign);
|
*it++ = detail::sign<Char>(sign);
|
||||||
out = base_iterator(out, it);
|
out = base_iterator(out, it);
|
||||||
fspecs.sign = sign::none;
|
sign = sign::none;
|
||||||
if (specs.width != 0) --specs.width;
|
if (specs.width != 0) --specs.width;
|
||||||
}
|
}
|
||||||
|
|
||||||
memory_buffer buffer;
|
memory_buffer buffer;
|
||||||
if (fspecs.format == float_format::hex) {
|
if (specs.type == presentation_type::hexfloat) {
|
||||||
if (fspecs.sign) buffer.push_back(detail::sign<char>(fspecs.sign));
|
if (sign) buffer.push_back(detail::sign<char>(sign));
|
||||||
format_hexfloat(convert_float(value), specs.precision, fspecs, buffer);
|
format_hexfloat(convert_float(value), specs, buffer);
|
||||||
return write_bytes<Char, align::right>(out, {buffer.data(), buffer.size()},
|
return write_bytes<Char, align::right>(out, {buffer.data(), buffer.size()},
|
||||||
specs);
|
specs);
|
||||||
}
|
}
|
||||||
|
|
||||||
int precision = specs.precision >= 0 || specs.type == presentation_type::none
|
int precision = specs.precision >= 0 || specs.type == presentation_type::none
|
||||||
? specs.precision
|
? specs.precision
|
||||||
: 6;
|
: 6;
|
||||||
if (fspecs.format == float_format::exp) {
|
if (specs.type == presentation_type::exp) {
|
||||||
if (precision == max_value<int>())
|
if (precision == max_value<int>())
|
||||||
report_error("number is too big");
|
report_error("number is too big");
|
||||||
else
|
else
|
||||||
++precision;
|
++precision;
|
||||||
} else if (fspecs.format != float_format::fixed && precision == 0) {
|
} else if (specs.type != presentation_type::fixed && precision == 0) {
|
||||||
precision = 1;
|
precision = 1;
|
||||||
}
|
}
|
||||||
|
float_specs fspecs = parse_float_type_spec(specs);
|
||||||
|
fspecs.sign = sign;
|
||||||
if (const_check(std::is_same<T, float>())) fspecs.binary32 = true;
|
if (const_check(std::is_same<T, float>())) fspecs.binary32 = true;
|
||||||
int exp = format_float(convert_float(value), precision, fspecs, buffer);
|
int exp = format_float(convert_float(value), precision, fspecs, buffer);
|
||||||
fspecs.precision = precision;
|
fspecs.precision = precision;
|
||||||
@ -3622,9 +3615,9 @@ FMT_CONSTEXPR20 auto write(OutputIt out, T value) -> OutputIt {
|
|||||||
if (is_constant_evaluated()) return write<Char>(out, value, format_specs());
|
if (is_constant_evaluated()) return write<Char>(out, value, format_specs());
|
||||||
if (const_check(!is_supported_floating_point(value))) return out;
|
if (const_check(!is_supported_floating_point(value))) return out;
|
||||||
|
|
||||||
auto fspecs = float_specs();
|
auto sign = sign_t::none;
|
||||||
if (detail::signbit(value)) {
|
if (detail::signbit(value)) {
|
||||||
fspecs.sign = sign::minus;
|
sign = sign::minus;
|
||||||
value = -value;
|
value = -value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3633,8 +3626,10 @@ FMT_CONSTEXPR20 auto write(OutputIt out, T value) -> OutputIt {
|
|||||||
using floaty_uint = typename dragonbox::float_info<floaty>::carrier_uint;
|
using floaty_uint = typename dragonbox::float_info<floaty>::carrier_uint;
|
||||||
floaty_uint mask = exponent_mask<floaty>();
|
floaty_uint mask = exponent_mask<floaty>();
|
||||||
if ((bit_cast<floaty_uint>(value) & mask) == mask)
|
if ((bit_cast<floaty_uint>(value) & mask) == mask)
|
||||||
return write_nonfinite<Char>(out, std::isnan(value), specs, fspecs);
|
return write_nonfinite<Char>(out, std::isnan(value), specs, sign);
|
||||||
|
|
||||||
|
auto fspecs = float_specs();
|
||||||
|
fspecs.sign = sign;
|
||||||
auto dec = dragonbox::to_decimal(static_cast<floaty>(value));
|
auto dec = dragonbox::to_decimal(static_cast<floaty>(value));
|
||||||
return write_float<Char>(out, dec, specs, fspecs, {});
|
return write_float<Char>(out, dec, specs, fspecs, {});
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user