From 1b94271ff69f1159abb0907dd5a18700531b2922 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sat, 3 Sep 2022 10:35:57 -0700 Subject: [PATCH] Add support for UTF-8 digit separators --- include/fmt/format-inl.h | 12 +++++------- include/fmt/format.h | 13 ++++++------- test/format-test.cc | 14 ++++++++++++-- 3 files changed, 23 insertions(+), 16 deletions(-) diff --git a/include/fmt/format-inl.h b/include/fmt/format-inl.h index 9ce96b1d..d77e5c82 100644 --- a/include/fmt/format-inl.h +++ b/include/fmt/format-inl.h @@ -123,8 +123,7 @@ FMT_FUNC auto write_int(appender out, basic_format_arg value, // 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, - locale); + std::use_facet>(locale).put(out, value, specs); return true; #endif return false; @@ -133,13 +132,13 @@ FMT_FUNC auto write_int(appender out, basic_format_arg value, struct localize_int { appender out; const format_specs& specs; - locale_ref loc; + std::string sep; template ::value)> void operator()(T value) { auto arg = make_write_int_arg(value, specs.sign); write_int(out, static_cast>(arg.abs_value), arg.prefix, - specs, digit_grouping(loc)); + specs, digit_grouping("\3", sep)); } template ::value)> void operator()(T) {} @@ -152,9 +151,8 @@ template typename Locale::id format_facet::id; template <> FMT_API FMT_FUNC void format_facet::do_put( appender out, basic_format_arg val, - const format_specs& specs, std::locale& loc) const { - visit_format_arg(detail::localize_int{out, specs, detail::locale_ref(loc)}, - val); + const format_specs& specs) const { + visit_format_arg(detail::localize_int{out, specs, separator_}, val); } #endif diff --git a/include/fmt/format.h b/include/fmt/format.h index f03a59f9..ab98dbd5 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -993,7 +993,7 @@ template class format_facet : public Locale::facet { protected: virtual void do_put(appender out, basic_format_arg val, - const format_specs& specs, Locale& loc) const; + const format_specs& specs) const; public: static FMT_API typename Locale::id id; @@ -1002,8 +1002,8 @@ template class format_facet : public Locale::facet { : separator_(sep.data(), sep.size()) {} void put(appender out, basic_format_arg val, - const format_specs& specs, Locale& loc) const { - do_put(out, val, specs, loc); + const format_specs& specs) const { + do_put(out, val, specs); } }; @@ -1981,9 +1981,8 @@ template class digit_grouping { grouping_ = sep.grouping; if (sep.thousands_sep) thousands_sep_.assign(1, sep.thousands_sep); } - explicit digit_grouping(thousands_sep_result sep) - : grouping_(sep.grouping), - thousands_sep_(sep.thousands_sep ? 1 : 0, sep.thousands_sep) {} + digit_grouping(std::string grouping, std::string sep) + : grouping_(std::move(grouping)), thousands_sep_(std::move(sep)) {} bool has_separator() const { return !thousands_sep_.empty(); } @@ -3950,7 +3949,7 @@ template struct formatter> : formatter { specs_.precision, specs_.precision_ref, ctx); return detail::write_int( ctx.out(), static_cast>(t.value), 0, specs_, - detail::digit_grouping({"\3", ','})); + detail::digit_grouping("\3", ",")); } }; diff --git a/test/format-test.cc b/test/format-test.cc index ee82bd9e..6fb38cb9 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -2330,12 +2330,12 @@ class format_facet : public fmt::format_facet { }; void do_put(fmt::appender out, fmt::basic_format_arg arg, - const fmt::format_specs&, std::locale&) const override; + const fmt::format_specs&) const override; }; void format_facet::do_put(fmt::appender out, fmt::basic_format_arg arg, - const fmt::format_specs&, std::locale&) const { + const fmt::format_specs&) const { visit_format_arg(int_formatter{out}, arg); } @@ -2345,4 +2345,14 @@ TEST(format_test, format_facet) { EXPECT_EQ(fmt::format(loc, "{:L}", -42), "[-42]"); } +TEST(format_test, format_facet_separator) { + // U+2019 RIGHT SINGLE QUOTATION MARK is a digit separator in the de_CH + // locale. + auto loc = std::locale(std::locale(), + new fmt::format_facet("\xe2\x80\x99")); + EXPECT_EQ(fmt::format(loc, "{:L}", 1000), + "1\xe2\x80\x99" + "000"); +} + #endif // FMT_STATIC_THOUSANDS_SEPARATOR