Add support for '%' type to output floating point values as a

percentage.

This helps with compatibility with Python's format strings.
This commit is contained in:
gawain 2019-03-01 20:32:05 +01:00
parent 287eaab3b2
commit 29db6bd91f
3 changed files with 30 additions and 5 deletions

View File

@ -656,7 +656,14 @@ void sprintf_format(Double value, internal::buffer& buf,
*format_ptr++ = '*'; *format_ptr++ = '*';
} }
if (std::is_same<Double, long double>::value) *format_ptr++ = 'L'; if (std::is_same<Double, long double>::value) *format_ptr++ = 'L';
char type = spec.type ? spec.type : 'g';
char type = spec.type;
if (type == '%') {
type = 'f';
} else if (type == 0) {
type = 'g';
}
#if FMT_MSC_VER #if FMT_MSC_VER
if (type == 'F') { if (type == 'F') {
// MSVC's printf doesn't support 'F'. // MSVC's printf doesn't support 'F'.

View File

@ -1274,6 +1274,9 @@ FMT_CONSTEXPR void handle_float_type_spec(char spec, Handler&& handler) {
case 'F': case 'F':
handler.on_fixed(); handler.on_fixed();
break; break;
case '%':
handler.on_percent();
break;
case 'a': case 'a':
case 'A': case 'A':
handler.on_hex(); handler.on_hex();
@ -1338,6 +1341,7 @@ class float_type_checker : private ErrorHandler {
FMT_CONSTEXPR void on_general() {} FMT_CONSTEXPR void on_general() {}
FMT_CONSTEXPR void on_exp() {} FMT_CONSTEXPR void on_exp() {}
FMT_CONSTEXPR void on_fixed() {} FMT_CONSTEXPR void on_fixed() {}
FMT_CONSTEXPR void on_percent() {}
FMT_CONSTEXPR void on_hex() {} FMT_CONSTEXPR void on_hex() {}
FMT_CONSTEXPR void on_error() { FMT_CONSTEXPR void on_error() {
@ -2808,10 +2812,11 @@ template <typename Range> class basic_writer {
struct float_spec_handler { struct float_spec_handler {
char type; char type;
bool upper; bool upper{false};
bool fixed; bool fixed{false};
bool as_percentage{false};
explicit float_spec_handler(char t) : type(t), upper(false), fixed(false) {} explicit float_spec_handler(char t) : type(t) {}
void on_general() { void on_general() {
if (type == 'G') upper = true; if (type == 'G') upper = true;
@ -2826,6 +2831,11 @@ struct float_spec_handler {
if (type == 'F') upper = true; if (type == 'F') upper = true;
} }
void on_percent() {
fixed = true;
as_percentage = true;
}
void on_hex() { void on_hex() {
if (type == 'A') upper = true; if (type == 'A') upper = true;
} }
@ -2869,11 +2879,19 @@ void basic_writer<Range>::write_double(T value, const format_specs& spec) {
memory_buffer buffer; memory_buffer buffer;
int exp = 0; int exp = 0;
int precision = spec.has_precision() || !spec.type ? spec.precision : 6; int precision = spec.has_precision() || !spec.type ? spec.precision : 6;
if (handler.as_percentage) value *= 100.;
bool use_grisu = fmt::internal::use_grisu<T>() && bool use_grisu = fmt::internal::use_grisu<T>() &&
(!spec.type || handler.fixed) && (!spec.type || handler.fixed) &&
internal::grisu2_format(static_cast<double>(value), buffer, internal::grisu2_format(static_cast<double>(value), buffer,
precision, handler.fixed, exp); precision, handler.fixed, exp);
if (!use_grisu) internal::sprintf_format(value, buffer, spec); if (!use_grisu) internal::sprintf_format(value, buffer, spec);
if (handler.as_percentage) {
buffer.push_back('%');
--exp; // Adjust decimal place position.
}
align_spec as = spec; align_spec as = spec;
if (spec.align() == ALIGN_NUMERIC) { if (spec.align() == ALIGN_NUMERIC) {
if (sign) { if (sign) {

View File

@ -1443,7 +1443,7 @@ TEST(FormatterTest, FormatFloat) {
} }
TEST(FormatterTest, FormatDouble) { TEST(FormatterTest, FormatDouble) {
check_unknown_types(1.2, "eEfFgGaA", "double"); check_unknown_types(1.2, "eEfFgGaA%", "double");
EXPECT_EQ("0.0", format("{:}", 0.0)); EXPECT_EQ("0.0", format("{:}", 0.0));
EXPECT_EQ("0.000000", format("{:f}", 0.0)); EXPECT_EQ("0.000000", format("{:f}", 0.0));
EXPECT_EQ("0", format("{:g}", 0.0)); EXPECT_EQ("0", format("{:g}", 0.0));