From e582d377c25bfb391e5a1f27795e39389f1a9a05 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Thu, 29 Aug 2024 13:04:56 -0700 Subject: [PATCH] Simplify locale handling --- include/fmt/format-inl.h | 75 +++++++++++++++++++++++----------------- include/fmt/format.h | 35 +++---------------- 2 files changed, 49 insertions(+), 61 deletions(-) diff --git a/include/fmt/format-inl.h b/include/fmt/format-inl.h index ab06f1a0..4f0c9bd9 100644 --- a/include/fmt/format-inl.h +++ b/include/fmt/format-inl.h @@ -14,10 +14,6 @@ # include # include # include - -# if !defined(FMT_STATIC_THOUSANDS_SEPARATOR) -# include -# endif #endif #if defined(_WIN32) && !defined(FMT_USE_WRITE_CONSOLE) @@ -26,6 +22,19 @@ #include "format.h" +#ifdef FMT_USE_LOCALE +// Use the provided definition. +#elif defined(FMT_STATIC_THOUSANDS_SEPARATOR) +# define FMT_USE_LOCALE 0 +#else +# define FMT_USE_LOCALE 1 +#endif +#if FMT_USE_LOCALE +# include +#elif !defined(FMT_STATIC_THOUSANDS_SEPARATOR) +# define FMT_STATIC_THOUSANDS_SEPARATOR ',' +#endif + FMT_BEGIN_NAMESPACE namespace detail { @@ -77,53 +86,56 @@ inline void fwrite_fully(const void* ptr, size_t count, FILE* stream) { FMT_THROW(system_error(errno, FMT_STRING("cannot write to file"))); } -#ifndef FMT_STATIC_THOUSANDS_SEPARATOR +#if FMT_USE_LOCALE +using std::locale; +using std::numpunct; +using std::use_facet; +#else +struct locale {}; +template struct numpunct { + auto grouping() const -> std::string { return "\03"; } + auto thousands_sep() const -> Char { return FMT_STATIC_THOUSANDS_SEPARATOR; } + auto decimal_point() const -> Char { return '.'; } +}; +template Facet use_facet(locale) { return {}; } +#endif // FMT_USE_LOCALE + template locale_ref::locale_ref(const Locale& loc) : locale_(&loc) { - static_assert(std::is_same::value, ""); + static_assert(std::is_same::value, ""); } template auto locale_ref::get() const -> Locale { - static_assert(std::is_same::value, ""); - return locale_ ? *static_cast(locale_) : std::locale(); + static_assert(std::is_same::value, ""); + return locale_ ? *static_cast(locale_) : locale(); } template FMT_FUNC auto thousands_sep_impl(locale_ref loc) -> thousands_sep_result { - auto& facet = std::use_facet>(loc.get()); + auto&& facet = use_facet>(loc.get()); auto grouping = facet.grouping(); auto thousands_sep = grouping.empty() ? Char() : facet.thousands_sep(); return {std::move(grouping), thousands_sep}; } template FMT_FUNC auto decimal_point_impl(locale_ref loc) -> Char { - return std::use_facet>(loc.get()) - .decimal_point(); + return use_facet>(loc.get()).decimal_point(); } -#else -template -FMT_FUNC auto thousands_sep_impl(locale_ref) -> thousands_sep_result { - return {"\03", FMT_STATIC_THOUSANDS_SEPARATOR}; -} -template FMT_FUNC Char decimal_point_impl(locale_ref) { - return '.'; -} -#endif FMT_FUNC auto write_loc(appender out, loc_value value, const format_specs& specs, locale_ref loc) -> bool { -#ifdef FMT_STATIC_THOUSANDS_SEPARATOR - value.visit(loc_writer<>{ - out, specs, std::string(1, FMT_STATIC_THOUSANDS_SEPARATOR), "\3", "."}); - return true; -#else +#if FMT_USE_LOCALE auto locale = loc.get(); // We cannot use the num_put facet because it may produce output in // a wrong encoding. using facet = format_facet; if (std::has_facet(locale)) - return std::use_facet(locale).put(out, value, specs); + return use_facet(locale).put(out, value, specs); return facet(locale).put(out, value, specs); +#else + value.visit(loc_writer<>{ + out, specs, std::string(1, FMT_STATIC_THOUSANDS_SEPARATOR), "\3", "."}); + return true; #endif } } // namespace detail @@ -134,13 +146,13 @@ FMT_FUNC void report_error(const char* message) { 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()); + auto& np = detail::use_facet>(loc); + grouping_ = np.grouping(); + if (!grouping_.empty()) separator_ = std::string(1, np.thousands_sep()); } +#if FMT_USE_LOCALE template <> FMT_API FMT_FUNC auto format_facet::do_put( appender out, loc_value val, const format_specs& specs) const -> bool { @@ -1019,7 +1031,8 @@ template <> struct cache_accessor { {0xe4d5e82392a40515, 0x0fabaf3feaa5334b}, {0xb8da1662e7b00a17, 0x3d6a751f3b936244}, {0x95527a5202df0ccb, 0x0f37801e0c43ebc9}, - {0xf13e34aabb430a15, 0x647726b9e7c68ff0} + { 0xf13e34aabb430a15, + 0x647726b9e7c68ff0 } #endif }; diff --git a/include/fmt/format.h b/include/fmt/format.h index 022fc501..f70a33dc 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -765,16 +765,6 @@ using is_integer = !std::is_same::value && !std::is_same::value>; -#ifndef FMT_USE_FLOAT -# define FMT_USE_FLOAT 1 -#endif -#ifndef FMT_USE_DOUBLE -# define FMT_USE_DOUBLE 1 -#endif -#ifndef FMT_USE_LONG_DOUBLE -# define FMT_USE_LONG_DOUBLE 1 -#endif - #if defined(FMT_USE_FLOAT128) // Use the provided definition. #elif FMT_CLANG_VERSION && FMT_HAS_INCLUDE() @@ -1132,14 +1122,6 @@ constexpr auto is_negative(T) -> bool { return false; } -template -FMT_CONSTEXPR auto is_supported_floating_point(T) -> bool { - if (std::is_same()) return FMT_USE_FLOAT; - if (std::is_same()) return FMT_USE_DOUBLE; - if (std::is_same()) return FMT_USE_LONG_DOUBLE; - return true; -} - // Smallest of uint32_t, uint64_t, uint128_t that is large enough to // represent all values of an integral type T. template @@ -3556,7 +3538,6 @@ template ::value)> FMT_CONSTEXPR20 auto write(OutputIt out, T value, format_specs specs, locale_ref loc = {}) -> OutputIt { - if (const_check(!is_supported_floating_point(value))) return out; return specs.localized() && write_loc(out, value, specs, loc) ? out : write_float(out, value, specs, loc); @@ -3566,7 +3547,6 @@ template ::value)> FMT_CONSTEXPR20 auto write(OutputIt out, T value) -> OutputIt { if (is_constant_evaluated()) return write(out, value, format_specs()); - if (const_check(!is_supported_floating_point(value))) return out; auto s = detail::signbit(value) ? sign::minus : sign::none; @@ -3708,28 +3688,23 @@ template struct default_arg_formatter { }; template struct arg_formatter { - using iterator = basic_appender; - using context = buffered_context; - - iterator out; + basic_appender out; const format_specs& specs; locale_ref locale; template ::value)> - FMT_CONSTEXPR FMT_INLINE auto operator()(T value) -> iterator { - return detail::write(out, value, specs, locale); + FMT_CONSTEXPR FMT_INLINE void operator()(T value) { + detail::write(out, value, specs, locale); } template ::value)> - auto operator()(T) -> iterator { + void operator()(T) { FMT_ASSERT(false, ""); - return out; } - auto operator()(typename basic_format_arg::handle) -> iterator { + void operator()(typename basic_format_arg>::handle) { // User-defined types are handled separately because they require access // to the parse context. - return out; } };