Refactor chrono formatting

This commit is contained in:
Victor Zverovich 2021-05-25 06:40:21 -07:00
parent b955e7a6b2
commit 35a2c2a743
2 changed files with 35 additions and 30 deletions

View File

@ -288,20 +288,18 @@ inline null<> localtime_s(...) { return null<>(); }
inline null<> gmtime_r(...) { return null<>(); } inline null<> gmtime_r(...) { return null<>(); }
inline null<> gmtime_s(...) { return null<>(); } inline null<> gmtime_s(...) { return null<>(); }
template <typename OutputIt> inline auto do_write(const std::tm& time, const std::locale& loc, char format,
OutputIt write(OutputIt out, const std::tm& time, const std::locale& loc, char modifier) -> std::string {
char format, char modifier = 0) {
auto&& os = std::ostringstream(); auto&& os = std::ostringstream();
using iterator = std::ostreambuf_iterator<char>; using iterator = std::ostreambuf_iterator<char>;
const auto& facet = std::use_facet<std::time_put<char, iterator>>(loc); const auto& facet = std::use_facet<std::time_put<char, iterator>>(loc);
auto end = facet.put(os, os, ' ', &time, format, modifier); auto end = facet.put(os, os, ' ', &time, format, modifier);
if (end.failed()) FMT_THROW(format_error("failed to format time")); if (end.failed()) FMT_THROW(format_error("failed to format time"));
auto str = os.str(); auto str = os.str();
if (detail::is_utf8() && loc != std::locale::classic()) { if (!detail::is_utf8() || loc == std::locale::classic()) return str;
// char16_t and char32_t codecvts are broken in MSVC (linkage errors). // char16_t and char32_t codecvts are broken in MSVC (linkage errors).
using code_unit = conditional_t<FMT_MSC_VER, wchar_t, char16_t>; using code_unit = conditional_t<FMT_MSC_VER, wchar_t, char16_t>;
auto& f = auto& f = std::use_facet<std::codecvt<code_unit, char, std::mbstate_t>>(loc);
std::use_facet<std::codecvt<code_unit, char, std::mbstate_t>>(loc);
auto mb = std::mbstate_t(); auto mb = std::mbstate_t();
const char* from_next = nullptr; const char* from_next = nullptr;
code_unit* to_next = nullptr; code_unit* to_next = nullptr;
@ -313,7 +311,7 @@ OutputIt write(OutputIt out, const std::tm& time, const std::locale& loc,
FMT_THROW(format_error("failed to format time")); FMT_THROW(format_error("failed to format time"));
str.clear(); str.clear();
for (code_unit* p = buf; p != to_next; ++p) { for (code_unit* p = buf; p != to_next; ++p) {
code_unit c = *p; auto c = *p;
if (c < 0x80) { if (c < 0x80) {
str.push_back(static_cast<char>(c)); str.push_back(static_cast<char>(c));
} else if (c < 0x800) { } else if (c < 0x800) {
@ -323,7 +321,13 @@ OutputIt write(OutputIt out, const std::tm& time, const std::locale& loc,
FMT_THROW(format_error("failed to format time")); FMT_THROW(format_error("failed to format time"));
} }
} }
} return str;
}
template <typename OutputIt>
auto write(OutputIt out, const std::tm& time, const std::locale& loc,
char format, char modifier = 0) -> OutputIt {
auto str = do_write(time, loc, format, modifier);
return std::copy(str.begin(), str.end(), out); return std::copy(str.begin(), str.end(), out);
} }
} // namespace detail } // namespace detail

View File

@ -376,13 +376,14 @@ TEST(chrono_test, unsigned_duration) {
EXPECT_EQ("42s", fmt::format("{}", std::chrono::duration<unsigned>(42))); EXPECT_EQ("42s", fmt::format("{}", std::chrono::duration<unsigned>(42)));
} }
TEST(chrono_test, format_weekday) { TEST(chrono_test, weekday) {
auto loc = get_locale("ru_RU.UTF-8"); auto loc = get_locale("ru_RU.UTF-8");
std::locale::global(loc); std::locale::global(loc);
EXPECT_EQ(fmt::format("{}", fmt::weekday(1)), "Mon"); auto mon = fmt::weekday(1);
EXPECT_EQ(fmt::format("{}", mon), "Mon");
if (loc != std::locale::classic()) { if (loc != std::locale::classic()) {
EXPECT_THAT((std::vector<std::string>{"пн", "Пн"}), EXPECT_THAT((std::vector<std::string>{"пн", "Пн"}),
Contains(fmt::format(loc, "{:L}", fmt::weekday(1)))); Contains(fmt::format(loc, "{:L}", mon)));
} }
} }