diff --git a/include/fmt/format-inl.h b/include/fmt/format-inl.h index 88c599cc..9ffcc836 100644 --- a/include/fmt/format-inl.h +++ b/include/fmt/format-inl.h @@ -28,7 +28,6 @@ #endif #include "format.h" -#include "locale.h" FMT_BEGIN_NAMESPACE template typename Locale::id num_format_facet::id; @@ -120,24 +119,18 @@ template FMT_FUNC Char decimal_point_impl(locale_ref) { } #endif -template -FMT_FUNC auto write_int(unsigned long long value, locale_ref loc) - -> std::basic_string { +FMT_FUNC auto write_int(unsigned long long value, const format_specs& specs, + locale_ref loc) -> std::string { #ifndef FMT_STATIC_THOUSANDS_SEPARATOR - auto&& ios = std::basic_ios(nullptr); auto locale = loc.get(); - ios.imbue(locale); - auto&& buf = std::basic_stringbuf(); - auto out = std::ostreambuf_iterator(&buf); // We cannot use the num_put facet because it may produce output in // a wrong encoding. - using facet_t = - conditional_t::value, - num_format_facet, std::num_put>; - if (std::has_facet(locale)) { - std::use_facet(locale).put(out, ios, ' ', value); - return buf.str(); - } + if (!std::has_facet>(locale)) return {}; + auto&& buf = std::basic_stringbuf(); + auto out = std::ostreambuf_iterator(&buf); + std::use_facet>(locale).put(out, value, specs, + locale); + return buf.str(); #endif return {}; } diff --git a/include/fmt/format.h b/include/fmt/format.h index f7263354..d31d1242 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -706,6 +706,7 @@ FMT_CONSTEXPR inline size_t compute_width(string_view s) { return true; } }; + // We could avoid branches by using utf8_decode directly. for_each_codepoint(s, count_code_points{&num_code_points}); return num_code_points; } @@ -2013,18 +2014,20 @@ auto write_int(OutputIt out, UInt value, unsigned prefix, }); } +FMT_API auto write_int(unsigned long long value, const format_specs& specs, + locale_ref loc) -> std::string; template -FMT_API auto write_int(unsigned long long value, locale_ref loc) - -> std::basic_string; +inline auto write_int(unsigned long long, const basic_format_specs&, + locale_ref) -> std::string { + return {}; +} template auto write_int(OutputIt& out, UInt value, unsigned prefix, const basic_format_specs& specs, locale_ref loc) -> bool { - using char_t = - conditional_t::value, wchar_t, char>; - auto str = std::basic_string(); + auto str = std::string(); if (sizeof(value) <= sizeof(unsigned long long)) - str = write_int(static_cast(value), loc); + str = write_int(static_cast(value), specs, loc); if (str.empty()) { auto grouping = digit_grouping(loc); out = write_int(out, value, prefix, specs, grouping); @@ -4171,6 +4174,25 @@ extern template FMT_API auto decimal_point_impl(locale_ref) -> wchar_t; FMT_END_DETAIL_NAMESPACE +// A locale facet that formats numeric values in UTF-8. +// It is parameterized on the locale to avoid heavy include. +template class num_format_facet : public Locale::facet { + public: + static FMT_API typename Locale::id id; + + using iter_type = std::ostreambuf_iterator; + + auto put(iter_type out, unsigned long long val, const format_specs& specs, + Locale& loc) const -> iter_type { + return do_put(out, val, specs, loc); + } + + protected: + virtual auto do_put(iter_type out, unsigned long long val, + const format_specs& specs, Locale& loc) const + -> iter_type = 0; +}; + #if FMT_USE_USER_DEFINED_LITERALS inline namespace literals { /** diff --git a/include/fmt/locale.h b/include/fmt/locale.h deleted file mode 100644 index cc252368..00000000 --- a/include/fmt/locale.h +++ /dev/null @@ -1,37 +0,0 @@ -// Formatting library for C++ - optional locale support -// -// Copyright (c) 2012 - present, Victor Zverovich -// All rights reserved. -// -// For the license information refer to format.h. - -#ifndef FMT_LOCALE_H_ -#define FMT_LOCALE_H_ - -#include // std::ios_base -#include // std::ostreambuf_iterator - -#include "core.h" - -FMT_BEGIN_NAMESPACE - -// A locale facet that formats numeric values in UTF-8. -template class num_format_facet : public Locale::facet { - public: - static FMT_API typename Locale::id id; - - using iter_type = std::ostreambuf_iterator; - - auto put(iter_type out, std::ios_base& str, char fill, - unsigned long long val) const -> iter_type { - return do_put(out, str, fill, val); - } - - protected: - virtual auto do_put(iter_type out, std::ios_base& str, char fill, - unsigned long long val) const -> iter_type = 0; -}; - -FMT_END_NAMESPACE - -#endif // FMT_LOCALE_H_ \ No newline at end of file diff --git a/src/format.cc b/src/format.cc index d0a7317f..19dff444 100644 --- a/src/format.cc +++ b/src/format.cc @@ -22,9 +22,6 @@ template FMT_API auto locale_ref::get() const -> std::locale; // Explicit instantiations for char. -template FMT_API auto write_int(unsigned long long, locale_ref) - -> std::basic_string; - template FMT_API auto thousands_sep_impl(locale_ref) -> thousands_sep_result; template FMT_API auto decimal_point_impl(locale_ref) -> char; @@ -37,9 +34,6 @@ template FMT_API void vformat_to(buffer&, string_view, // Explicit instantiations for wchar_t. -template FMT_API auto write_int(unsigned long long, locale_ref) - -> std::basic_string; - template FMT_API auto thousands_sep_impl(locale_ref) -> thousands_sep_result; template FMT_API auto decimal_point_impl(locale_ref) -> wchar_t; diff --git a/test/xchar-test.cc b/test/xchar-test.cc index 582b3495..e1958315 100644 --- a/test/xchar-test.cc +++ b/test/xchar-test.cc @@ -14,7 +14,6 @@ #include "fmt/chrono.h" #include "fmt/color.h" -#include "fmt/locale.h" #include "fmt/ostream.h" #include "fmt/ranges.h" #include "gtest-extra.h" // Contains @@ -523,13 +522,13 @@ TEST(locale_test, sign) { class num_format : public fmt::num_format_facet { protected: - using fmt::num_format_facet::do_put; - iter_type do_put(iter_type out, std::ios_base&, char, - unsigned long long) const override; + iter_type do_put(iter_type out, unsigned long long, const fmt::format_specs&, + std::locale&) const override; }; -num_format::iter_type num_format::do_put(iter_type out, std::ios_base&, char, - unsigned long long) const { +num_format::iter_type num_format::do_put(iter_type out, unsigned long long, + const fmt::format_specs&, + std::locale&) const { const char s[] = "foo"; return std::copy_n(s, sizeof(s) - 1, out); }