On Tue, 6 May 2025 at 13:35, Tomasz Kamiński <tkami...@redhat.com> 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.
> ---
> Reduced the dg-options to just set add -fexec-charset=UTF-8.
> OK for trunk?

OK thanks.

I think this is OK for backport to gcc-15 too, but I think it's not
needed on gcc-14 (because on that branch chrono formatting already has
some flaws regarding non-ASCII text).


>
>  libstdc++-v3/include/bits/chrono_io.h         |   9 +-
>  .../testsuite/std/time/format/pr120114.cc     | 125 ++++++++++++++++++
>  2 files changed, 132 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..c630bb35a9d
> --- /dev/null
> +++ b/libstdc++-v3/testsuite/std/time/format/pr120114.cc
> @@ -0,0 +1,125 @@
> +// { dg-do run { target c++23 } }
> +// { dg-options "-fexec-charset=UTF-8" }
> +// { 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