From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [216.205.24.124]) by sourceware.org (Postfix) with ESMTP id 7B5123858431 for ; Fri, 8 Oct 2021 11:21:04 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 7B5123858431 Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-345-lit1kjzBMMWrbB4u57-jSw-1; Fri, 08 Oct 2021 07:21:02 -0400 X-MC-Unique: lit1kjzBMMWrbB4u57-jSw-1 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.phx2.redhat.com [10.5.11.13]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 6FD85362F9; Fri, 8 Oct 2021 11:21:01 +0000 (UTC) Received: from localhost (unknown [10.33.37.44]) by smtp.corp.redhat.com (Postfix) with ESMTP id 1A23360936; Fri, 8 Oct 2021 11:21:00 +0000 (UTC) Date: Fri, 8 Oct 2021 12:21:00 +0100 From: Jonathan Wakely To: libstdc++@gcc.gnu.org, gcc-patches@gcc.gnu.org Subject: [committed] libstdc++: Implement ostream insertion for chrono::duration Message-ID: MIME-Version: 1.0 X-Clacks-Overhead: GNU Terry Pratchett X-Scanned-By: MIMEDefang 2.79 on 10.5.11.13 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Type: multipart/mixed; boundary="bL4sV6kwCrI4SyYi" Content-Disposition: inline X-Spam-Status: No, score=-13.8 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_LOW, RCVD_IN_MSPIKE_H2, SPF_HELO_NONE, SPF_NONE, TXREP autolearn=ham autolearn_force=no version=3.4.4 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on server2.sourceware.org X-BeenThere: libstdc++@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Libstdc++ mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 08 Oct 2021 11:21:07 -0000 --bL4sV6kwCrI4SyYi Content-Type: text/plain; charset=us-ascii Content-Disposition: inline This is a missing piece of the C++20 header. It would be good to move the code into the compiled library, so that we don't need in . It could also use spanstream in C++20, to avoid memory allocations. That can be changed at a later date. libstdc++-v3/ChangeLog: * include/std/chrono (__detail::__units_suffix_misc): New helper function. (__detail::__units_suffix): Likewise. (chrono::operator<<(basic_ostream&, const duration&)): Define. * testsuite/20_util/duration/io.cc: New test. Tested powerpc64le-linux. Committed to trunk. --bL4sV6kwCrI4SyYi Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="patch.txt" commit fcc13d6fc31441b5672b68a5e3b247687724218f Author: Jonathan Wakely Date: Thu Oct 7 19:58:07 2021 libstdc++: Implement ostream insertion for chrono::duration This is a missing piece of the C++20 header. It would be good to move the code into the compiled library, so that we don't need in . It could also use spanstream in C++20, to avoid memory allocations. That can be changed at a later date. libstdc++-v3/ChangeLog: * include/std/chrono (__detail::__units_suffix_misc): New helper function. (__detail::__units_suffix): Likewise. (chrono::operator<<(basic_ostream&, const duration&)): Define. * testsuite/20_util/duration/io.cc: New test. diff --git a/libstdc++-v3/include/std/chrono b/libstdc++-v3/include/std/chrono index c8060d7a67e..0662e26348f 100644 --- a/libstdc++-v3/include/std/chrono +++ b/libstdc++-v3/include/std/chrono @@ -37,6 +37,10 @@ #else #include +#if __cplusplus > 201703L +# include // ostringstream +# include +#endif namespace std _GLIBCXX_VISIBILITY(default) { @@ -2077,6 +2081,101 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION /// @} } // inline namespace chrono_literals } // inline namespace literals + + namespace chrono + { + /// @addtogroup chrono + /// @{ + + /// @cond undocumented + namespace __detail + { + template + const char* + __units_suffix_misc(char* __buf, size_t __n) noexcept + { + namespace __tc = std::__detail; + char* __p = __buf; + __p[0] = '['; + unsigned __nlen = __tc::__to_chars_len((uintmax_t)_Period::num); + __tc::__to_chars_10_impl(__p + 1, __nlen, (uintmax_t)_Period::num); + __p += 1 + __nlen; + if constexpr (_Period::den != 1) + { + __p[0] = '/'; + unsigned __dlen = __tc::__to_chars_len((uintmax_t)_Period::den); + __tc::__to_chars_10_impl(__p + 1, __dlen, (uintmax_t)_Period::den); + __p += 1 + __dlen; + } + __p[0] = ']'; + __p[1] = 's'; + __p[2] = '\0'; + return __buf; + } + + template + auto + __units_suffix(char* __buf, size_t __n) noexcept + { +#define _GLIBCXX_UNITS_SUFFIX(period, suffix) \ + if constexpr (is_same_v<_Period, period>) \ + { \ + if constexpr (is_same_v<_CharT, wchar_t>) \ + return L##suffix; \ + else \ + return suffix; \ + } \ + else + + _GLIBCXX_UNITS_SUFFIX(atto, "as") + _GLIBCXX_UNITS_SUFFIX(femto, "fs") + _GLIBCXX_UNITS_SUFFIX(pico, "ps") + _GLIBCXX_UNITS_SUFFIX(nano, "ns") + _GLIBCXX_UNITS_SUFFIX(micro, "\u00b5s") + _GLIBCXX_UNITS_SUFFIX(milli, "ms") + _GLIBCXX_UNITS_SUFFIX(centi, "cs") + _GLIBCXX_UNITS_SUFFIX(deci, "ds") + _GLIBCXX_UNITS_SUFFIX(ratio<1>, "s") + _GLIBCXX_UNITS_SUFFIX(deca, "das") + _GLIBCXX_UNITS_SUFFIX(hecto, "hs") + _GLIBCXX_UNITS_SUFFIX(kilo, "ks") + _GLIBCXX_UNITS_SUFFIX(mega, "Ms") + _GLIBCXX_UNITS_SUFFIX(giga, "Gs") + _GLIBCXX_UNITS_SUFFIX(tera, "Ts") + _GLIBCXX_UNITS_SUFFIX(tera, "Ts") + _GLIBCXX_UNITS_SUFFIX(peta, "Ps") + _GLIBCXX_UNITS_SUFFIX(exa, "Es") + _GLIBCXX_UNITS_SUFFIX(ratio<60>, "min") + _GLIBCXX_UNITS_SUFFIX(ratio<3600>, "h") + _GLIBCXX_UNITS_SUFFIX(ratio<86400>, "d") +#undef _GLIBCXX_UNITS_SUFFIX + return __detail::__units_suffix_misc<_Period>(__buf, __n); + } + } // namespace __detail + /// @endcond + + template + inline basic_ostream<_CharT, _Traits>& + operator<<(std::basic_ostream<_CharT, _Traits>& __os, + const duration<_Rep, _Period>& __d) + { + using period = typename _Period::type; + char __buf[sizeof("[/]s") + 2 * numeric_limits::digits10]; + std::basic_ostringstream<_CharT, _Traits> __s; + __s.flags(__os.flags()); + __s.imbue(__os.getloc()); + __s.precision(__os.precision()); + __s << __d.count(); + __s << __detail::__units_suffix(__buf, sizeof(__buf)); + __os << std::move(__s).str(); + return __os; + } + + // TODO: from_stream for duration + + /// @} group chrono + } // namespace chrono #endif // C++20 _GLIBCXX_END_NAMESPACE_VERSION diff --git a/libstdc++-v3/testsuite/20_util/duration/io.cc b/libstdc++-v3/testsuite/20_util/duration/io.cc new file mode 100644 index 00000000000..405e1afa440 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/duration/io.cc @@ -0,0 +1,54 @@ +// { dg-options "-std=gnu++20" } +// { dg-do run { target c++20 } } + +#include +#include +#include + +void +test01() +{ + using namespace std::chrono; + std::stringstream ss; + ss << 0s << '\n'; + ss << 3h + 5min << '\n'; + ss << duration>(3) << '\n'; + ss << duration>(9) << '\n'; + std::string s; + std::getline(ss, s); + VERIFY( s == "0s" ); + std::getline(ss, s); + VERIFY( s == "185min" ); + std::getline(ss, s); + VERIFY( s == "3[2]s" ); + std::getline(ss, s); + VERIFY( s == "9[2/3]s" ); +} + +void +test02() +{ +#ifdef _GLIBCXX_USE_WCHAR_T + using namespace std::chrono; + std::wstringstream ss; + ss << 0s << L'\n'; + ss << 3h + 5min << L'\n'; + ss << duration>(3) << L'\n'; + ss << duration>(9) << L'\n'; + std::wstring s; + std::getline(ss, s); + VERIFY( s == L"0s" ); + std::getline(ss, s); + VERIFY( s == L"185min" ); + std::getline(ss, s); + VERIFY( s == L"3[2]s" ); + std::getline(ss, s); + VERIFY( s == L"9[2/3]s" ); +#endif +} + +int main() +{ + test01(); + test02(); +} --bL4sV6kwCrI4SyYi--