[libcxx-commits] [libcxx] 0ee73de - [libc++][format] Fixes year formatter on Windows.
Mark de Wever via libcxx-commits
libcxx-commits at lists.llvm.org
Tue May 30 09:58:05 PDT 2023
Author: Mark de Wever
Date: 2023-05-30T18:57:55+02:00
New Revision: 0ee73debf7445a9a34dcdf0215a99a2919d00112
URL: https://github.com/llvm/llvm-project/commit/0ee73debf7445a9a34dcdf0215a99a2919d00112
DIFF: https://github.com/llvm/llvm-project/commit/0ee73debf7445a9a34dcdf0215a99a2919d00112.diff
LOG: [libc++][format] Fixes year formatter on Windows.
Windows' libc, like some other libc implementations do not work as
specified for %Y and %y. This uses the fixes used for other libc
implementations.
The work was part of D150593.
Reviewed By: #libc, ldionne
Differential Revision: https://reviews.llvm.org/D151612
Added:
Modified:
libcxx/include/__chrono/formatter.h
libcxx/test/std/time/time.cal/time.cal.year/time.cal.year.nonmembers/ostream.pass.cpp
libcxx/test/std/time/time.syn/formatter.year.pass.cpp
Removed:
################################################################################
diff --git a/libcxx/include/__chrono/formatter.h b/libcxx/include/__chrono/formatter.h
index c8d5993be1961..679edf39cbb39 100644
--- a/libcxx/include/__chrono/formatter.h
+++ b/libcxx/include/__chrono/formatter.h
@@ -270,20 +270,19 @@ _LIBCPP_HIDE_FROM_ABI void __format_chrono_using_chrono_specs(
//
// TODO FMT evaluate the comment above.
-# if defined(__GLIBC__) || defined(_AIX)
+# if defined(__GLIBC__) || defined(_AIX) || defined(_WIN32)
case _CharT('y'):
// Glibc fails for negative values, AIX for positive values too.
__sstr << std::format(_LIBCPP_STATICALLY_WIDEN(_CharT, "{:02}"), (std::abs(__t.tm_year + 1900)) % 100);
break;
-# endif // defined(__GLIBC__) || defined(_AIX)
+# endif // defined(__GLIBC__) || defined(_AIX) || defined(_WIN32)
- case _CharT('Y'): {
- int __year = __t.tm_year + 1900;
- if (__year < 1000)
- __formatter::__format_year(__year, __sstr);
- else
- __facet.put({__sstr}, __sstr, _CharT(' '), std::addressof(__t), std::to_address(__s), std::to_address(__it + 1));
- } break;
+ case _CharT('Y'):
+ // Depending on the platform's libc the range of supported years is
+ // limited. Intead of of testing all conditions use the internal
+ // implementation unconditionally.
+ __formatter::__format_year(__t.tm_year + 1900, __sstr);
+ break;
case _CharT('F'): {
int __year = __t.tm_year + 1900;
diff --git a/libcxx/test/std/time/time.cal/time.cal.year/time.cal.year.nonmembers/ostream.pass.cpp b/libcxx/test/std/time/time.cal/time.cal.year/time.cal.year.nonmembers/ostream.pass.cpp
index 6e95849e9faf4..cd565b82bc2a6 100644
--- a/libcxx/test/std/time/time.cal/time.cal.year/time.cal.year.nonmembers/ostream.pass.cpp
+++ b/libcxx/test/std/time/time.cal/time.cal.year/time.cal.year.nonmembers/ostream.pass.cpp
@@ -9,9 +9,6 @@
// UNSUPPORTED: c++03, c++11, c++14, c++17
// UNSUPPORTED: no-localization
-// TODO FMT Investigate Windows issues.
-// UNSUPPORTED: msvc, target={{.+}}-windows-gnu
-
// TODO FMT Fix this test using GCC, it currently crashes.
// UNSUPPORTED: gcc-12
@@ -35,9 +32,16 @@
#include "make_string.h"
#include "platform_support.h" // locale name macros
#include "test_macros.h"
+#include "assert_macros.h"
+#include "concat_macros.h"
#define SV(S) MAKE_STRING_VIEW(CharT, S)
+#define TEST_EQUAL(OUT, EXPECTED) \
+ TEST_REQUIRE(OUT == EXPECTED, \
+ TEST_WRITE_CONCATENATED( \
+ "\nExpression ", #OUT, "\nExpected output ", EXPECTED, "\nActual output ", OUT, '\n'));
+
template <class CharT>
static std::basic_string<CharT> stream_c_locale(std::chrono::year year) {
std::basic_stringstream<CharT> sstr;
@@ -65,23 +69,23 @@ static std::basic_string<CharT> stream_ja_JP_locale(std::chrono::year year) {
template <class CharT>
static void test() {
- assert(stream_c_locale<CharT>(std::chrono::year{-32'768}) == SV("-32768 is not a valid year"));
- assert(stream_c_locale<CharT>(std::chrono::year{-32'767}) == SV("-32767"));
- assert(stream_c_locale<CharT>(std::chrono::year{0}) == SV("0000"));
- assert(stream_c_locale<CharT>(std::chrono::year{1970}) == SV("1970"));
- assert(stream_c_locale<CharT>(std::chrono::year{32'767}) == SV("32767"));
-
- assert(stream_fr_FR_locale<CharT>(std::chrono::year{-32'768}) == SV("-32768 is not a valid year"));
- assert(stream_fr_FR_locale<CharT>(std::chrono::year{-32'767}) == SV("-32767"));
- assert(stream_fr_FR_locale<CharT>(std::chrono::year{0}) == SV("0000"));
- assert(stream_fr_FR_locale<CharT>(std::chrono::year{1970}) == SV("1970"));
- assert(stream_fr_FR_locale<CharT>(std::chrono::year{32'767}) == SV("32767"));
-
- assert(stream_ja_JP_locale<CharT>(std::chrono::year{-32'768}) == SV("-32768 is not a valid year"));
- assert(stream_ja_JP_locale<CharT>(std::chrono::year{-32'767}) == SV("-32767"));
- assert(stream_ja_JP_locale<CharT>(std::chrono::year{0}) == SV("0000"));
- assert(stream_ja_JP_locale<CharT>(std::chrono::year{1970}) == SV("1970"));
- assert(stream_ja_JP_locale<CharT>(std::chrono::year{32'767}) == SV("32767"));
+ TEST_EQUAL(stream_c_locale<CharT>(std::chrono::year{-32'768}), SV("-32768 is not a valid year"));
+ TEST_EQUAL(stream_c_locale<CharT>(std::chrono::year{-32'767}), SV("-32767"));
+ TEST_EQUAL(stream_c_locale<CharT>(std::chrono::year{0}), SV("0000"));
+ TEST_EQUAL(stream_c_locale<CharT>(std::chrono::year{1970}), SV("1970"));
+ TEST_EQUAL(stream_c_locale<CharT>(std::chrono::year{32'767}), SV("32767"));
+
+ TEST_EQUAL(stream_fr_FR_locale<CharT>(std::chrono::year{-32'768}), SV("-32768 is not a valid year"));
+ TEST_EQUAL(stream_fr_FR_locale<CharT>(std::chrono::year{-32'767}), SV("-32767"));
+ TEST_EQUAL(stream_fr_FR_locale<CharT>(std::chrono::year{0}), SV("0000"));
+ TEST_EQUAL(stream_fr_FR_locale<CharT>(std::chrono::year{1970}), SV("1970"));
+ TEST_EQUAL(stream_fr_FR_locale<CharT>(std::chrono::year{32'767}), SV("32767"));
+
+ TEST_EQUAL(stream_ja_JP_locale<CharT>(std::chrono::year{-32'768}), SV("-32768 is not a valid year"));
+ TEST_EQUAL(stream_ja_JP_locale<CharT>(std::chrono::year{-32'767}), SV("-32767"));
+ TEST_EQUAL(stream_ja_JP_locale<CharT>(std::chrono::year{0}), SV("0000"));
+ TEST_EQUAL(stream_ja_JP_locale<CharT>(std::chrono::year{1970}), SV("1970"));
+ TEST_EQUAL(stream_ja_JP_locale<CharT>(std::chrono::year{32'767}), SV("32767"));
}
int main(int, char**) {
diff --git a/libcxx/test/std/time/time.syn/formatter.year.pass.cpp b/libcxx/test/std/time/time.syn/formatter.year.pass.cpp
index c29140c8192c5..33c427932573a 100644
--- a/libcxx/test/std/time/time.syn/formatter.year.pass.cpp
+++ b/libcxx/test/std/time/time.syn/formatter.year.pass.cpp
@@ -10,9 +10,6 @@
// UNSUPPORTED: c++03, c++11, c++14, c++17
// UNSUPPORTED: no-localization
-// TODO FMT Investigate Windows issues.
-// UNSUPPORTED: msvc, target={{.+}}-windows-gnu
-
// TODO FMT Fix this test using GCC, it currently crashes.
// UNSUPPORTED: gcc-12
@@ -88,7 +85,7 @@ static void test_valid_values() {
// Non localized output using C-locale
check(SV("%C='00'\t"
-#if defined(__APPLE__)
+#if defined(__APPLE__) || defined(_WIN32)
"%EC='00'\t"
#else
"%EC='0'\t"
@@ -97,7 +94,7 @@ static void test_valid_values() {
"%Ey='00'\t"
"%Oy='00'\t"
"%Y='0000'\t"
-#if defined(__APPLE__)
+#if defined(__APPLE__) || defined(_WIN32)
"%EY='0000'\t"
#elif defined(_AIX)
"%EY=''\t"
@@ -132,7 +129,7 @@ static void test_valid_values() {
// Use the global locale (fr_FR)
check(SV("%C='00'\t"
-#if defined(__APPLE__)
+#if defined(__APPLE__) || defined(_WIN32)
"%EC='00'\t"
#else
"%EC='0'\t"
@@ -141,7 +138,7 @@ static void test_valid_values() {
"%Ey='00'\t"
"%Oy='00'\t"
"%Y='0000'\t"
-#if defined(__APPLE__)
+#if defined(__APPLE__) || defined(_WIN32)
"%EY='0000'\t"
#elif defined(_AIX)
"%EY=''\t"
@@ -175,10 +172,10 @@ static void test_valid_values() {
std::chrono::year{2038});
// Use supplied locale (ja_JP). This locale has a
diff erent alternate.
-#if defined(__APPLE__) || defined(_AIX)
+#if defined(__APPLE__) || defined(_AIX) || defined(_WIN32)
check(SV("%C='00'\t"
-# if defined(__APPLE__)
+# if defined(__APPLE__) || defined(_WIN32)
"%EC='00'\t"
# else
"%EC='0'\t"
@@ -218,12 +215,12 @@ static void test_valid_values() {
lfmt,
std::chrono::year{2038});
-#else // defined(__APPLE__) || defined(_AIX)
+#else // defined(__APPLE__) || defined(_AIX) || defined(_WIN32)
check(loc,
SV("%C='00'\t"
"%EC='紀元前'\t"
"%y='00'\t"
-// https://sourceware.org/bugzilla/show_bug.cgi?id=23758
+ // https://sourceware.org/bugzilla/show_bug.cgi?id=23758
# if defined(__GLIBC__) && __GLIBC__ <= 2 && __GLIBC_MINOR__ < 29
"%Ey='1'\t"
# else
@@ -231,7 +228,7 @@ static void test_valid_values() {
# endif
"%Oy='〇'\t"
"%Y='0000'\t"
-// https://sourceware.org/bugzilla/show_bug.cgi?id=23758
+ // https://sourceware.org/bugzilla/show_bug.cgi?id=23758
# if defined(__GLIBC__) && __GLIBC__ <= 2 && __GLIBC_MINOR__ < 29
"%EY='紀元前1年'\t"
# else
@@ -265,7 +262,7 @@ static void test_valid_values() {
"\n"),
lfmt,
std::chrono::year{2038});
-#endif // defined(__APPLE__) || defined(_AIX)
+#endif // defined(__APPLE__) || defined(_AIX) || defined(_WIN32)
std::locale::global(std::locale::classic());
}
@@ -273,7 +270,6 @@ static void test_valid_values() {
template <class CharT>
static void test_padding() {
constexpr std::basic_string_view<CharT> fmt = SV("{:%%C='%C'%t%%y='%y'%t%%Y='%Y'%t%n}");
-
check(SV("%C='-100'\t%y='99'\t%Y='-9999'\t\n"), fmt, std::chrono::year{-9'999});
check(SV("%C='-10'\t%y='99'\t%Y='-0999'\t\n"), fmt, std::chrono::year{-999});
check(SV("%C='-1'\t%y='99'\t%Y='-0099'\t\n"), fmt, std::chrono::year{-99});
More information about the libcxx-commits
mailing list