public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH] Implement C++17 rounding functions for std::chrono (P0092R1)
@ 2016-08-05 13:53 Jonathan Wakely
  0 siblings, 0 replies; only message in thread
From: Jonathan Wakely @ 2016-08-05 13:53 UTC (permalink / raw)
  To: libstdc++, gcc-patches

[-- Attachment #1: Type: text/plain, Size: 618 bytes --]

	* include/std/chrono (floor, ceil, round, abs): New for C++17.
	* testsuite/20_util/duration_cast/rounding.cc: New test.
	* testsuite/20_util/time_point_cast/rounding.cc: New test.
	* doc/xml/manual/status_cxx2017.xml: Update status table.
	* doc/html/manual/status.html: Regenerate.
	* testsuite/20_util/duration/requirements/typedefs_neg1.cc: Adjust
	dg-error lineno.
	* testsuite/20_util/duration/requirements/typedefs_neg2.cc: Likewise.
	* testsuite/20_util/duration/requirements/typedefs_neg3.cc: Likewise.
	* testsuite/20_util/duration/literals/range.cc: Likewise.

Tested powerpc64-linux, committed to trunk.


[-- Attachment #2: patch.txt --]
[-- Type: text/plain, Size: 13305 bytes --]

commit ac54a375293a58fc9b42e7bd8e8b0518c5988bd2
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Fri Aug 5 13:54:57 2016 +0100

    Implement C++17 rounding functions for std::chrono (P0092R1)
    
    	* include/std/chrono (floor, ceil, round, abs): New for C++17.
    	* testsuite/20_util/duration_cast/rounding.cc: New test.
    	* testsuite/20_util/time_point_cast/rounding.cc: New test.
    	* doc/xml/manual/status_cxx2017.xml: Update status table.
    	* doc/html/manual/status.html: Regenerate.
    	* testsuite/20_util/duration/requirements/typedefs_neg1.cc: Adjust
    	dg-error lineno.
    	* testsuite/20_util/duration/requirements/typedefs_neg2.cc: Likewise.
    	* testsuite/20_util/duration/requirements/typedefs_neg3.cc: Likewise.
    	* testsuite/20_util/duration/literals/range.cc: Likewise.

diff --git a/libstdc++-v3/doc/xml/manual/status_cxx2017.xml b/libstdc++-v3/doc/xml/manual/status_cxx2017.xml
index 8391758..4d098d1 100644
--- a/libstdc++-v3/doc/xml/manual/status_cxx2017.xml
+++ b/libstdc++-v3/doc/xml/manual/status_cxx2017.xml
@@ -437,14 +437,13 @@ Feature-testing recommendations for C++</link>.
     </row>
 
     <row>
-      <?dbhtml bgcolor="#C8B0B0" ?>
       <entry> Polishing <code>&lt;chrono&gt;</code> </entry>
       <entry>
 	<link xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0092r1.html">
 	P0092R1
 	</link>
       </entry>
-      <entry align="center"> No </entry>
+      <entry align="center"> 7 </entry>
       <entry><code> __cpp_lib_chrono >= 201510 </code></entry>
     </row>
 
diff --git a/libstdc++-v3/include/std/chrono b/libstdc++-v3/include/std/chrono
index fdb21b3..f29d8e1 100644
--- a/libstdc++-v3/include/std/chrono
+++ b/libstdc++-v3/include/std/chrono
@@ -208,11 +208,69 @@ _GLIBCXX_END_NAMESPACE_VERSION
       struct treat_as_floating_point
       : is_floating_point<_Rep>
       { };
+
 #if __cplusplus > 201402L
     template <typename _Rep>
       constexpr bool treat_as_floating_point_v =
         treat_as_floating_point<_Rep>::value;
 #endif // C++17
+
+#if __cplusplus > 201402L
+# define __cpp_lib_chrono 201510
+
+    template<typename _ToDur, typename _Rep, typename _Period>
+      constexpr enable_if_t<__is_duration<_ToDur>::value, _ToDur>
+      floor(const duration<_Rep, _Period>& __d)
+      {
+	auto __to = chrono::duration_cast<_ToDur>(__d);
+	if (__to > __d)
+	  --__to;
+	return __to;
+      }
+
+    template<typename _ToDur, typename _Rep, typename _Period>
+      constexpr enable_if_t<__is_duration<_ToDur>::value, _ToDur>
+      ceil(const duration<_Rep, _Period>& __d)
+      {
+	auto __to = chrono::duration_cast<_ToDur>(__d);
+	if (__to < __d)
+	  return __to + _ToDur{1};
+	return __to;
+      }
+
+    template <typename _ToDur, typename _Rep, typename _Period>
+      constexpr enable_if_t<
+	__and_<__is_duration<_ToDur>,
+	       __not_<treat_as_floating_point<typename _ToDur::rep>>>::value,
+	_ToDur>
+      round(const duration<_Rep, _Period>& __d)
+      {
+	_ToDur __t0 = chrono::floor<_ToDur>(__d);
+	_ToDur __t1 = __t0 + _ToDur{1};
+	auto __diff0 = __d - __t0;
+	auto __diff1 = __t1 - __d;
+	if (__diff0 == __diff1)
+	{
+	    if (__t0.count() & 1)
+		return __t1;
+	    return __t0;
+	}
+	else if (__diff0 < __diff1)
+	    return __t0;
+	return __t1;
+      }
+
+    template<typename _Rep, typename _Period>
+      constexpr
+      enable_if_t<numeric_limits<_Rep>::is_signed, duration<_Rep, _Period>>
+      abs(duration<_Rep, _Period> __d)
+      {
+	if (__d >= __d.zero())
+	  return __d;
+	return -__d;
+      }
+#endif // C++17
+
     /// duration_values
     template<typename _Rep>
       struct duration_values
@@ -610,6 +668,37 @@ _GLIBCXX_END_NAMESPACE_VERSION
 	return __time_point(duration_cast<_ToDur>(__t.time_since_epoch()));
       }
 
+#if __cplusplus > 201402L
+    template<typename _ToDur, typename _Clock, typename _Dur>
+      constexpr
+      enable_if_t<__is_duration<_ToDur>::value, time_point<_Clock, _ToDur>>
+      floor(const time_point<_Clock, _Dur>& __tp)
+      {
+	return time_point<_Clock, _ToDur>{
+	    chrono::floor<_ToDur>(__tp.time_since_epoch())};
+      }
+
+    template<typename _ToDur, typename _Clock, typename _Dur>
+      constexpr
+      enable_if_t<__is_duration<_ToDur>::value, time_point<_Clock, _ToDur>>
+      ceil(const time_point<_Clock, _Dur>& __tp)
+      {
+	return time_point<_Clock, _ToDur>{
+	    chrono::ceil<_ToDur>(__tp.time_since_epoch())};
+      }
+
+    template<typename _ToDur, typename _Clock, typename _Dur>
+      constexpr enable_if_t<
+	__and_<__is_duration<_ToDur>,
+	       __not_<treat_as_floating_point<typename _ToDur::rep>>>::value,
+	time_point<_Clock, _ToDur>>
+      round(const time_point<_Clock, _Dur>& __tp)
+      {
+	return time_point<_Clock, _ToDur>{
+	    chrono::round<_ToDur>(__tp.time_since_epoch())};
+      }
+#endif // C++17
+
     template<typename _Clock, typename _Dur1,
 	     typename _Rep2, typename _Period2>
       constexpr time_point<_Clock,
diff --git a/libstdc++-v3/testsuite/20_util/duration/literals/range.cc b/libstdc++-v3/testsuite/20_util/duration/literals/range.cc
index 6fe4bde..940236c 100644
--- a/libstdc++-v3/testsuite/20_util/duration/literals/range.cc
+++ b/libstdc++-v3/testsuite/20_util/duration/literals/range.cc
@@ -27,5 +27,5 @@ test01()
 
   // std::numeric_limits<int64_t>::max() == 9223372036854775807;
   auto h = 9223372036854775808h;
-  // { dg-error "cannot be represented" "" { target *-*-* } 800 }
+  // { dg-error "cannot be represented" "" { target *-*-* } 889 }
 }
diff --git a/libstdc++-v3/testsuite/20_util/duration/requirements/typedefs_neg1.cc b/libstdc++-v3/testsuite/20_util/duration/requirements/typedefs_neg1.cc
index 731a4a7..db9a4f5 100644
--- a/libstdc++-v3/testsuite/20_util/duration/requirements/typedefs_neg1.cc
+++ b/libstdc++-v3/testsuite/20_util/duration/requirements/typedefs_neg1.cc
@@ -31,5 +31,5 @@ void test01()
   test_type d;
 }
 
-// { dg-error "rep cannot be a duration" "" { target *-*-* } 250 }
+// { dg-error "rep cannot be a duration" "" { target *-*-* } 308 }
 // { dg-error "required from here" "" { target *-*-* } 31 }
diff --git a/libstdc++-v3/testsuite/20_util/duration/requirements/typedefs_neg2.cc b/libstdc++-v3/testsuite/20_util/duration/requirements/typedefs_neg2.cc
index c32b885..e562134 100644
--- a/libstdc++-v3/testsuite/20_util/duration/requirements/typedefs_neg2.cc
+++ b/libstdc++-v3/testsuite/20_util/duration/requirements/typedefs_neg2.cc
@@ -32,5 +32,5 @@ void test01()
   test_type d;			// { dg-error "required from here" }
 }
 
-// { dg-error "must be a specialization of ratio" "" { target *-*-* } 251 }
+// { dg-error "must be a specialization of ratio" "" { target *-*-* } 309 }
 // { dg-prune-output "not a member" }
diff --git a/libstdc++-v3/testsuite/20_util/duration/requirements/typedefs_neg3.cc b/libstdc++-v3/testsuite/20_util/duration/requirements/typedefs_neg3.cc
index 7fb022b..a71d5b1 100644
--- a/libstdc++-v3/testsuite/20_util/duration/requirements/typedefs_neg3.cc
+++ b/libstdc++-v3/testsuite/20_util/duration/requirements/typedefs_neg3.cc
@@ -33,4 +33,4 @@ void test01()
   test_type d;  // { dg-error "required from here" }
 }
 
-// { dg-error "period must be positive" "" { target *-*-* } 253 }
+// { dg-error "period must be positive" "" { target *-*-* } 311 }
diff --git a/libstdc++-v3/testsuite/20_util/duration_cast/rounding.cc b/libstdc++-v3/testsuite/20_util/duration_cast/rounding.cc
new file mode 100644
index 0000000..a753323
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/duration_cast/rounding.cc
@@ -0,0 +1,57 @@
+// Copyright (C) 2016 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++17" }
+// { dg-do compile }
+
+#include <chrono>
+
+#if __cpp_lib_chrono < 201510
+# error "__cpp_lib_chrono < 201510"
+#endif
+
+using namespace std::chrono_literals;
+using std::chrono::seconds;
+
+static_assert( std::chrono::floor<seconds>(1000ms) == 1s );
+static_assert( std::chrono::floor<seconds>(1001ms) == 1s );
+static_assert( std::chrono::floor<seconds>(1500ms) == 1s );
+static_assert( std::chrono::floor<seconds>(1999ms) == 1s );
+static_assert( std::chrono::floor<seconds>(2000ms) == 2s );
+static_assert( std::chrono::floor<seconds>(2001ms) == 2s );
+static_assert( std::chrono::floor<seconds>(2500ms) == 2s );
+
+static_assert( std::chrono::ceil<seconds>(1000ms) == 1s );
+static_assert( std::chrono::ceil<seconds>(1001ms) == 2s );
+static_assert( std::chrono::ceil<seconds>(1500ms) == 2s );
+static_assert( std::chrono::ceil<seconds>(1999ms) == 2s );
+static_assert( std::chrono::ceil<seconds>(2000ms) == 2s );
+static_assert( std::chrono::ceil<seconds>(2001ms) == 3s );
+static_assert( std::chrono::ceil<seconds>(2500ms) == 3s );
+
+static_assert( std::chrono::round<seconds>(1000ms) == 1s );
+static_assert( std::chrono::round<seconds>(1001ms) == 1s );
+static_assert( std::chrono::round<seconds>(1499ms) == 1s );
+static_assert( std::chrono::round<seconds>(1500ms) == 2s );
+static_assert( std::chrono::round<seconds>(1999ms) == 2s );
+static_assert( std::chrono::round<seconds>(2000ms) == 2s );
+static_assert( std::chrono::round<seconds>(2001ms) == 2s );
+static_assert( std::chrono::round<seconds>(2500ms) == 2s );
+static_assert( std::chrono::round<seconds>(2501ms) == 3s );
+
+static_assert( std::chrono::abs(100ms) == 100ms );
+static_assert( std::chrono::abs(-100ms) == 100ms );
diff --git a/libstdc++-v3/testsuite/20_util/time_point_cast/rounding.cc b/libstdc++-v3/testsuite/20_util/time_point_cast/rounding.cc
new file mode 100644
index 0000000..bf596e9
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/time_point_cast/rounding.cc
@@ -0,0 +1,59 @@
+// Copyright (C) 2016 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-do run { target c++11 } }
+
+// { dg-options "-std=gnu++17" }
+// { dg-do compile }
+
+#include <chrono>
+
+#if __cpp_lib_chrono < 201510
+# error "__cpp_lib_chrono < 201510"
+#endif
+
+using namespace std::chrono_literals;
+using std::chrono::seconds;
+using std::chrono::milliseconds;
+
+constexpr std::chrono::system_clock::time_point base{};
+
+static_assert( std::chrono::floor<seconds>(base + 1000ms) == (base + 1s) );
+static_assert( std::chrono::floor<seconds>(base + 1001ms) == (base + 1s) );
+static_assert( std::chrono::floor<seconds>(base + 1500ms) == (base + 1s) );
+static_assert( std::chrono::floor<seconds>(base + 1999ms) == (base + 1s) );
+static_assert( std::chrono::floor<seconds>(base + 2000ms) == (base + 2s) );
+static_assert( std::chrono::floor<seconds>(base + 2001ms) == (base + 2s) );
+static_assert( std::chrono::floor<seconds>(base + 2500ms) == (base + 2s) );
+
+static_assert( std::chrono::ceil<seconds>(base + 1000ms) == (base + 1s) );
+static_assert( std::chrono::ceil<seconds>(base + 1001ms) == (base + 2s) );
+static_assert( std::chrono::ceil<seconds>(base + 1500ms) == (base + 2s) );
+static_assert( std::chrono::ceil<seconds>(base + 1999ms) == (base + 2s) );
+static_assert( std::chrono::ceil<seconds>(base + 2000ms) == (base + 2s) );
+static_assert( std::chrono::ceil<seconds>(base + 2001ms) == (base + 3s) );
+static_assert( std::chrono::ceil<seconds>(base + 2500ms) == (base + 3s) );
+
+static_assert( std::chrono::round<seconds>(base + 1000ms) == (base + 1s) );
+static_assert( std::chrono::round<seconds>(base + 1001ms) == (base + 1s) );
+static_assert( std::chrono::round<seconds>(base + 1499ms) == (base + 1s) );
+static_assert( std::chrono::round<seconds>(base + 1500ms) == (base + 2s) );
+static_assert( std::chrono::round<seconds>(base + 1999ms) == (base + 2s) );
+static_assert( std::chrono::round<seconds>(base + 2000ms) == (base + 2s) );
+static_assert( std::chrono::round<seconds>(base + 2001ms) == (base + 2s) );
+static_assert( std::chrono::round<seconds>(base + 2500ms) == (base + 2s) );
+static_assert( std::chrono::round<seconds>(base + 2501ms) == (base + 3s) );

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2016-08-05 13:53 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-08-05 13:53 [PATCH] Implement C++17 rounding functions for std::chrono (P0092R1) Jonathan Wakely

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).