Skip to content

Commit

Permalink
Improve locale retrieval code
Browse files Browse the repository at this point in the history
  • Loading branch information
phprus committed Nov 12, 2021
1 parent 5539cbd commit 9a987ac
Showing 1 changed file with 45 additions and 42 deletions.
87 changes: 45 additions & 42 deletions include/fmt/chrono.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 <typename F>
auto with_locale(locale_ref loc_ref, F&& f) -> decltype(f(std::locale{})) {
if (loc_ref) return f(loc_ref.template get<std::locale>());
// 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 <typename F>
auto with_locale(bool localized, locale_ref loc_ref, F&& f)
-> decltype(f(std::locale{})) {
if (localized) return f(loc_ref.template get<std::locale>());
// 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
Expand Down Expand Up @@ -1474,21 +1493,15 @@ struct chrono_formatter {
void write_pinf() { std::copy_n("inf", 3, out); }
void write_ninf() { std::copy_n("-inf", 4, out); }

template <class Callback, class... Args>
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>(args)...);
out = w.out();
}
template <class Callback, class... Args>
void format_tm(const tm& time, Callback cb, Args... args) {
if (isnan(val)) return write_nan();
if (localized)
do_format_tm(context.locale().template get<std::locale>(), time, cb,
std::forward<Args>(args)...);
else
do_format_tm(get_classic_locale(), time, cb, std::forward<Args>(args)...);
with_locale(localized, context.locale(),
[this, &time, &cb, &args...](const std::locale& loc) {
auto w = tm_writer_type(loc, out, time);
(w.*cb)(std::forward<Args>(args)...);
out = w.out();
});
}

void on_text(const char_type* begin, const char_type* end) {
Expand Down Expand Up @@ -1640,14 +1653,6 @@ template <typename Char> struct formatter<weekday, Char> {
private:
bool localized = false;

template <typename It>
auto do_format(It out, const std::tm& time, const std::locale& loc) const
-> It {
auto w = detail::tm_writer<It, Char>(loc, out, time);
w.on_abbr_weekday();
return w.out();
}

public:
FMT_CONSTEXPR auto parse(basic_format_parse_context<Char>& ctx)
-> decltype(ctx.begin()) {
Expand All @@ -1661,12 +1666,15 @@ template <typename Char> struct formatter<weekday, Char> {

template <typename FormatContext>
auto format(weekday wd, FormatContext& ctx) const -> decltype(ctx.out()) {
auto time = std::tm();
time.tm_wday = static_cast<int>(wd.c_encoding());
if (localized)
return this->do_format(ctx.out(), time,
ctx.locale().template get<std::locale>());
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<int>(wd.c_encoding());
auto w = detail::tm_writer<decltype(out), Char>(loc, out, time);
w.on_abbr_weekday();
return w.out();
});
}
};

Expand Down Expand Up @@ -1843,18 +1851,6 @@ template <typename Char> struct formatter<std::tm, Char> {
return end;
}

template <typename It>
It do_format(It out, const std::tm& tm, const std::locale& loc) const {
auto w = detail::tm_writer<It, Char>(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 <typename ParseContext>
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
Expand All @@ -1864,10 +1860,17 @@ template <typename Char> struct formatter<std::tm, Char> {
template <typename FormatContext>
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<std::locale>());
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<decltype(out), Char>(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();
});
}
};

Expand Down

0 comments on commit 9a987ac

Please sign in to comment.