From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 2181) id F3FD93857C73; Fri, 8 Oct 2021 11:20:53 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org F3FD93857C73 MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset="utf-8" From: Jonathan Wakely To: gcc-cvs@gcc.gnu.org, libstdc++-cvs@gcc.gnu.org Subject: [gcc r12-4246] libstdc++: Implement ostream insertion for chrono::duration X-Act-Checkin: gcc X-Git-Author: Jonathan Wakely X-Git-Refname: refs/heads/master X-Git-Oldrev: db3d7270b42fe27fb05664c4fdf524ab7ad13a75 X-Git-Newrev: fcc13d6fc31441b5672b68a5e3b247687724218f Message-Id: <20211008112053.F3FD93857C73@sourceware.org> Date: Fri, 8 Oct 2021 11:20:53 +0000 (GMT) X-BeenThere: libstdc++-cvs@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Libstdc++-cvs mailing list List-Unsubscribe: , List-Archive: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 08 Oct 2021 11:20:54 -0000 https://gcc.gnu.org/g:fcc13d6fc31441b5672b68a5e3b247687724218f commit r12-4246-gfcc13d6fc31441b5672b68a5e3b247687724218f Author: Jonathan Wakely Date: Thu Oct 7 19:58:07 2021 +0100 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: --- libstdc++-v3/include/std/chrono | 99 +++++++++++++++++++++++++++ libstdc++-v3/testsuite/20_util/duration/io.cc | 54 +++++++++++++++ 2 files changed, 153 insertions(+) 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(); +}