From 5f6acdfb0ba89c642058479a3e2d78edbc94d2f1 Mon Sep 17 00:00:00 2001 From: Jonathan Wakely Date: Fri, 5 Aug 2016 14:52:59 +0100 Subject: [PATCH] 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. From-SVN: r239170 --- libstdc++-v3/ChangeLog | 11 +++ libstdc++-v3/doc/html/manual/status.html | 8 +- .../doc/xml/manual/status_cxx2017.xml | 3 +- libstdc++-v3/include/std/chrono | 89 +++++++++++++++++++ .../20_util/duration/literals/range.cc | 2 +- .../duration/requirements/typedefs_neg1.cc | 2 +- .../duration/requirements/typedefs_neg2.cc | 2 +- .../duration/requirements/typedefs_neg3.cc | 2 +- .../20_util/duration_cast/rounding.cc | 57 ++++++++++++ .../20_util/time_point_cast/rounding.cc | 59 ++++++++++++ 10 files changed, 225 insertions(+), 10 deletions(-) create mode 100644 libstdc++-v3/testsuite/20_util/duration_cast/rounding.cc create mode 100644 libstdc++-v3/testsuite/20_util/time_point_cast/rounding.cc diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index c6df8abfa64..b5516d6745f 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,5 +1,16 @@ 2016-08-05 Jonathan Wakely + * 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. + * include/std/functional (__callable_functor): Remove. (_Function_handler::_M_invoke): Use __invoke instead of __callable_functor or mem_fn. diff --git a/libstdc++-v3/doc/html/manual/status.html b/libstdc++-v3/doc/html/manual/status.html index 0b4821c00f8..ada3d688ac9 100644 --- a/libstdc++-v3/doc/html/manual/status.html +++ b/libstdc++-v3/doc/html/manual/status.html @@ -606,11 +606,11 @@ Feature-testing recommendations for C++. P0185R1 - 7 (__is_swappable available since 6.1) __cpp_lib_is_swappable >= 201603 is_callable, the missing INVOKE related trait + 7 (__is_swappable available since 6.1) __cpp_lib_is_swappable >= 201603 is_callable, the missing INVOKE related trait P0077R2 - No __cpp_lib_is_callable >= 201603 has_unique_object_representations + 7 __cpp_lib_is_callable >= 201603 has_unique_object_representations P0258R2 @@ -618,11 +618,11 @@ Feature-testing recommendations for C++. P0181R1 - No __cpp_lib_default_order >= 201606 Polishing <chrono> + No __cpp_lib_default_order >= 201606 Polishing <chrono> P0092R1 - No __cpp_lib_chrono >= 201510 Integrating std::string_view and std::string + 7 __cpp_lib_chrono >= 201510 Integrating std::string_view and std::string P0254R2 diff --git a/libstdc++-v3/doc/xml/manual/status_cxx2017.xml b/libstdc++-v3/doc/xml/manual/status_cxx2017.xml index 8391758333c..4d098d16baf 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++. - Polishing <chrono> P0092R1 - No + 7 __cpp_lib_chrono >= 201510 diff --git a/libstdc++-v3/include/std/chrono b/libstdc++-v3/include/std/chrono index fdb21b34d43..f29d8e1adbc 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 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 + 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 + 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 + constexpr enable_if_t< + __and_<__is_duration<_ToDur>, + __not_>>::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 + constexpr + enable_if_t::is_signed, duration<_Rep, _Period>> + abs(duration<_Rep, _Period> __d) + { + if (__d >= __d.zero()) + return __d; + return -__d; + } +#endif // C++17 + /// duration_values template 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 + 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 + 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 + constexpr enable_if_t< + __and_<__is_duration<_ToDur>, + __not_>>::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 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 6fe4bdea2ab..940236ce646 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::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 731a4a7092b..db9a4f5bc02 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 c32b8852dfa..e562134ffcb 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 7fb022b6221..a71d5b12039 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 00000000000..a7533230273 --- /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 +// . + +// { dg-options "-std=gnu++17" } +// { dg-do compile } + +#include + +#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(1000ms) == 1s ); +static_assert( std::chrono::floor(1001ms) == 1s ); +static_assert( std::chrono::floor(1500ms) == 1s ); +static_assert( std::chrono::floor(1999ms) == 1s ); +static_assert( std::chrono::floor(2000ms) == 2s ); +static_assert( std::chrono::floor(2001ms) == 2s ); +static_assert( std::chrono::floor(2500ms) == 2s ); + +static_assert( std::chrono::ceil(1000ms) == 1s ); +static_assert( std::chrono::ceil(1001ms) == 2s ); +static_assert( std::chrono::ceil(1500ms) == 2s ); +static_assert( std::chrono::ceil(1999ms) == 2s ); +static_assert( std::chrono::ceil(2000ms) == 2s ); +static_assert( std::chrono::ceil(2001ms) == 3s ); +static_assert( std::chrono::ceil(2500ms) == 3s ); + +static_assert( std::chrono::round(1000ms) == 1s ); +static_assert( std::chrono::round(1001ms) == 1s ); +static_assert( std::chrono::round(1499ms) == 1s ); +static_assert( std::chrono::round(1500ms) == 2s ); +static_assert( std::chrono::round(1999ms) == 2s ); +static_assert( std::chrono::round(2000ms) == 2s ); +static_assert( std::chrono::round(2001ms) == 2s ); +static_assert( std::chrono::round(2500ms) == 2s ); +static_assert( std::chrono::round(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 00000000000..bf596e92fc1 --- /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 +// . + +// { dg-do run { target c++11 } } + +// { dg-options "-std=gnu++17" } +// { dg-do compile } + +#include + +#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(base + 1000ms) == (base + 1s) ); +static_assert( std::chrono::floor(base + 1001ms) == (base + 1s) ); +static_assert( std::chrono::floor(base + 1500ms) == (base + 1s) ); +static_assert( std::chrono::floor(base + 1999ms) == (base + 1s) ); +static_assert( std::chrono::floor(base + 2000ms) == (base + 2s) ); +static_assert( std::chrono::floor(base + 2001ms) == (base + 2s) ); +static_assert( std::chrono::floor(base + 2500ms) == (base + 2s) ); + +static_assert( std::chrono::ceil(base + 1000ms) == (base + 1s) ); +static_assert( std::chrono::ceil(base + 1001ms) == (base + 2s) ); +static_assert( std::chrono::ceil(base + 1500ms) == (base + 2s) ); +static_assert( std::chrono::ceil(base + 1999ms) == (base + 2s) ); +static_assert( std::chrono::ceil(base + 2000ms) == (base + 2s) ); +static_assert( std::chrono::ceil(base + 2001ms) == (base + 3s) ); +static_assert( std::chrono::ceil(base + 2500ms) == (base + 3s) ); + +static_assert( std::chrono::round(base + 1000ms) == (base + 1s) ); +static_assert( std::chrono::round(base + 1001ms) == (base + 1s) ); +static_assert( std::chrono::round(base + 1499ms) == (base + 1s) ); +static_assert( std::chrono::round(base + 1500ms) == (base + 2s) ); +static_assert( std::chrono::round(base + 1999ms) == (base + 2s) ); +static_assert( std::chrono::round(base + 2000ms) == (base + 2s) ); +static_assert( std::chrono::round(base + 2001ms) == (base + 2s) ); +static_assert( std::chrono::round(base + 2500ms) == (base + 2s) ); +static_assert( std::chrono::round(base + 2501ms) == (base + 3s) );