diff options
author | redi <redi@138bc75d-0d04-0410-961f-82ee72b054a4> | 2016-08-05 13:52:59 +0000 |
---|---|---|
committer | redi <redi@138bc75d-0d04-0410-961f-82ee72b054a4> | 2016-08-05 13:52:59 +0000 |
commit | bbc6c232520c00b5d8e7a830334cdac2fb3dc74f (patch) | |
tree | f6ce94aae8f245f477ba0df6a4ea83fe617ead9b | |
parent | 80ece1dc65adec22f264acb7342ecfb6c1bee223 (diff) | |
download | gcc-bbc6c232520c00b5d8e7a830334cdac2fb3dc74f.tar.gz |
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.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@239170 138bc75d-0d04-0410-961f-82ee72b054a4
10 files changed, 225 insertions, 10 deletions
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 <jwakely@redhat.com> + * 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++</a>. <a class="link" href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0185r1.html" target="_top"> P0185R1 </a> - </td><td align="center"> 7 (<code class="code">__is_swappable</code> available since 6.1)</td><td align="left"><code class="code"> __cpp_lib_is_swappable >= 201603 </code></td></tr><tr bgcolor="#C8B0B0"><td align="left"> <code class="code">is_callable</code>, the missing INVOKE related trait</td><td align="left"> + </td><td align="center"> 7 (<code class="code">__is_swappable</code> available since 6.1)</td><td align="left"><code class="code"> __cpp_lib_is_swappable >= 201603 </code></td></tr><tr><td align="left"> <code class="code">is_callable</code>, the missing INVOKE related trait</td><td align="left"> <a class="link" href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0077r2.html" target="_top"> P0077R2 </a> - </td><td align="center"> No </td><td align="left"><code class="code"> __cpp_lib_is_callable >= 201603 </code></td></tr><tr bgcolor="#C8B0B0"><td align="left"> has_unique_object_representations </td><td align="left"> + </td><td align="center"> 7 </td><td align="left"><code class="code"> __cpp_lib_is_callable >= 201603 </code></td></tr><tr bgcolor="#C8B0B0"><td align="left"> has_unique_object_representations </td><td align="left"> <a class="link" href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0258r2.html" target="_top"> P0258R2 </a> @@ -618,11 +618,11 @@ Feature-testing recommendations for C++</a>. <a class="link" href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0181r1.html" target="_top"> P0181R1 </a> - </td><td align="center"> No </td><td align="left"><code class="code"> __cpp_lib_default_order >= 201606</code></td></tr><tr bgcolor="#C8B0B0"><td align="left"> Polishing <code class="code"><chrono></code> </td><td align="left"> + </td><td align="center"> No </td><td align="left"><code class="code"> __cpp_lib_default_order >= 201606</code></td></tr><tr><td align="left"> Polishing <code class="code"><chrono></code> </td><td align="left"> <a class="link" href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0092r1.html" target="_top"> P0092R1 </a> - </td><td align="center"> No </td><td align="left"><code class="code"> __cpp_lib_chrono >= 201510 </code></td></tr><tr><td align="left"> Integrating <code class="code">std::string_view</code> and <code class="code">std::string</code> </td><td align="left"> + </td><td align="center"> 7 </td><td align="left"><code class="code"> __cpp_lib_chrono >= 201510 </code></td></tr><tr><td align="left"> Integrating <code class="code">std::string_view</code> and <code class="code">std::string</code> </td><td align="left"> <a class="link" href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0254r2.pdf" target="_top"> P0254R2 </a> 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++</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 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 <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 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<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 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 +// <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 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 +// <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) ); |