[committed] libstdc++: Implement ostream insertion for chrono::duration

Jonathan Wakely jwakely@redhat.com
Fri Oct 8 11:21:00 GMT 2021


This is a missing piece of the C++20 <chrono> header.

It would be good to move the code into the compiled library, so that we
don't need <sstream> in <chrono>. 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.

-------------- next part --------------
commit fcc13d6fc31441b5672b68a5e3b247687724218f
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Thu Oct 7 19:58:07 2021

    libstdc++: Implement ostream insertion for chrono::duration
    
    This is a missing piece of the C++20 <chrono> header.
    
    It would be good to move the code into the compiled library, so that we
    don't need <sstream> in <chrono>. 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 <bits/chrono.h>
+#if __cplusplus > 201703L
+# include <sstream> // ostringstream
+# include <bits/charconv.h>
+#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<typename _Period>
+	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<typename _Period, typename _CharT>
+	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<typename _CharT, typename _Traits,
+	     typename _Rep, typename _Period>
+      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<intmax_t>::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<period, _CharT>(__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 <chrono>
+#include <sstream>
+#include <testsuite_hooks.h>
+
+void
+test01()
+{
+  using namespace std::chrono;
+  std::stringstream ss;
+  ss << 0s << '\n';
+  ss << 3h + 5min << '\n';
+  ss << duration<long, std::ratio<2>>(3) << '\n';
+  ss << duration<long, std::ratio<2, 3>>(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<long, std::ratio<2>>(3) << L'\n';
+  ss << duration<long, std::ratio<2, 3>>(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();
+}


More information about the Gcc-patches mailing list