On Tue, 6 May 2025 at 13:06, Tomasz Kaminski <tkami...@redhat.com> wrote:
>
>
>
> On Tue, May 6, 2025 at 1:59 PM Jonathan Wakely <jwak...@redhat.com> wrote:
>>
>> On 05/05/25 16:45 +0200, Tomasz Kamiński wrote:
>> >Use `__unicode::_field_width` to compute the field width of the output when 
>> >writting
>> >the formatted output for std::chrono::types. This applies both to 
>> >characters copied
>> >from format string, and one produced by localized formatting.
>> >
>> >We also use _Str_sink::view() instead of get(), which avoids copying the 
>> >content of
>> >the buffer to std::string in case of small output.
>> >
>> >       PR libstdc++/120114
>> >
>> >libstdc++-v3/ChangeLog:
>> >
>> >       * include/bits/chrono_io.h (__formatter_chrono::_M_format): Use 
>> > __field_width.
>> >       * testsuite/std/time/format/pr120114.cc: New test.
>> >---
>> > libstdc++-v3/include/bits/chrono_io.h         |   9 +-
>> > .../testsuite/std/time/format/pr120114.cc     | 127 ++++++++++++++++++
>> > 2 files changed, 134 insertions(+), 2 deletions(-)
>> > create mode 100644 libstdc++-v3/testsuite/std/time/format/pr120114.cc
>> >
>> >diff --git a/libstdc++-v3/include/bits/chrono_io.h 
>> >b/libstdc++-v3/include/bits/chrono_io.h
>> >index b7f6f5f49e5..620227a9f35 100644
>> >--- a/libstdc++-v3/include/bits/chrono_io.h
>> >+++ b/libstdc++-v3/include/bits/chrono_io.h
>> >@@ -705,8 +705,13 @@ namespace __format
>> >           if (__write_direct)
>> >             return __out;
>> >
>> >-        auto __str = std::move(__sink).get();
>> >-        return __format::__write_padded_as_spec(__str, __str.size(),
>> >+        auto __str = __sink.view();
>> >+        size_t __width;
>> >+        if constexpr (__unicode::__literal_encoding_is_unicode<_CharT>())
>> >+          __width = __unicode::__field_width(__str);
>> >+        else
>> >+          __width = __str.size();
>> >+        return __format::__write_padded_as_spec(__str, __width,
>> >                                                 __fc, _M_spec);
>> >       }
>> >
>> >diff --git a/libstdc++-v3/testsuite/std/time/format/pr120114.cc 
>> >b/libstdc++-v3/testsuite/std/time/format/pr120114.cc
>> >new file mode 100644
>> >index 00000000000..08968eb053a
>> >--- /dev/null
>> >+++ b/libstdc++-v3/testsuite/std/time/format/pr120114.cc
>> >@@ -0,0 +1,127 @@
>> >+// { dg-options "-fexec-charset=UTF-8 -fwide-exec-charset=UTF-32LE 
>> >-DUNICODE_ENC" { target le } }
>> >+// { dg-options "-fexec-charset=UTF-8 -fwide-exec-charset=UTF-32BE 
>> >-DUNICODE_ENC" { target be } }
>>
>> Do we need the -DUNICODE_ENC options? The macro isn't used in the
>> test.
>>
>> Do we even need the exec charset options here?
>
> I believe "\u32C8" is ill-formed when the exec-charset is not UTF-8, so I 
> think "-fexec-charset=UTF-8" is necessary.

UTF-8 is the default so it would only fail if people intentionally run
the tests with some other -fexec-charset option, but I do occasionally
do that to test things with e.g. -fexec-charset=ascii so let's keep
the -fexec-charset


>
>>
>> >+// { dg-do run { target c++23 } }
>> >+// { dg-add-options no_pch }
>>
>> I don't think we need no_pch here either.
>>
>> >+// { dg-timeout-factor 2 }
>> >+
>> >+#include <algorithm>
>> >+#include <chrono>
>> >+#include <testsuite_hooks.h>
>> >+
>> >+#define WIDEN_(C, S) ::std::__format::_Widen<C>(S, L##S)
>> >+#define WIDEN(S) WIDEN_(_CharT, S)
>> >+
>> >+template<typename _CharT>
>> >+void
>> >+test_from_format_string()
>> >+{
>> >+  std::basic_string<_CharT> res;
>> >+  using namespace std::chrono_literals;
>> >+  auto date = 2025y/std::chrono::May/05d;
>> >+
>> >+  res = std::format(WIDEN("{:+<13%F\U0001f921}"), date);
>> >+  VERIFY( res == WIDEN("2025-05-05\U0001f921+") );
>> >+
>> >+  res = std::format(WIDEN("{:->15%F\U0001f921}"), date);
>> >+  VERIFY( res == WIDEN("---2025-05-05\U0001f921") );
>> >+
>> >+  res = std::format(WIDEN("{:=^20%F\U0001f921}"), date);
>> >+  VERIFY( res == WIDEN("====2025-05-05\U0001f921====") );
>> >+}
>> >+
>> >+template<typename _CharT>
>> >+void
>> >+test_formatted_value()
>> >+{
>> >+  // Custom time_put facet which returns Ideographic Telegraph Symbol
>> >+  // for given month for Om.
>> >+  struct TimePut : std::time_put<_CharT>
>> >+  {
>> >+    using iter_type = std::time_put<_CharT>::iter_type;
>> >+    using char_type = std::time_put<_CharT>::char_type;
>> >+
>> >+    iter_type
>> >+    do_put(iter_type out, std::ios_base& io, char_type fill, const tm* t,
>> >+         char format, char modifier) const override
>> >+    {
>> >+      if (format != 'm' && modifier != 'm')
>> >+      return std::time_put<_CharT>::do_put(out, io, fill, t, format, 
>> >modifier);
>> >+      std::basic_string_view<_CharT> str;
>> >+      switch (t->tm_mon)
>> >+       {
>> >+       case 0:
>> >+         str = WIDEN("\u32C0");
>> >+         break;
>> >+       case 1:
>> >+         str = WIDEN("\u32C1");
>> >+         break;
>> >+       case 2:
>> >+         str = WIDEN("\u32C2");
>> >+         break;
>> >+       case 3:
>> >+         str = WIDEN("\u32C3");
>> >+         break;
>> >+       case 4:
>> >+         str = WIDEN("\u32C4");
>> >+         break;
>> >+       case 5:
>> >+         str = WIDEN("\u32C5");
>> >+         break;
>> >+       case 6:
>> >+         str = WIDEN("\u32C6");
>> >+         break;
>> >+       case 7:
>> >+         str = WIDEN("\u32C7");
>> >+         break;
>> >+       case 8:
>> >+         str = WIDEN("\u32C8");
>> >+         break;
>> >+       case 9:
>> >+         str = WIDEN("\u32C9");
>> >+         break;
>> >+       case 10:
>> >+         str = WIDEN("\u32CA");
>> >+         break;
>> >+       case 11:
>> >+         str = WIDEN("\u32CB");
>> >+         break;
>> >+       };
>> >+       return std::copy(str.begin(), str.end(), out);
>> >+    }
>> >+  };
>> >+  const std::locale loc(std::locale::classic(), new TimePut);
>> >+
>> >+  std::basic_string<_CharT> res;
>> >+
>> >+  res = std::format(loc, WIDEN("{:<1L%Om}"), std::chrono::January);
>> >+  VERIFY( res == WIDEN("\u32C0") );
>> >+
>> >+  res = std::format(loc, WIDEN("{:>2L%Om}"), std::chrono::February);
>> >+  VERIFY( res == WIDEN("\u32C1") );
>> >+
>> >+  res = std::format(loc, WIDEN("{:<3L%Om}"), std::chrono::March);
>> >+  VERIFY( res == WIDEN("\u32C2 ") );
>> >+
>> >+  res = std::format(loc, WIDEN("{:^4L%Om}"), std::chrono::April);
>> >+  VERIFY( res == WIDEN(" \u32C3 ") );
>> >+
>> >+  res = std::format(loc, WIDEN("{:>5L%Om}"), std::chrono::May);
>> >+  VERIFY( res == WIDEN("   \u32C4") );
>> >+
>> >+  res = std::format(loc, WIDEN("{:+<6L%Om}"), std::chrono::June);
>> >+  VERIFY( res == WIDEN("\u32C5++++") );
>> >+
>> >+  res = std::format(loc, WIDEN("{:=^7L%Om}"), std::chrono::July);
>> >+  VERIFY( res == WIDEN("==\u32C6===") );
>> >+
>> >+  res = std::format(loc, WIDEN("{:->8L%Om}"), std::chrono::August);
>> >+  VERIFY( res == WIDEN("------\u32C7") );
>> >+}
>> >+
>> >+int main()
>> >+{
>> >+  test_from_format_string<char>();
>> >+  test_from_format_string<wchar_t>();
>> >+  test_formatted_value<char>();
>> >+  test_formatted_value<wchar_t>();
>> >+}
>> >--
>> >2.49.0
>> >
>> >
>>

Reply via email to