mirror of
https://github.com/shadps4-emu/ext-fmt.git
synced 2024-11-24 18:29:41 +00:00
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:
parent
287eaab3b2
commit
79b79f329e
@ -539,8 +539,7 @@ struct fixed_stop {
|
|||||||
void on_exp(int exp) {
|
void on_exp(int exp) {
|
||||||
if (!fixed) return;
|
if (!fixed) return;
|
||||||
exp += exp10;
|
exp += exp10;
|
||||||
if (exp >= 0)
|
if (exp >= 0) precision += exp;
|
||||||
precision += exp;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator()(char*, int& size, uint64_t remainder, uint64_t divisor,
|
bool operator()(char*, int& size, uint64_t remainder, uint64_t divisor,
|
||||||
@ -656,7 +655,13 @@ 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'.
|
||||||
|
@ -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() {
|
||||||
@ -2642,10 +2646,12 @@ template <typename Range> class basic_writer {
|
|||||||
|
|
||||||
struct inf_or_nan_writer {
|
struct inf_or_nan_writer {
|
||||||
char sign;
|
char sign;
|
||||||
|
bool as_percentage;
|
||||||
const char* str;
|
const char* str;
|
||||||
|
|
||||||
size_t size() const {
|
size_t size() const {
|
||||||
return static_cast<std::size_t>(INF_SIZE + (sign ? 1 : 0));
|
return static_cast<std::size_t>(INF_SIZE + (sign ? 1 : 0) +
|
||||||
|
(as_percentage ? 1 : 0));
|
||||||
}
|
}
|
||||||
size_t width() const { return size(); }
|
size_t width() const { return size(); }
|
||||||
|
|
||||||
@ -2653,6 +2659,7 @@ template <typename Range> class basic_writer {
|
|||||||
if (sign) *it++ = static_cast<char_type>(sign);
|
if (sign) *it++ = static_cast<char_type>(sign);
|
||||||
it = internal::copy_str<char_type>(
|
it = internal::copy_str<char_type>(
|
||||||
str, str + static_cast<std::size_t>(INF_SIZE), it);
|
str, str + static_cast<std::size_t>(INF_SIZE), it);
|
||||||
|
if (as_percentage) *it++ = static_cast<char_type>('%');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -2810,8 +2817,10 @@ struct float_spec_handler {
|
|||||||
char type;
|
char type;
|
||||||
bool upper;
|
bool upper;
|
||||||
bool fixed;
|
bool fixed;
|
||||||
|
bool as_percentage;
|
||||||
|
|
||||||
explicit float_spec_handler(char t) : type(t), upper(false), fixed(false) {}
|
explicit float_spec_handler(char t)
|
||||||
|
: type(t), upper(false), fixed(false), as_percentage(false) {}
|
||||||
|
|
||||||
void on_general() {
|
void on_general() {
|
||||||
if (type == 'G') upper = true;
|
if (type == 'G') upper = true;
|
||||||
@ -2826,6 +2835,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;
|
||||||
}
|
}
|
||||||
@ -2854,10 +2868,11 @@ void basic_writer<Range>::write_double(T value, const format_specs& spec) {
|
|||||||
basic_writer& writer;
|
basic_writer& writer;
|
||||||
format_specs spec;
|
format_specs spec;
|
||||||
char sign;
|
char sign;
|
||||||
|
bool as_percentage;
|
||||||
void operator()(const char* str) const {
|
void operator()(const char* str) const {
|
||||||
writer.write_padded(spec, inf_or_nan_writer{sign, str});
|
writer.write_padded(spec, inf_or_nan_writer{sign, as_percentage, str});
|
||||||
}
|
}
|
||||||
} write_inf_or_nan = {*this, spec, sign};
|
} write_inf_or_nan = {*this, spec, sign, handler.as_percentage};
|
||||||
|
|
||||||
// Format NaN and ininity ourselves because sprintf's output is not consistent
|
// Format NaN and ininity ourselves because sprintf's output is not consistent
|
||||||
// across platforms.
|
// across platforms.
|
||||||
@ -2869,11 +2884,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) {
|
||||||
|
@ -1207,6 +1207,8 @@ TEST(FormatterTest, Precision) {
|
|||||||
"precision not allowed for this argument type");
|
"precision not allowed for this argument type");
|
||||||
EXPECT_THROW_MSG(format("{0:.2f}", 42ull), format_error,
|
EXPECT_THROW_MSG(format("{0:.2f}", 42ull), format_error,
|
||||||
"precision not allowed for this argument type");
|
"precision not allowed for this argument type");
|
||||||
|
EXPECT_THROW_MSG(format("{0:.2%}", 42), format_error,
|
||||||
|
"precision not allowed for this argument type");
|
||||||
EXPECT_THROW_MSG(format("{0:3.0}", 'x'), format_error,
|
EXPECT_THROW_MSG(format("{0:3.0}", 'x'), format_error,
|
||||||
"precision not allowed for this argument type");
|
"precision not allowed for this argument type");
|
||||||
EXPECT_EQ("1.2", format("{0:.2}", 1.2345));
|
EXPECT_EQ("1.2", format("{0:.2}", 1.2345));
|
||||||
@ -1440,10 +1442,11 @@ TEST(FormatterTest, FormatConvertibleToLongLong) {
|
|||||||
|
|
||||||
TEST(FormatterTest, FormatFloat) {
|
TEST(FormatterTest, FormatFloat) {
|
||||||
EXPECT_EQ("392.500000", format("{0:f}", 392.5f));
|
EXPECT_EQ("392.500000", format("{0:f}", 392.5f));
|
||||||
|
EXPECT_EQ("12.500000%", format("{0:%}", 0.125f));
|
||||||
}
|
}
|
||||||
|
|
||||||
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));
|
||||||
@ -1452,6 +1455,8 @@ TEST(FormatterTest, FormatDouble) {
|
|||||||
EXPECT_EQ("392.65", format("{:G}", 392.65));
|
EXPECT_EQ("392.65", format("{:G}", 392.65));
|
||||||
EXPECT_EQ("392.650000", format("{:f}", 392.65));
|
EXPECT_EQ("392.650000", format("{:f}", 392.65));
|
||||||
EXPECT_EQ("392.650000", format("{:F}", 392.65));
|
EXPECT_EQ("392.650000", format("{:F}", 392.65));
|
||||||
|
EXPECT_EQ("12.500000%", format("{:%}", 0.125));
|
||||||
|
EXPECT_EQ("12.34%", format("{:.2%}", 0.1234432));
|
||||||
char buffer[BUFFER_SIZE];
|
char buffer[BUFFER_SIZE];
|
||||||
safe_sprintf(buffer, "%e", 392.65);
|
safe_sprintf(buffer, "%e", 392.65);
|
||||||
EXPECT_EQ(buffer, format("{0:e}", 392.65));
|
EXPECT_EQ(buffer, format("{0:e}", 392.65));
|
||||||
@ -1473,6 +1478,7 @@ TEST(FormatterTest, FormatNaN) {
|
|||||||
EXPECT_EQ("nan ", format("{:<7}", nan));
|
EXPECT_EQ("nan ", format("{:<7}", nan));
|
||||||
EXPECT_EQ(" nan ", format("{:^7}", nan));
|
EXPECT_EQ(" nan ", format("{:^7}", nan));
|
||||||
EXPECT_EQ(" nan", format("{:>7}", nan));
|
EXPECT_EQ(" nan", format("{:>7}", nan));
|
||||||
|
EXPECT_EQ("nan%", format("{:%}", nan));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(FormatterTest, FormatInfinity) {
|
TEST(FormatterTest, FormatInfinity) {
|
||||||
@ -1485,6 +1491,7 @@ TEST(FormatterTest, FormatInfinity) {
|
|||||||
EXPECT_EQ("inf ", format("{:<7}", inf));
|
EXPECT_EQ("inf ", format("{:<7}", inf));
|
||||||
EXPECT_EQ(" inf ", format("{:^7}", inf));
|
EXPECT_EQ(" inf ", format("{:^7}", inf));
|
||||||
EXPECT_EQ(" inf", format("{:>7}", inf));
|
EXPECT_EQ(" inf", format("{:>7}", inf));
|
||||||
|
EXPECT_EQ("inf%", format("{:%}", inf));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(FormatterTest, FormatLongDouble) {
|
TEST(FormatterTest, FormatLongDouble) {
|
||||||
@ -1495,6 +1502,8 @@ TEST(FormatterTest, FormatLongDouble) {
|
|||||||
EXPECT_EQ("392.65", format("{0:G}", 392.65l));
|
EXPECT_EQ("392.65", format("{0:G}", 392.65l));
|
||||||
EXPECT_EQ("392.650000", format("{0:f}", 392.65l));
|
EXPECT_EQ("392.650000", format("{0:f}", 392.65l));
|
||||||
EXPECT_EQ("392.650000", format("{0:F}", 392.65l));
|
EXPECT_EQ("392.650000", format("{0:F}", 392.65l));
|
||||||
|
EXPECT_EQ("12.500000%", format("{:%}", 0.125l));
|
||||||
|
EXPECT_EQ("12.34%", format("{:.2%}", 0.1234432l));
|
||||||
char buffer[BUFFER_SIZE];
|
char buffer[BUFFER_SIZE];
|
||||||
safe_sprintf(buffer, "%Le", 392.65l);
|
safe_sprintf(buffer, "%Le", 392.65l);
|
||||||
EXPECT_EQ(buffer, format("{0:e}", 392.65l));
|
EXPECT_EQ(buffer, format("{0:e}", 392.65l));
|
||||||
|
Loading…
Reference in New Issue
Block a user