From c7abf2c448d867ffca8d9c0b3d3a19988be27c5b Mon Sep 17 00:00:00 2001 From: Vladislav Shchapov Date: Fri, 12 Nov 2021 22:33:29 +0500 Subject: [PATCH] Improve locale retrieval code --- include/fmt/chrono.h | 101 ++++++++++++++++++++++++------------------- 1 file changed, 57 insertions(+), 44 deletions(-) diff --git a/include/fmt/chrono.h b/include/fmt/chrono.h index 7bfbb79ab2e40..996700aa3a609 100644 --- a/include/fmt/chrono.h +++ b/include/fmt/chrono.h @@ -383,6 +383,25 @@ auto write(OutputIt out, const std::tm& time, const std::locale& loc, return std::copy(str.begin(), str.end(), out); } +template +auto with_locale(locale_ref loc_ref, F&& f) -> decltype(f(std::locale{})) { + if (loc_ref) return f(loc_ref.template get()); + // in contrast to the case above, classic locale is returned by reference + // without introducing a temporary object + // (locale copy ctor & dtor are relatively expensive) + return f(get_classic_locale()); +} + +template +auto with_locale(bool localized, locale_ref loc_ref, F&& f) + -> decltype(f(std::locale{})) { + if (localized) return f(loc_ref.template get()); + // in contrast to the case above, classic locale is returned by reference + // without introducing a temporary object + // (locale copy ctor & dtor are relatively expensive) + return f(get_classic_locale()); +} + } // namespace detail FMT_MODULE_EXPORT_BEGIN @@ -1474,21 +1493,25 @@ struct chrono_formatter { void write_pinf() { std::copy_n("inf", 3, out); } void write_ninf() { std::copy_n("-inf", 4, out); } - template - void do_format_tm(const std::locale& loc, const tm& time, Callback cb, - Args... args) { - auto w = tm_writer_type(loc, out, time); - (w.*cb)(std::forward(args)...); - out = w.out(); - } - template - void format_tm(const tm& time, Callback cb, Args... args) { + // Splitted because gcc 4.8 doesn't support pack expansion in lambda capture. + void format_tm(const tm& time, void (tm_writer_type::*cb)()) { if (isnan(val)) return write_nan(); - if (localized) - do_format_tm(context.locale().template get(), time, cb, - std::forward(args)...); - else - do_format_tm(get_classic_locale(), time, cb, std::forward(args)...); + with_locale(localized, context.locale(), + [this, &time, &cb](const std::locale& loc) { + auto w = tm_writer_type(loc, out, time); + (w.*cb)(); + out = w.out(); + }); + } + void format_tm(const tm& time, void (tm_writer_type::*cb)(numeric_system), + numeric_system ns) { + if (isnan(val)) return write_nan(); + with_locale(localized, context.locale(), + [this, &time, &cb, &ns](const std::locale& loc) { + auto w = tm_writer_type(loc, out, time); + (w.*cb)(ns); + out = w.out(); + }); } void on_text(const char_type* begin, const char_type* end) { @@ -1640,14 +1663,6 @@ template struct formatter { private: bool localized = false; - template - auto do_format(It out, const std::tm& time, const std::locale& loc) const - -> It { - auto w = detail::tm_writer(loc, out, time); - w.on_abbr_weekday(); - return w.out(); - } - public: FMT_CONSTEXPR auto parse(basic_format_parse_context& ctx) -> decltype(ctx.begin()) { @@ -1661,12 +1676,15 @@ template struct formatter { template auto format(weekday wd, FormatContext& ctx) const -> decltype(ctx.out()) { - auto time = std::tm(); - time.tm_wday = static_cast(wd.c_encoding()); - if (localized) - return this->do_format(ctx.out(), time, - ctx.locale().template get()); - return this->do_format(ctx.out(), time, detail::get_classic_locale()); + auto out = ctx.out(); + return with_locale( + localized, ctx.locale(), [&out, &wd](const std::locale& loc) { + auto time = std::tm(); + time.tm_wday = static_cast(wd.c_encoding()); + auto w = detail::tm_writer(loc, out, time); + w.on_abbr_weekday(); + return w.out(); + }); } }; @@ -1843,18 +1861,6 @@ template struct formatter { return end; } - template - It do_format(It out, const std::tm& tm, const std::locale& loc) const { - auto w = detail::tm_writer(loc, out, tm); - if (spec_ == spec::year_month_day) - w.on_iso_date(); - else if (spec_ == spec::hh_mm_ss) - w.on_iso_time(); - else - detail::parse_chrono_format(specs.begin(), specs.end(), w); - return w.out(); - } - public: template FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { @@ -1864,10 +1870,17 @@ template struct formatter { template auto format(const std::tm& tm, FormatContext& ctx) const -> decltype(ctx.out()) { - if (const auto& loc_ref = ctx.locale()) - return this->do_format(ctx.out(), tm, - loc_ref.template get()); - return this->do_format(ctx.out(), tm, detail::get_classic_locale()); + auto out = ctx.out(); + return with_locale(ctx.locale(), [this, &tm, &out](const std::locale& loc) { + auto w = detail::tm_writer(loc, out, tm); + if (spec_ == spec::year_month_day) + w.on_iso_date(); + else if (spec_ == spec::hh_mm_ss) + w.on_iso_time(); + else + detail::parse_chrono_format(specs.begin(), specs.end(), w); + return w.out(); + }); } };