From 16faf54dd67fa1e08a9c05c4df675865c0d87293 Mon Sep 17 00:00:00 2001 From: Vladislav Shchapov Date: Sat, 27 Nov 2021 14:25:48 +0500 Subject: [PATCH] Use tm.tm_zone --- include/fmt/chrono.h | 148 ++++++++++++++++++++++++++++--------------- 1 file changed, 98 insertions(+), 50 deletions(-) diff --git a/include/fmt/chrono.h b/include/fmt/chrono.h index fd9410f65b42..6fcd4e4d5dde 100644 --- a/include/fmt/chrono.h +++ b/include/fmt/chrono.h @@ -291,6 +291,11 @@ inline null<> localtime_s(...) { return null<>(); } inline null<> gmtime_r(...) { return null<>(); } inline null<> gmtime_s(...) { return null<>(); } +inline const std::locale& get_classic_locale() { + static const auto& locale = std::locale::classic(); + return locale; +} + template inline void do_write(buffer& buf, const std::tm& time, const std::locale& loc, char format, char modifier) { @@ -303,26 +308,32 @@ inline void do_write(buffer& buf, const std::tm& time, if (end.failed()) FMT_THROW(format_error("failed to format time")); } -template ::value)> -auto write(OutputIt out, const std::tm& time, const std::locale& loc, - char format, char modifier = 0) -> OutputIt { - auto&& buffer = get_buffer(out); - do_write(buffer, time, loc, format, modifier); - return buffer.out(); -} - -inline const std::locale& get_classic_locale() { - static const auto& locale = std::locale::classic(); - return locale; +template +inline auto do_write_codecvt(CodeUnit* unit_buf, size_t unit_buf_size, + string_view in_buf, const std::locale& loc) + -> CodeUnit* { + using codecvt = std::codecvt; +#if FMT_CLANG_VERSION +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wdeprecated" + auto& f = std::use_facet(loc); +# pragma clang diagnostic pop +#else + auto& f = std::use_facet(loc); +#endif + auto mb = std::mbstate_t(); + const char* from_next = nullptr; + CodeUnit* to_next = nullptr; + auto result = f.in(mb, in_buf.begin(), in_buf.end(), from_next, unit_buf, + unit_buf + unit_buf_size, to_next); + if (result != std::codecvt_base::ok) + FMT_THROW(format_error("failed to format time")); + return to_next; } -template ::value)> -auto write(OutputIt out, const std::tm& time, const std::locale& loc, - char format, char modifier = 0) -> OutputIt { - auto&& buffer = basic_memory_buffer(); - do_write(buffer, time, loc, format, modifier); +template +auto do_write_char_buffer(OutputIt out, buffer& buf, + const std::locale& loc) -> OutputIt { if (detail::is_utf8() && loc != get_classic_locale()) { // char16_t and char32_t codecvts are broken in MSVC (linkage errors) and // gcc-4. @@ -335,27 +346,13 @@ auto write(OutputIt out, const std::tm& time, const std::locale& loc, using code_unit = char32_t; #endif - using codecvt = std::codecvt; -#if FMT_CLANG_VERSION -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wdeprecated" - auto& f = std::use_facet(loc); -# pragma clang diagnostic pop -#else - auto& f = std::use_facet(loc); -#endif + constexpr size_t unit_buf_size = 32; + code_unit unit_buf[unit_buf_size] = {}; + auto to_next = do_write_codecvt(unit_buf, unit_buf_size, + string_view(buf.data(), buf.size()), loc); - auto mb = std::mbstate_t(); - const char* from_next = nullptr; - code_unit* to_next = nullptr; - constexpr size_t buf_size = 32; - code_unit buf[buf_size] = {}; - auto result = f.in(mb, buffer.data(), buffer.data() + buffer.size(), - from_next, buf, buf + buf_size, to_next); - if (result != std::codecvt_base::ok) - FMT_THROW(format_error("failed to format time")); - buffer.clear(); - for (code_unit* p = buf; p != to_next; ++p) { + buf.clear(); + for (code_unit* p = unit_buf; p != to_next; ++p) { uint32_t c = static_cast(*p); if (sizeof(code_unit) == 2 && c >= 0xd800 && c <= 0xdfff) { // surrogate pair @@ -366,25 +363,62 @@ auto write(OutputIt out, const std::tm& time, const std::locale& loc, c = (c << 10) + static_cast(*p) - 0x35fdc00; } if (c < 0x80) { - buffer.push_back(static_cast(c)); + buf.push_back(static_cast(c)); } else if (c < 0x800) { - buffer.push_back(static_cast(0xc0 | (c >> 6))); - buffer.push_back(static_cast(0x80 | (c & 0x3f))); + buf.push_back(static_cast(0xc0 | (c >> 6))); + buf.push_back(static_cast(0x80 | (c & 0x3f))); } else if ((c >= 0x800 && c <= 0xd7ff) || (c >= 0xe000 && c <= 0xffff)) { - buffer.push_back(static_cast(0xe0 | (c >> 12))); - buffer.push_back(static_cast(0x80 | ((c & 0xfff) >> 6))); - buffer.push_back(static_cast(0x80 | (c & 0x3f))); + buf.push_back(static_cast(0xe0 | (c >> 12))); + buf.push_back(static_cast(0x80 | ((c & 0xfff) >> 6))); + buf.push_back(static_cast(0x80 | (c & 0x3f))); } else if (c >= 0x10000 && c <= 0x10ffff) { - buffer.push_back(static_cast(0xf0 | (c >> 18))); - buffer.push_back(static_cast(0x80 | ((c & 0x3ffff) >> 12))); - buffer.push_back(static_cast(0x80 | ((c & 0xfff) >> 6))); - buffer.push_back(static_cast(0x80 | (c & 0x3f))); + buf.push_back(static_cast(0xf0 | (c >> 18))); + buf.push_back(static_cast(0x80 | ((c & 0x3ffff) >> 12))); + buf.push_back(static_cast(0x80 | ((c & 0xfff) >> 6))); + buf.push_back(static_cast(0x80 | (c & 0x3f))); } else { FMT_THROW(format_error("failed to format time")); } } } - return copy_str(buffer.data(), buffer.data() + buffer.size(), out); + return copy_str(buf.data(), buf.data() + buf.size(), out); +} + +template ::value)> +auto write_tm_str(OutputIt out, string_view sv, const std::locale& loc) + -> OutputIt { + constexpr size_t unit_buf_size = 32; + Char unit_buf[unit_buf_size] = {}; + auto to_next = do_write_codecvt(unit_buf, unit_buf_size, sv, loc); + return copy_str(unit_buf, to_next, out); +} + +template ::value)> +auto write_tm_str(OutputIt out, string_view sv, const std::locale& loc) + -> OutputIt { + auto&& buf = basic_memory_buffer(); + buf.append(sv.begin(), sv.end()); + return do_write_char_buffer(out, buf, loc); +} + +template ::value)> +auto write(OutputIt out, const std::tm& time, const std::locale& loc, + char format, char modifier = 0) -> OutputIt { + auto&& buffer = get_buffer(out); + do_write(buffer, time, loc, format, modifier); + return buffer.out(); +} + +template ::value)> +auto write(OutputIt out, const std::tm& time, const std::locale& loc, + char format, char modifier = 0) -> OutputIt { + auto&& buffer = basic_memory_buffer(); + do_write(buffer, time, loc, format, modifier); + return do_write_char_buffer(out, buffer, loc); } } // namespace detail @@ -881,6 +915,12 @@ template struct has_member_data_tm_gmtoff> : std::true_type {}; +template +struct has_member_data_tm_zone : std::false_type {}; +template +struct has_member_data_tm_zone> + : std::true_type {}; + #if defined(_WIN32) inline void tzset_once() { static bool init = []() -> bool { @@ -1038,6 +1078,14 @@ template class tm_writer { #endif } + void format_tz_name_impl(std::true_type) { + if (is_classic_) + out_ = write_tm_str(out_, tm_.tm_zone, loc_); + else + format_localized('Z'); + } + void format_tz_name_impl(std::false_type) { format_localized('Z'); } + void format_localized(char format, char modifier = 0) { out_ = write(out_, tm_, loc_, format, modifier); } @@ -1147,7 +1195,7 @@ template class tm_writer { void on_utc_offset() { format_utc_offset_impl(has_member_data_tm_gmtoff{}); } - void on_tz_name() { format_localized('Z'); } + void on_tz_name() { format_tz_name_impl(has_member_data_tm_zone{}); } void on_year(numeric_system ns) { if (is_classic_ || ns == numeric_system::standard)