* 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.
commit ac54a375293a58fc9b42e7bd8e8b0518c5988bd2 Author: Jonathan Wakely <jwak...@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><chrono></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) );