Use the decimal point from locale
This commit is contained in:
parent
476f25cd81
commit
bc14c6ee20
@ -210,12 +210,20 @@ template <typename Char> FMT_FUNC Char thousands_sep_impl(locale_ref loc) {
|
||||
return std::use_facet<std::numpunct<Char>>(loc.get<std::locale>())
|
||||
.thousands_sep();
|
||||
}
|
||||
template <typename Char> FMT_FUNC Char decimal_point_impl(locale_ref loc) {
|
||||
return std::use_facet<std::numpunct<Char>>(loc.get<std::locale>())
|
||||
.decimal_point();
|
||||
}
|
||||
} // namespace internal
|
||||
#else
|
||||
template <typename Char>
|
||||
FMT_FUNC Char internal::thousands_sep_impl(locale_ref) {
|
||||
return FMT_STATIC_THOUSANDS_SEPARATOR;
|
||||
}
|
||||
template <typename Char>
|
||||
FMT_FUNC Char internal::decimal_point_impl(locale_ref) {
|
||||
return '.';
|
||||
}
|
||||
#endif
|
||||
|
||||
FMT_API FMT_FUNC format_error::~format_error() FMT_NOEXCEPT {}
|
||||
|
@ -742,15 +742,21 @@ inline int count_digits(uint32_t n) {
|
||||
#endif
|
||||
|
||||
template <typename Char> FMT_API Char thousands_sep_impl(locale_ref loc);
|
||||
|
||||
template <typename Char> inline Char thousands_sep(locale_ref loc) {
|
||||
return Char(thousands_sep_impl<char>(loc));
|
||||
}
|
||||
|
||||
template <> inline wchar_t thousands_sep(locale_ref loc) {
|
||||
return thousands_sep_impl<wchar_t>(loc);
|
||||
}
|
||||
|
||||
template <typename Char> FMT_API Char decimal_point_impl(locale_ref loc);
|
||||
template <typename Char> inline Char decimal_point(locale_ref loc) {
|
||||
return Char(decimal_point_impl<char>(loc));
|
||||
}
|
||||
template <> inline wchar_t decimal_point(locale_ref loc) {
|
||||
return decimal_point_impl<wchar_t>(loc);
|
||||
}
|
||||
|
||||
// Formats a decimal unsigned integer value writing into buffer.
|
||||
// add_thousands_sep is called after writing each char to add a thousands
|
||||
// separator if necessary.
|
||||
@ -985,13 +991,13 @@ template <typename Char, typename It> It write_exponent(int exp, It it) {
|
||||
// The number is given as v = digits * pow(10, exp).
|
||||
template <typename Char, typename It>
|
||||
It grisu_prettify(const char* digits, int size, int exp, It it,
|
||||
gen_digits_params params) {
|
||||
gen_digits_params params, Char decimal_point) {
|
||||
// pow(10, full_exp - 1) <= v <= pow(10, full_exp).
|
||||
int full_exp = size + exp;
|
||||
if (!params.fixed) {
|
||||
// Insert a decimal point after the first digit and add an exponent.
|
||||
*it++ = static_cast<Char>(*digits);
|
||||
if (size > 1) *it++ = static_cast<Char>('.');
|
||||
if (size > 1) *it++ = decimal_point;
|
||||
exp += size - 1;
|
||||
it = copy_str<Char>(digits + 1, digits + size, it);
|
||||
if (size < params.num_digits)
|
||||
@ -1005,7 +1011,7 @@ It grisu_prettify(const char* digits, int size, int exp, It it,
|
||||
it = std::fill_n(it, full_exp - size, static_cast<Char>('0'));
|
||||
int num_zeros = (std::max)(params.num_digits - full_exp, 1);
|
||||
if (params.trailing_zeros) {
|
||||
*it++ = static_cast<Char>('.');
|
||||
*it++ = decimal_point;
|
||||
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
|
||||
if (num_zeros > 1000)
|
||||
throw std::runtime_error("fuzz mode - avoiding excessive cpu use");
|
||||
@ -1018,10 +1024,10 @@ It grisu_prettify(const char* digits, int size, int exp, It it,
|
||||
if (!params.trailing_zeros) {
|
||||
// Remove trailing zeros.
|
||||
while (size > full_exp && digits[size - 1] == '0') --size;
|
||||
if (size != full_exp) *it++ = static_cast<Char>('.');
|
||||
if (size != full_exp) *it++ = decimal_point;
|
||||
return copy_str<Char>(digits + full_exp, digits + size, it);
|
||||
}
|
||||
*it++ = static_cast<Char>('.');
|
||||
*it++ = decimal_point;
|
||||
it = copy_str<Char>(digits + full_exp, digits + size, it);
|
||||
if (params.num_digits > size) {
|
||||
// Add trailing zeros.
|
||||
@ -1037,7 +1043,7 @@ It grisu_prettify(const char* digits, int size, int exp, It it,
|
||||
if (!params.trailing_zeros)
|
||||
while (size > 0 && digits[size - 1] == '0') --size;
|
||||
if (num_zeros != 0 || size != 0) {
|
||||
*it++ = static_cast<Char>('.');
|
||||
*it++ = decimal_point;
|
||||
it = std::fill_n(it, num_zeros, static_cast<Char>('0'));
|
||||
it = copy_str<Char>(digits, digits + size, it);
|
||||
}
|
||||
@ -1453,18 +1459,24 @@ template <typename Range> class basic_writer {
|
||||
char sign_;
|
||||
int exp_;
|
||||
internal::gen_digits_params params_;
|
||||
char_type decimal_point_;
|
||||
|
||||
public:
|
||||
grisu_writer(char sign, internal::buffer<char>& digits, int exp,
|
||||
const internal::gen_digits_params& params)
|
||||
: digits_(digits), sign_(sign), exp_(exp), params_(params) {
|
||||
const internal::gen_digits_params& params,
|
||||
char_type decimal_point)
|
||||
: digits_(digits),
|
||||
sign_(sign),
|
||||
exp_(exp),
|
||||
params_(params),
|
||||
decimal_point_(decimal_point) {
|
||||
int num_digits = static_cast<int>(digits.size());
|
||||
int full_exp = num_digits + exp - 1;
|
||||
int precision = params.num_digits > 0 ? params.num_digits : 11;
|
||||
params_.fixed |= full_exp >= -4 && full_exp < precision;
|
||||
auto it = internal::grisu_prettify<char>(
|
||||
digits.data(), num_digits, exp, internal::counting_iterator<char>(),
|
||||
params_);
|
||||
params_, '.');
|
||||
size_ = it.count();
|
||||
}
|
||||
|
||||
@ -1475,7 +1487,7 @@ template <typename Range> class basic_writer {
|
||||
if (sign_) *it++ = static_cast<char_type>(sign_);
|
||||
int num_digits = static_cast<int>(digits_.size());
|
||||
it = internal::grisu_prettify<char_type>(digits_.data(), num_digits, exp_,
|
||||
it, params_);
|
||||
it, params_, decimal_point_);
|
||||
}
|
||||
};
|
||||
|
||||
@ -2739,15 +2751,18 @@ void internal::basic_writer<Range>::write_double(T value,
|
||||
} else if (spec.align() == ALIGN_DEFAULT) {
|
||||
as.align_ = ALIGN_RIGHT;
|
||||
}
|
||||
// TODO: add thousands separators if handler.use_locale is set
|
||||
char_type decimal_point = handler.use_locale
|
||||
? internal::decimal_point<char_type>(locale_)
|
||||
: static_cast<char_type>('.');
|
||||
if (use_grisu) {
|
||||
auto params = internal::gen_digits_params();
|
||||
params.fixed = handler.fixed;
|
||||
params.num_digits = precision;
|
||||
params.trailing_zeros = (precision != 0 && (handler.fixed || !spec.type)) ||
|
||||
spec.has(HASH_FLAG);
|
||||
write_padded(as, grisu_writer{sign, buffer, exp, params});
|
||||
write_padded(as, grisu_writer(sign, buffer, exp, params, decimal_point));
|
||||
} else {
|
||||
// TODO: set decimal point
|
||||
write_padded(as, double_writer{sign, buffer});
|
||||
}
|
||||
}
|
||||
|
@ -22,6 +22,7 @@ template FMT_API std::locale internal::locale_ref::get<std::locale>() const;
|
||||
// Explicit instantiations for char.
|
||||
|
||||
template FMT_API char internal::thousands_sep_impl(locale_ref);
|
||||
template FMT_API char internal::decimal_point_impl(locale_ref);
|
||||
|
||||
template FMT_API void internal::buffer<char>::append(const char*, const char*);
|
||||
|
||||
@ -43,6 +44,7 @@ template FMT_API void internal::sprintf_format(long double,
|
||||
// Explicit instantiations for wchar_t.
|
||||
|
||||
template FMT_API wchar_t internal::thousands_sep_impl(locale_ref);
|
||||
template FMT_API wchar_t internal::decimal_point_impl(locale_ref);
|
||||
|
||||
template FMT_API void internal::buffer<wchar_t>::append(const wchar_t*,
|
||||
const wchar_t*);
|
||||
|
@ -1447,10 +1447,6 @@ TEST(FormatterTest, FormatDouble) {
|
||||
EXPECT_EQ(buffer, format("{:A}", -42.0));
|
||||
}
|
||||
|
||||
TEST(FormatterTest, FormatDoubleLocale) {
|
||||
EXPECT_EQ("1.23", format("{:n}", 1.23));
|
||||
}
|
||||
|
||||
TEST(FormatterTest, PrecisionRounding) {
|
||||
EXPECT_EQ("0", format("{:.0f}", 0.0));
|
||||
EXPECT_EQ("0", format("{:.0f}", 0.01));
|
||||
|
@ -11,9 +11,15 @@
|
||||
#ifndef FMT_STATIC_THOUSANDS_SEPARATOR
|
||||
template <typename Char> struct numpunct : std::numpunct<Char> {
|
||||
protected:
|
||||
Char do_decimal_point() const FMT_OVERRIDE { return '?'; }
|
||||
Char do_thousands_sep() const FMT_OVERRIDE { return '~'; }
|
||||
};
|
||||
|
||||
TEST(LocaleTest, DoubleDecimalPoint) {
|
||||
std::locale loc(std::locale(), new numpunct<char>());
|
||||
EXPECT_EQ("1?23", fmt::format(loc, "{:n}", 1.23));
|
||||
}
|
||||
|
||||
TEST(LocaleTest, Format) {
|
||||
std::locale loc(std::locale(), new numpunct<char>());
|
||||
EXPECT_EQ("1,234,567", fmt::format(std::locale(), "{:n}", 1234567));
|
||||
|
Loading…
Reference in New Issue
Block a user