diff --git a/include/fmt/format-inl.h b/include/fmt/format-inl.h index 0591e5af..9ce96b1d 100644 --- a/include/fmt/format-inl.h +++ b/include/fmt/format-inl.h @@ -29,8 +29,6 @@ #include "format.h" FMT_BEGIN_NAMESPACE -template typename Locale::id format_facet::id; - namespace detail { FMT_FUNC void assert_fail(const char* file, int line, const char* message) { @@ -132,8 +130,34 @@ FMT_FUNC auto write_int(appender out, basic_format_arg value, return false; } +struct localize_int { + appender out; + const format_specs& specs; + locale_ref loc; + + 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)); + } + template ::value)> + void operator()(T) {} +}; } // namespace detail +template typename Locale::id format_facet::id; + +#ifndef FMT_STATIC_THOUSANDS_SEPARATOR +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); +} +#endif + #if !FMT_MSC_VERSION FMT_API FMT_FUNC format_error::~format_error() noexcept = default; #endif diff --git a/include/fmt/format.h b/include/fmt/format.h index 32ae14dc..f03a59f9 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -988,17 +988,23 @@ constexpr auto compile_string_to_view(detail::std_string_view s) // A locale facet that formats values in UTF-8. // It is parameterized on the locale to avoid the heavy include. template class format_facet : public Locale::facet { + private: + std::string separator_; + + protected: + virtual void do_put(appender out, basic_format_arg val, + const format_specs& specs, Locale& loc) const; + public: static FMT_API typename Locale::id id; + explicit format_facet(string_view sep = ",") + : 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); } - - protected: - virtual void do_put(appender out, basic_format_arg val, - const format_specs& specs, Locale& loc) const = 0; }; FMT_BEGIN_DETAIL_NAMESPACE @@ -1949,19 +1955,19 @@ FMT_CONSTEXPR FMT_INLINE auto write_int(OutputIt out, int num_digits, template class digit_grouping { private: - thousands_sep_result sep_; + std::string grouping_; + std::basic_string thousands_sep_; struct next_state { std::string::const_iterator group; int pos; }; - next_state initial_state() const { return {sep_.grouping.begin(), 0}; } + next_state initial_state() const { return {grouping_.begin(), 0}; } // Returns the next digit group separator position. int next(next_state& state) const { - if (!sep_.thousands_sep) return max_value(); - if (state.group == sep_.grouping.end()) - return state.pos += sep_.grouping.back(); + if (thousands_sep_.empty()) return max_value(); + if (state.group == grouping_.end()) return state.pos += grouping_.back(); if (*state.group <= 0 || *state.group == max_value()) return max_value(); state.pos += *state.group++; @@ -1970,14 +1976,16 @@ template class digit_grouping { public: explicit digit_grouping(locale_ref loc, bool localized = true) { - if (localized) - sep_ = thousands_sep(loc); - else - sep_.thousands_sep = Char(); + if (!localized) return; + auto sep = thousands_sep(loc); + grouping_ = sep.grouping; + if (sep.thousands_sep) thousands_sep_.assign(1, sep.thousands_sep); } - explicit digit_grouping(thousands_sep_result sep) : sep_(sep) {} + explicit digit_grouping(thousands_sep_result sep) + : grouping_(sep.grouping), + thousands_sep_(sep.thousands_sep ? 1 : 0, sep.thousands_sep) {} - Char separator() const { return sep_.thousands_sep; } + bool has_separator() const { return !thousands_sep_.empty(); } int count_separators(int num_digits) const { int count = 0; @@ -2000,7 +2008,9 @@ template class digit_grouping { for (int i = 0, sep_index = static_cast(separators.size() - 1); i < num_digits; ++i) { if (num_digits - i == separators[sep_index]) { - *out++ = separator(); + out = + copy_str(thousands_sep_.data(), + thousands_sep_.data() + thousands_sep_.size(), out); --sep_index; } *out++ = static_cast(digits[to_unsigned(i)]); @@ -2307,7 +2317,7 @@ template FMT_CONSTEXPR20 auto write_significand(OutputIt out, T significand, int significand_size, int exponent, const Grouping& grouping) -> OutputIt { - if (!grouping.separator()) { + if (!grouping.has_separator()) { out = write_significand(out, significand, significand_size); return detail::fill_n(out, exponent, static_cast('0')); } @@ -2369,7 +2379,7 @@ FMT_CONSTEXPR20 auto write_significand(OutputIt out, T significand, int significand_size, int integral_size, Char decimal_point, const Grouping& grouping) -> OutputIt { - if (!grouping.separator()) { + if (!grouping.has_separator()) { return write_significand(out, significand, significand_size, integral_size, decimal_point); } @@ -2492,7 +2502,7 @@ template class fallback_digit_grouping { public: constexpr fallback_digit_grouping(locale_ref, bool) {} - constexpr Char separator() const { return Char(); } + constexpr bool has_separator() const { return false; } constexpr int count_separators(int) const { return 0; }