From 8ba27a347da2eda79d5ca8278a1ff2749009db62 Mon Sep 17 00:00:00 2001 From: Vladislav Shchapov Date: Sun, 17 Oct 2021 18:22:42 +0500 Subject: [PATCH] Replace strftime to std::time_put --- include/fmt/chrono.h | 51 ++++++-------------------------------------- test/chrono-test.cc | 13 ++++++----- test/xchar-test.cc | 13 ++++++----- 3 files changed, 22 insertions(+), 55 deletions(-) diff --git a/include/fmt/chrono.h b/include/fmt/chrono.h index a6587600af014..e0f5792a2c000 100644 --- a/include/fmt/chrono.h +++ b/include/fmt/chrono.h @@ -474,25 +474,6 @@ inline std::tm gmtime( FMT_BEGIN_DETAIL_NAMESPACE -inline size_t strftime(char* str, size_t count, const char* format, - const std::tm* time) { - // Assign to a pointer to suppress GCCs -Wformat-nonliteral - // First assign the nullptr to suppress -Wsuggest-attribute=format - std::size_t (*strftime)(char*, std::size_t, const char*, const std::tm*) = - nullptr; - strftime = std::strftime; - return strftime(str, count, format, time); -} - -inline size_t strftime(wchar_t* str, size_t count, const wchar_t* format, - const std::tm* time) { - // See above - std::size_t (*wcsftime)(wchar_t*, std::size_t, const wchar_t*, - const std::tm*) = nullptr; - wcsftime = std::wcsftime; - return wcsftime(str, count, format, time); -} - // Writes two-digit numbers a, b and c separated by sep to buf. // The method by Pavel Novikov based on // https://johnnylee-sde.github.io/Fast-unsigned-integer-to-time-string/. @@ -1415,6 +1396,7 @@ template class tm_writer { private: static constexpr int days_per_week = 7; + const std::locale& loc_; OutputIt out_; const std::tm& tm_; @@ -1494,34 +1476,12 @@ template class tm_writer { } void format_localized(char format, char modifier = 0) { - // By prepending an extra space we can distinguish an empty result that - // indicates insufficient buffer size from a guaranteed non-empty result - // https://github.com/fmtlib/fmt/issues/2238 - Char tm_format[5] = {' ', '%', 'x', '\0', '\0'}; - if (modifier) { - tm_format[2] = modifier; - tm_format[3] = format; - } else { - tm_format[2] = format; - } - - basic_memory_buffer buf; - for (;;) { - size_t size = buf.capacity(); - size_t count = detail::strftime(buf.data(), size, tm_format, &tm_); - if (count != 0) { - buf.resize(count); - break; - } - const size_t min_growth = 10; - buf.reserve(buf.capacity() + (size > min_growth ? size : min_growth)); - } - // Remove the extra space. - out_ = copy_str(buf.begin() + 1, buf.end(), out_); + out_ = write(Char(), out_, tm_, loc_, format, modifier); } public: - explicit tm_writer(OutputIt out, const std::tm& tm) : out_(out), tm_(tm) {} + explicit tm_writer(const std::locale& loc, OutputIt out, const std::tm& tm) + : loc_(loc), out_(out), tm_(tm) {} OutputIt out() const { return out_; } @@ -1748,7 +1708,8 @@ template struct formatter { template auto format(const std::tm& tm, FormatContext& ctx) const -> decltype(ctx.out()) { - auto w = detail::tm_writer(ctx.out(), tm); + const auto& loc = std::locale::classic(); + auto w = detail::tm_writer(loc, ctx.out(), tm); if (spec_ == spec::year_month_day) w.on_iso_date(); else if (spec_ == spec::hh_mm_ss) diff --git a/test/chrono-test.cc b/test/chrono-test.cc index 648ba6003b71b..a8e40cc7cc08e 100644 --- a/test/chrono-test.cc +++ b/test/chrono-test.cc @@ -42,11 +42,14 @@ auto make_second(int s) -> std::tm { } std::string system_strftime(const std::string& format, const std::tm* timeptr, - size_t maxsize = 1024) { - std::vector output(maxsize); - auto size = - std::strftime(output.data(), output.size(), format.c_str(), timeptr); - return std::string(output.data(), size); + std::locale* locptr = nullptr) { + auto loc = locptr ? *locptr : std::locale::classic(); + auto& facet = std::use_facet>(loc); + std::ostringstream os; + os.imbue(loc); + facet.put(os, os, ' ', timeptr, format.c_str(), + format.c_str() + format.size()); + return os.str(); } FMT_CONSTEXPR std::tm make_tm(int year, int mon, int mday, int hour, int min, diff --git a/test/xchar-test.cc b/test/xchar-test.cc index d5e8ce7ba302e..39ebc5c33b561 100644 --- a/test/xchar-test.cc +++ b/test/xchar-test.cc @@ -270,11 +270,14 @@ TEST(xchar_test, chrono) { } std::wstring system_wcsftime(const std::wstring& format, const std::tm* timeptr, - size_t maxsize = 1024) { - std::vector output(maxsize); - auto size = - std::wcsftime(output.data(), output.size(), format.c_str(), timeptr); - return std::wstring(output.data(), size); + std::locale* locptr = nullptr) { + auto loc = locptr ? *locptr : std::locale::classic(); + auto& facet = std::use_facet>(loc); + std::wostringstream os; + os.imbue(loc); + facet.put(os, os, L' ', timeptr, format.c_str(), + format.c_str() + format.size()); + return os.str(); } TEST(chrono_test, time_point) {