From 3b9c44268961db3605901ab018430e0c4c6fbf61 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Fri, 3 Sep 2021 22:04:58 -0700 Subject: [PATCH] Implement thousands separators without locales --- include/fmt/format.h | 35 +++++++++++++++++++++++++++++------ test/format-test.cc | 4 ++++ 2 files changed, 33 insertions(+), 6 deletions(-) diff --git a/include/fmt/format.h b/include/fmt/format.h index 3e9af1c6..cc68c116 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -1467,6 +1467,7 @@ template class digit_grouping { else sep_.thousands_sep = Char(); } + explicit digit_grouping(thousands_sep_result sep) : sep_(sep) {} Char separator() const { return sep_.thousands_sep; } @@ -1501,22 +1502,28 @@ template class digit_grouping { }; template -auto write_int_localized(OutputIt& out, UInt value, unsigned prefix, - const basic_format_specs& specs, locale_ref loc) - -> bool { +auto write_int_localized(OutputIt out, UInt value, unsigned prefix, + const basic_format_specs& specs, + const digit_grouping& grouping) -> OutputIt { static_assert(std::is_same, UInt>::value, ""); int num_digits = count_digits(value); char digits[40]; format_decimal(digits, value, num_digits); - - auto grouping = digit_grouping(loc); unsigned size = to_unsigned((prefix != 0 ? 1 : 0) + num_digits + grouping.count_separators(num_digits)); - out = write_padded( + return write_padded( out, specs, size, size, [&](reserve_iterator it) { if (prefix != 0) *it++ = static_cast(prefix); return grouping.apply(it, string_view(digits, to_unsigned(num_digits))); }); +} + +template +auto write_int_localized(OutputIt& out, UInt value, unsigned prefix, + const basic_format_specs& specs, locale_ref loc) + -> bool { + auto grouping = digit_grouping(loc); + out = write_int_localized(out, value, prefix, specs, grouping); return true; } @@ -2604,6 +2611,22 @@ template <> struct formatter { } }; +// thousands_view is not derived from view because it copies the argument. +template struct thousands_view { T value; }; + +template auto thousands(T value) -> thousands_view { + return {value}; +} + +template struct formatter> : formatter { + template + auto format(thousands_view t, FormatContext& ctx) -> decltype(ctx.out()) { + return detail::write_int_localized( + ctx.out(), static_cast>(t.value), 0, + format_specs(), detail::digit_grouping({"\3", ','})); + } +}; + template struct join_view : detail::view { It begin; diff --git a/test/format-test.cc b/test/format-test.cc index ec59a5fc..ae129a82 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -1595,6 +1595,10 @@ TEST(format_test, bytes) { EXPECT_EQ(10, s.size()); } +TEST(format_test, thousands) { + EXPECT_EQ(fmt::format("{}", fmt::thousands(1000)), "1,000"); +} + enum test_enum { foo, bar }; TEST(format_test, join) {