mirror of
https://github.com/fmtlib/fmt.git
synced 2024-11-23 19:00:09 +00:00
float_spec -> float_specs
This commit is contained in:
parent
9a21728b0a
commit
c68703c9f4
@ -1039,11 +1039,11 @@ void fallback_format(Double d, buffer<char>& buf, int& exp10) {
|
|||||||
// (https://www.cs.tufts.edu/~nr/cs257/archive/florian-loitsch/printf.pdf)
|
// (https://www.cs.tufts.edu/~nr/cs257/archive/florian-loitsch/printf.pdf)
|
||||||
// if T is a IEEE754 binary32 or binary64 and snprintf otherwise.
|
// if T is a IEEE754 binary32 or binary64 and snprintf otherwise.
|
||||||
template <typename T>
|
template <typename T>
|
||||||
int format_float(T value, int precision, float_spec spec, buffer<char>& buf) {
|
int format_float(T value, int precision, float_specs specs, buffer<char>& buf) {
|
||||||
static_assert(!std::is_same<T, float>(), "");
|
static_assert(!std::is_same<T, float>(), "");
|
||||||
FMT_ASSERT(value >= 0, "value is negative");
|
FMT_ASSERT(value >= 0, "value is negative");
|
||||||
|
|
||||||
const bool fixed = spec.format == float_format::fixed;
|
const bool fixed = specs.format == float_format::fixed;
|
||||||
if (value <= 0) { // <= instead of == to silence a warning.
|
if (value <= 0) { // <= instead of == to silence a warning.
|
||||||
if (precision <= 0 || !fixed) {
|
if (precision <= 0 || !fixed) {
|
||||||
buf.push_back('0');
|
buf.push_back('0');
|
||||||
@ -1054,20 +1054,20 @@ int format_float(T value, int precision, float_spec spec, buffer<char>& buf) {
|
|||||||
return -precision;
|
return -precision;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!spec.use_grisu) return snprintf_float(value, precision, spec, buf);
|
if (!specs.use_grisu) return snprintf_float(value, precision, specs, buf);
|
||||||
|
|
||||||
int exp = 0;
|
int exp = 0;
|
||||||
const int min_exp = -60; // alpha in Grisu.
|
const int min_exp = -60; // alpha in Grisu.
|
||||||
int cached_exp10 = 0; // K in Grisu.
|
int cached_exp10 = 0; // K in Grisu.
|
||||||
if (precision != -1) {
|
if (precision != -1) {
|
||||||
if (precision > 17) return snprintf_float(value, precision, spec, buf);
|
if (precision > 17) return snprintf_float(value, precision, specs, buf);
|
||||||
fp normalized = normalize(fp(value));
|
fp normalized = normalize(fp(value));
|
||||||
const auto cached_pow = get_cached_power(
|
const auto cached_pow = get_cached_power(
|
||||||
min_exp - (normalized.e + fp::significand_size), cached_exp10);
|
min_exp - (normalized.e + fp::significand_size), cached_exp10);
|
||||||
normalized = normalized * cached_pow;
|
normalized = normalized * cached_pow;
|
||||||
fixed_handler handler{buf.data(), 0, precision, -cached_exp10, fixed};
|
fixed_handler handler{buf.data(), 0, precision, -cached_exp10, fixed};
|
||||||
if (grisu_gen_digits(normalized, 1, exp, handler) == digits::error)
|
if (grisu_gen_digits(normalized, 1, exp, handler) == digits::error)
|
||||||
return snprintf_float(value, precision, spec, buf);
|
return snprintf_float(value, precision, specs, buf);
|
||||||
int num_digits = handler.size;
|
int num_digits = handler.size;
|
||||||
if (!fixed) {
|
if (!fixed) {
|
||||||
// Remove trailing zeros.
|
// Remove trailing zeros.
|
||||||
@ -1079,7 +1079,7 @@ int format_float(T value, int precision, float_spec spec, buffer<char>& buf) {
|
|||||||
buf.resize(to_unsigned(num_digits));
|
buf.resize(to_unsigned(num_digits));
|
||||||
} else {
|
} else {
|
||||||
fp fp_value;
|
fp fp_value;
|
||||||
auto boundaries = spec.binary32
|
auto boundaries = specs.binary32
|
||||||
? fp_value.assign_float_with_boundaries(value)
|
? fp_value.assign_float_with_boundaries(value)
|
||||||
: fp_value.assign_with_boundaries(value);
|
: fp_value.assign_with_boundaries(value);
|
||||||
fp_value = normalize(fp_value);
|
fp_value = normalize(fp_value);
|
||||||
@ -1111,14 +1111,16 @@ int format_float(T value, int precision, float_spec spec, buffer<char>& buf) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
int snprintf_float(T value, int precision, float_spec spec, buffer<char>& buf) {
|
int snprintf_float(T value, int precision, float_specs specs,
|
||||||
|
buffer<char>& buf) {
|
||||||
// Buffer capacity must be non-zero, otherwise MSVC's vsnprintf_s will fail.
|
// Buffer capacity must be non-zero, otherwise MSVC's vsnprintf_s will fail.
|
||||||
FMT_ASSERT(buf.capacity() > buf.size(), "empty buffer");
|
FMT_ASSERT(buf.capacity() > buf.size(), "empty buffer");
|
||||||
static_assert(!std::is_same<T, float>(), "");
|
static_assert(!std::is_same<T, float>(), "");
|
||||||
|
|
||||||
// Subtract 1 to account for the difference in precision since we use %e for
|
// Subtract 1 to account for the difference in precision since we use %e for
|
||||||
// both general and exponent format.
|
// both general and exponent format.
|
||||||
if (spec.format == float_format::general || spec.format == float_format::exp)
|
if (specs.format == float_format::general ||
|
||||||
|
specs.format == float_format::exp)
|
||||||
precision = (precision >= 0 ? precision : 6) - 1;
|
precision = (precision >= 0 ? precision : 6) - 1;
|
||||||
|
|
||||||
// Build the format string.
|
// Build the format string.
|
||||||
@ -1126,15 +1128,15 @@ int snprintf_float(T value, int precision, float_spec spec, buffer<char>& buf) {
|
|||||||
char format[max_format_size];
|
char format[max_format_size];
|
||||||
char* format_ptr = format;
|
char* format_ptr = format;
|
||||||
*format_ptr++ = '%';
|
*format_ptr++ = '%';
|
||||||
if (spec.alt) *format_ptr++ = '#';
|
if (specs.alt) *format_ptr++ = '#';
|
||||||
if (precision >= 0) {
|
if (precision >= 0) {
|
||||||
*format_ptr++ = '.';
|
*format_ptr++ = '.';
|
||||||
*format_ptr++ = '*';
|
*format_ptr++ = '*';
|
||||||
}
|
}
|
||||||
if (std::is_same<T, long double>()) *format_ptr++ = 'L';
|
if (std::is_same<T, long double>()) *format_ptr++ = 'L';
|
||||||
*format_ptr++ = spec.format != float_format::hex
|
*format_ptr++ = specs.format != float_format::hex
|
||||||
? (spec.format == float_format::fixed ? 'f' : 'e')
|
? (specs.format == float_format::fixed ? 'f' : 'e')
|
||||||
: (spec.upper ? 'A' : 'a');
|
: (specs.upper ? 'A' : 'a');
|
||||||
*format_ptr = '\0';
|
*format_ptr = '\0';
|
||||||
|
|
||||||
// Format using snprintf.
|
// Format using snprintf.
|
||||||
@ -1163,7 +1165,7 @@ int snprintf_float(T value, int precision, float_spec spec, buffer<char>& buf) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
auto is_digit = [](char c) { return c >= '0' && c <= '9'; };
|
auto is_digit = [](char c) { return c >= '0' && c <= '9'; };
|
||||||
if (spec.format == float_format::fixed) {
|
if (specs.format == float_format::fixed) {
|
||||||
if (precision == 0) {
|
if (precision == 0) {
|
||||||
buf.resize(size);
|
buf.resize(size);
|
||||||
return 0;
|
return 0;
|
||||||
@ -1178,7 +1180,7 @@ int snprintf_float(T value, int precision, float_spec spec, buffer<char>& buf) {
|
|||||||
buf.resize(size - 1);
|
buf.resize(size - 1);
|
||||||
return -fraction_size;
|
return -fraction_size;
|
||||||
}
|
}
|
||||||
if (spec.format == float_format::hex) {
|
if (specs.format == float_format::hex) {
|
||||||
buf.resize(size + offset);
|
buf.resize(size + offset);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1062,24 +1062,24 @@ using format_specs = basic_format_specs<char>;
|
|||||||
namespace internal {
|
namespace internal {
|
||||||
|
|
||||||
// A floating-point presentation format.
|
// A floating-point presentation format.
|
||||||
enum class float_format {
|
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
|
hex
|
||||||
};
|
};
|
||||||
|
|
||||||
struct float_spec {
|
struct float_specs {
|
||||||
int precision;
|
int precision;
|
||||||
float_format format;
|
float_format format : 8;
|
||||||
sign_t sign : 3;
|
sign_t sign : 8;
|
||||||
bool upper;
|
bool upper : 1;
|
||||||
bool locale;
|
bool locale : 1;
|
||||||
bool percent;
|
bool percent : 1;
|
||||||
bool alt;
|
bool alt : 1;
|
||||||
bool binary32;
|
bool binary32 : 1;
|
||||||
bool use_grisu;
|
bool use_grisu : 1;
|
||||||
bool trailing_zeros;
|
bool trailing_zeros : 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Writes the exponent exp in the form "[+-]d{2,3}" to buffer.
|
// Writes the exponent exp in the form "[+-]d{2,3}" to buffer.
|
||||||
@ -1110,7 +1110,7 @@ template <typename Char> class float_writer {
|
|||||||
int num_digits_;
|
int num_digits_;
|
||||||
int exp_;
|
int exp_;
|
||||||
size_t size_;
|
size_t size_;
|
||||||
float_spec params_;
|
float_specs params_;
|
||||||
Char decimal_point_;
|
Char decimal_point_;
|
||||||
|
|
||||||
template <typename It> It prettify(It it) const {
|
template <typename It> It prettify(It it) const {
|
||||||
@ -1182,21 +1182,21 @@ template <typename Char> class float_writer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
float_writer(const char* digits, int num_digits, int exp, float_spec spec,
|
float_writer(const char* digits, int num_digits, int exp, float_specs specs,
|
||||||
Char decimal_point)
|
Char decimal_point)
|
||||||
: digits_(digits),
|
: digits_(digits),
|
||||||
num_digits_(num_digits),
|
num_digits_(num_digits),
|
||||||
exp_(exp),
|
exp_(exp),
|
||||||
params_(spec),
|
params_(specs),
|
||||||
decimal_point_(decimal_point) {
|
decimal_point_(decimal_point) {
|
||||||
int full_exp = num_digits + exp - 1;
|
int full_exp = num_digits + exp - 1;
|
||||||
int precision = spec.precision > 0 ? spec.precision : 16;
|
int precision = specs.precision > 0 ? specs.precision : 16;
|
||||||
if (params_.format == float_format::general &&
|
if (params_.format == float_format::general &&
|
||||||
!(full_exp >= -4 && full_exp < precision)) {
|
!(full_exp >= -4 && full_exp < precision)) {
|
||||||
params_.format = float_format::exp;
|
params_.format = float_format::exp;
|
||||||
}
|
}
|
||||||
size_ = prettify(counting_iterator()).count();
|
size_ = prettify(counting_iterator()).count();
|
||||||
size_ += spec.sign ? 1 : 0;
|
size_ += specs.sign ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t size() const { return size_; }
|
size_t size() const { return size_; }
|
||||||
@ -1209,11 +1209,12 @@ template <typename Char> class float_writer {
|
|||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
int format_float(T value, int precision, float_spec spec, buffer<char>& buf);
|
int format_float(T value, int precision, float_specs specs, buffer<char>& buf);
|
||||||
|
|
||||||
// Formats a floating-point number with snprintf.
|
// Formats a floating-point number with snprintf.
|
||||||
template <typename T>
|
template <typename T>
|
||||||
int snprintf_float(T value, int precision, float_spec spec, buffer<char>& buf);
|
int snprintf_float(T value, int precision, float_specs specs,
|
||||||
|
buffer<char>& buf);
|
||||||
|
|
||||||
template <typename T> T promote_float(T value) { return value; }
|
template <typename T> T promote_float(T value) { return value; }
|
||||||
inline double promote_float(float value) { return value; }
|
inline double promote_float(float value) { return value; }
|
||||||
@ -1245,9 +1246,9 @@ FMT_CONSTEXPR void handle_int_type_spec(char spec, Handler&& handler) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename ErrorHandler = error_handler>
|
template <typename ErrorHandler = error_handler>
|
||||||
FMT_CONSTEXPR float_spec parse_float_type_spec(char spec,
|
FMT_CONSTEXPR float_specs parse_float_type_spec(char spec,
|
||||||
ErrorHandler&& eh = {}) {
|
ErrorHandler&& eh = {}) {
|
||||||
auto result = float_spec();
|
auto result = float_specs();
|
||||||
switch (spec) {
|
switch (spec) {
|
||||||
case 'G':
|
case 'G':
|
||||||
result.upper = true;
|
result.upper = true;
|
||||||
@ -1690,62 +1691,63 @@ template <typename Range> class basic_writer {
|
|||||||
|
|
||||||
template <typename T, FMT_ENABLE_IF(std::is_floating_point<T>::value)>
|
template <typename T, FMT_ENABLE_IF(std::is_floating_point<T>::value)>
|
||||||
void write(T value, format_specs specs = {}) {
|
void write(T value, format_specs specs = {}) {
|
||||||
float_spec fspec = parse_float_type_spec(specs.type);
|
float_specs fspecs = parse_float_type_spec(specs.type);
|
||||||
fspec.sign = specs.sign;
|
fspecs.sign = specs.sign;
|
||||||
if (std::signbit(value)) { // value < 0 is false for NaN so use signbit.
|
if (std::signbit(value)) { // value < 0 is false for NaN so use signbit.
|
||||||
fspec.sign = sign::minus;
|
fspecs.sign = sign::minus;
|
||||||
value = -value;
|
value = -value;
|
||||||
} else if (fspec.sign == sign::minus) {
|
} else if (fspecs.sign == sign::minus) {
|
||||||
fspec.sign = sign::none;
|
fspecs.sign = sign::none;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!std::isfinite(value)) {
|
if (!std::isfinite(value)) {
|
||||||
auto str = std::isinf(value) ? (fspec.upper ? "INF" : "inf")
|
auto str = std::isinf(value) ? (fspecs.upper ? "INF" : "inf")
|
||||||
: (fspec.upper ? "NAN" : "nan");
|
: (fspecs.upper ? "NAN" : "nan");
|
||||||
return write_padded(specs, inf_or_nan_writer<char_type>{fspec.sign, str});
|
return write_padded(specs,
|
||||||
|
inf_or_nan_writer<char_type>{fspecs.sign, str});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (specs.align == align::none) {
|
if (specs.align == align::none) {
|
||||||
specs.align = align::right;
|
specs.align = align::right;
|
||||||
} else if (specs.align == align::numeric) {
|
} else if (specs.align == align::numeric) {
|
||||||
if (fspec.sign) {
|
if (fspecs.sign) {
|
||||||
auto&& it = reserve(1);
|
auto&& it = reserve(1);
|
||||||
*it++ = static_cast<char_type>(data::signs[fspec.sign]);
|
*it++ = static_cast<char_type>(data::signs[fspecs.sign]);
|
||||||
fspec.sign = sign::none;
|
fspecs.sign = sign::none;
|
||||||
if (specs.width != 0) --specs.width;
|
if (specs.width != 0) --specs.width;
|
||||||
}
|
}
|
||||||
specs.align = align::right;
|
specs.align = align::right;
|
||||||
}
|
}
|
||||||
|
|
||||||
memory_buffer buffer;
|
memory_buffer buffer;
|
||||||
if (fspec.format == float_format::hex) {
|
if (fspecs.format == float_format::hex) {
|
||||||
if (fspec.sign) buffer.push_back(data::signs[fspec.sign]);
|
if (fspecs.sign) buffer.push_back(data::signs[fspecs.sign]);
|
||||||
fspec.alt = specs.alt;
|
fspecs.alt = specs.alt;
|
||||||
snprintf_float(promote_float(value), specs.precision, fspec, buffer);
|
snprintf_float(promote_float(value), specs.precision, fspecs, buffer);
|
||||||
write_padded(specs, str_writer<char>{buffer.data(), buffer.size()});
|
write_padded(specs, str_writer<char>{buffer.data(), buffer.size()});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
int precision = specs.precision >= 0 || !specs.type ? specs.precision : 6;
|
int precision = specs.precision >= 0 || !specs.type ? specs.precision : 6;
|
||||||
if (fspec.format == float_format::exp) ++precision;
|
if (fspecs.format == float_format::exp) ++precision;
|
||||||
fspec.trailing_zeros =
|
fspecs.trailing_zeros =
|
||||||
(precision != 0 &&
|
(precision != 0 &&
|
||||||
(!specs.type || fspec.format == float_format::fixed ||
|
(!specs.type || fspecs.format == float_format::fixed ||
|
||||||
fspec.format == float_format::exp)) ||
|
fspecs.format == float_format::exp)) ||
|
||||||
specs.alt;
|
specs.alt;
|
||||||
if (const_check(std::is_same<T, float>())) fspec.binary32 = true;
|
if (const_check(std::is_same<T, float>())) fspecs.binary32 = true;
|
||||||
fspec.use_grisu = use_grisu<T>();
|
fspecs.use_grisu = use_grisu<T>();
|
||||||
if (const_check(FMT_DEPRECATED_PERCENT) && fspec.percent) value *= 100;
|
if (const_check(FMT_DEPRECATED_PERCENT) && fspecs.percent) value *= 100;
|
||||||
int exp = format_float(promote_float(value), precision, fspec, buffer);
|
int exp = format_float(promote_float(value), precision, fspecs, buffer);
|
||||||
if (const_check(FMT_DEPRECATED_PERCENT) && fspec.percent) {
|
if (const_check(FMT_DEPRECATED_PERCENT) && fspecs.percent) {
|
||||||
buffer.push_back('%');
|
buffer.push_back('%');
|
||||||
--exp; // Adjust decimal place position.
|
--exp; // Adjust decimal place position.
|
||||||
}
|
}
|
||||||
fspec.precision = precision;
|
fspecs.precision = precision;
|
||||||
char_type point = fspec.locale ? decimal_point<char_type>(locale_)
|
char_type point = fspecs.locale ? decimal_point<char_type>(locale_)
|
||||||
: static_cast<char_type>('.');
|
: static_cast<char_type>('.');
|
||||||
write_padded(specs, float_writer<char_type>(buffer.data(),
|
write_padded(specs, float_writer<char_type>(buffer.data(),
|
||||||
static_cast<int>(buffer.size()),
|
static_cast<int>(buffer.size()),
|
||||||
exp, fspec, point));
|
exp, fspecs, point));
|
||||||
}
|
}
|
||||||
|
|
||||||
void write(char value) {
|
void write(char value) {
|
||||||
|
@ -11,7 +11,7 @@ FMT_BEGIN_NAMESPACE
|
|||||||
template struct FMT_API internal::basic_data<void>;
|
template struct FMT_API internal::basic_data<void>;
|
||||||
|
|
||||||
// Workaround a bug in MSVC2013 that prevents instantiation of format_float.
|
// Workaround a bug in MSVC2013 that prevents instantiation of format_float.
|
||||||
int (*instantiate_format_float)(double, int, internal::float_spec,
|
int (*instantiate_format_float)(double, int, internal::float_specs,
|
||||||
internal::buffer<char>&) =
|
internal::buffer<char>&) =
|
||||||
internal::format_float;
|
internal::format_float;
|
||||||
|
|
||||||
@ -37,15 +37,16 @@ template FMT_API std::string internal::vformat<char>(
|
|||||||
template FMT_API format_context::iterator internal::vformat_to(
|
template FMT_API format_context::iterator internal::vformat_to(
|
||||||
internal::buffer<char>&, string_view, basic_format_args<format_context>);
|
internal::buffer<char>&, string_view, basic_format_args<format_context>);
|
||||||
|
|
||||||
template FMT_API int internal::snprintf_float(double, int, internal::float_spec,
|
template FMT_API int internal::snprintf_float(double, int,
|
||||||
|
internal::float_specs,
|
||||||
internal::buffer<char>&);
|
internal::buffer<char>&);
|
||||||
template FMT_API int internal::snprintf_float(long double, int,
|
template FMT_API int internal::snprintf_float(long double, int,
|
||||||
internal::float_spec,
|
internal::float_specs,
|
||||||
internal::buffer<char>&);
|
internal::buffer<char>&);
|
||||||
template FMT_API int internal::format_float(double, int, internal::float_spec,
|
template FMT_API int internal::format_float(double, int, internal::float_specs,
|
||||||
internal::buffer<char>&);
|
internal::buffer<char>&);
|
||||||
template FMT_API int internal::format_float(long double, int,
|
template FMT_API int internal::format_float(long double, int,
|
||||||
internal::float_spec,
|
internal::float_specs,
|
||||||
internal::buffer<char>&);
|
internal::buffer<char>&);
|
||||||
|
|
||||||
// Explicit instantiations for wchar_t.
|
// Explicit instantiations for wchar_t.
|
||||||
|
@ -318,7 +318,7 @@ TEST(FPTest, FixedHandler) {
|
|||||||
|
|
||||||
TEST(FPTest, GrisuFormatCompilesWithNonIEEEDouble) {
|
TEST(FPTest, GrisuFormatCompilesWithNonIEEEDouble) {
|
||||||
fmt::memory_buffer buf;
|
fmt::memory_buffer buf;
|
||||||
format_float(0.42, -1, fmt::internal::float_spec(), buf);
|
format_float(0.42, -1, fmt::internal::float_specs(), buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T> struct value_extractor {
|
template <typename T> struct value_extractor {
|
||||||
|
Loading…
Reference in New Issue
Block a user