From 22948841d6d88153e4bb50ce07b59264f6829364 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 459e7239..f937e463 100644 --- a/include/fmt/chrono.h +++ b/include/fmt/chrono.h @@ -475,25 +475,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/. @@ -1416,6 +1397,7 @@ template class tm_writer { private: static constexpr int days_per_week = 7; + const std::locale& loc_; OutputIt out_; const std::tm& tm_; @@ -1527,34 +1509,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(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_; } @@ -1784,7 +1744,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 84431f69..82d96c04 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 7a1a452b..4620ee25 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) {