diff --git a/include/fmt/format-inl.h b/include/fmt/format-inl.h index 75fa163b..465dd6b0 100644 --- a/include/fmt/format-inl.h +++ b/include/fmt/format-inl.h @@ -116,45 +116,60 @@ template FMT_FUNC Char decimal_point_impl(locale_ref) { } #endif -FMT_FUNC auto write_int(appender out, basic_format_arg value, +FMT_FUNC auto write_loc(appender out, basic_format_arg value, const format_specs& specs, locale_ref loc) -> bool { #ifndef FMT_STATIC_THOUSANDS_SEPARATOR auto locale = loc.get(); // We cannot use the num_put facet because it may produce output in // a wrong encoding. - if (!std::has_facet>(locale)) return {}; - std::use_facet>(locale).put(out, value, specs); - return true; + using facet = format_facet; + if (std::has_facet(locale)) + return std::use_facet(locale).put(out, value, specs); + return facet(locale).put(out, value, specs); #endif return false; } -struct localize_int { +struct localizer { appender out; const format_specs& specs; std::string sep; std::string grouping; + std::string decimal_point; template ::value)> - void operator()(T value) { + auto operator()(T value) -> bool { auto arg = make_write_int_arg(value, specs.sign); write_int(out, static_cast>(arg.abs_value), arg.prefix, specs, digit_grouping(grouping, sep)); + return true; } - template ::value)> - void operator()(T) {} + + template ::value)> + auto operator()(T) -> bool { + return false; + } + + auto operator()(...) -> bool { return false; } }; } // namespace detail template typename Locale::id format_facet::id; #ifndef FMT_STATIC_THOUSANDS_SEPARATOR +template format_facet::format_facet(Locale& loc) { + auto& numpunct = std::use_facet>(loc); + grouping_ = numpunct.grouping(); + if (!grouping_.empty()) separator_ = std::string(1, numpunct.thousands_sep()); +} + template <> -FMT_API FMT_FUNC void format_facet::do_put( +FMT_API FMT_FUNC auto format_facet::do_put( appender out, basic_format_arg val, - const format_specs& specs) const { - visit_format_arg(detail::localize_int{out, specs, separator_, grouping_}, - val); + const format_specs& specs) const -> bool { + return visit_format_arg( + detail::localizer{out, specs, separator_, grouping_, decimal_point_}, + val); } #endif diff --git a/include/fmt/format.h b/include/fmt/format.h index 5e17a0a1..c2bff6c4 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -992,21 +992,26 @@ template class format_facet : public Locale::facet { private: std::string separator_; std::string grouping_; + std::string decimal_point_; protected: - virtual void do_put(appender out, basic_format_arg val, - const format_specs& specs) const; + virtual auto do_put(appender out, basic_format_arg val, + const format_specs& specs) const -> bool; public: static FMT_API typename Locale::id id; - explicit format_facet(string_view sep = ",", - std::initializer_list g = {3}) - : separator_(sep.data(), sep.size()), grouping_(g.begin(), g.end()) {} + explicit format_facet(Locale& loc); + explicit format_facet(string_view sep = "", + std::initializer_list g = {3}, + std::string decimal_point = ".") + : separator_(sep.data(), sep.size()), + grouping_(g.begin(), g.end()), + decimal_point_(decimal_point) {} - void put(appender out, basic_format_arg val, - const format_specs& specs) const { - do_put(out, val, specs); + auto put(appender out, basic_format_arg val, + const format_specs& specs) const -> bool { + return do_put(out, val, specs); } }; @@ -2042,10 +2047,11 @@ auto write_int(OutputIt out, UInt value, unsigned prefix, }); } -FMT_API auto write_int(appender out, basic_format_arg value, +// Writes value with localization. +FMT_API auto write_loc(appender out, basic_format_arg value, const format_specs& specs, locale_ref loc) -> bool; template -inline auto write_int(OutputIt, basic_format_arg>, +inline auto write_loc(OutputIt, basic_format_arg>, const basic_format_specs&, locale_ref) -> bool { return false; } @@ -4165,8 +4171,8 @@ void vformat_to(buffer& buf, basic_string_view fmt, begin = parse_format_specs(begin, end, handler); if (begin == end || *begin != '}') on_error("missing '}' in format string"); - if (specs.localized && arg.is_integral() && - write_int(context.out(), arg, specs, context.locale())) { + if (specs.localized && + write_loc(context.out(), arg, specs, context.locale())) { return begin; } auto f = arg_formatter{context.out(), specs, context.locale()}; diff --git a/test/format-test.cc b/test/format-test.cc index 85f1af49..ee722ab3 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -2322,21 +2322,25 @@ class format_facet : public fmt::format_facet { fmt::appender out; template ::value)> - void operator()(T value) { + auto operator()(T value) -> bool { fmt::format_to(out, "[{}]", value); + return true; } + template ::value)> - void operator()(T) {} + auto operator()(T) -> bool { + return false; + } }; - void do_put(fmt::appender out, fmt::basic_format_arg arg, - const fmt::format_specs&) const override; + auto do_put(fmt::appender out, fmt::basic_format_arg arg, + const fmt::format_specs&) const -> bool override; }; -void format_facet::do_put(fmt::appender out, +auto format_facet::do_put(fmt::appender out, fmt::basic_format_arg arg, - const fmt::format_specs&) const { - visit_format_arg(int_formatter{out}, arg); + const fmt::format_specs&) const -> bool { + return visit_format_arg(int_formatter{out}, arg); } TEST(format_test, format_facet) {