diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index 10939d8f0dc..1b8e8aa3521 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,14 @@ +2010-10-08 Jonathan Wakely + + PR libstdc++/45893 + * include/std/functional (bind): Implement DR 817 and add support + for volatile-qualified call wrappers. + * include/std/mutex (call_once): Implement DR 891. + * include/std/thread (thread::thread): Implement DR 929. + * include/std/future: Optimise use of std::bind. + * testsuite/20_util/bind/cv_quals.cc: Test volatile-qualification. + * testsuite/20_util/bind/move.cc: New. + 2010-10-07 Hans-Peter Nilsson PR libstdc++/45841 diff --git a/libstdc++-v3/include/std/functional b/libstdc++-v3/include/std/functional index 2dae72dcf68..51054ac2da6 100644 --- a/libstdc++-v3/include/std/functional +++ b/libstdc++-v3/include/std/functional @@ -957,7 +957,7 @@ _GLIBCXX_HAS_NESTED_TYPE(result_type) */ template result_type - operator()(_CVRef& __arg, _Tuple&&) const volatile + operator()(_CVRef& __arg, _Tuple&) const volatile { return __arg.get(); } }; @@ -970,33 +970,26 @@ _GLIBCXX_HAS_NESTED_TYPE(result_type) class _Mu<_Arg, true, false> { public: - template class result; - - // Determine the result type when we pass the arguments along. This - // involves passing along the cv-qualifiers placed on _Mu and - // unwrapping the argument bundle. - template - class result<_CVMu(_CVArg, tuple<_Args...>)> - : public result_of<_CVArg(_Args...)> { }; - template - typename result_of<_CVArg(_Args...)>::type + auto operator()(_CVArg& __arg, - tuple<_Args...>&& __tuple) const volatile + tuple<_Args...>& __tuple) const volatile + -> decltype(__arg(declval<_Args>()...)) { // Construct an index tuple and forward to __call typedef typename _Build_index_tuple::__type _Indexes; - return this->__call(__arg, std::move(__tuple), _Indexes()); + return this->__call(__arg, __tuple, _Indexes()); } private: // Invokes the underlying function object __arg by unpacking all // of the arguments in the tuple. template - typename result_of<_CVArg(_Args...)>::type - __call(_CVArg& __arg, tuple<_Args...>&& __tuple, + auto + __call(_CVArg& __arg, tuple<_Args...>& __tuple, const _Index_tuple<_Indexes...>&) const volatile + -> decltype(__arg(declval<_Args>()...)) { return __arg(std::forward<_Args>(get<_Indexes>(__tuple))...); } @@ -1029,7 +1022,7 @@ _GLIBCXX_HAS_NESTED_TYPE(result_type) template typename result<_Mu(_Arg, _Tuple)>::type - operator()(const volatile _Arg&, _Tuple&& __tuple) const volatile + operator()(const volatile _Arg&, _Tuple& __tuple) const volatile { return std::forward::type>( ::std::get<(is_placeholder<_Arg>::value - 1)>(__tuple)); @@ -1056,7 +1049,7 @@ _GLIBCXX_HAS_NESTED_TYPE(result_type) // Pick up the cv-qualifiers of the argument template _CVArg&& - operator()(_CVArg&& __arg, _Tuple&&) const volatile + operator()(_CVArg&& __arg, _Tuple&) const volatile { return std::forward<_CVArg>(__arg); } }; @@ -1069,10 +1062,14 @@ _GLIBCXX_HAS_NESTED_TYPE(result_type) struct _Maybe_wrap_member_pointer { typedef _Tp type; - + static const _Tp& __do_wrap(const _Tp& __x) { return __x; } + + static _Tp&& + __do_wrap(_Tp&& __x) + { return static_cast<_Tp&&>(__x); } }; /** @@ -1100,6 +1097,20 @@ _GLIBCXX_HAS_NESTED_TYPE(result_type) typedef void type; }; + // std::get for volatile-qualified tuples + template + inline auto + __volget(volatile tuple<_Tp...>& __tuple) + -> typename tuple_element<_Ind, tuple<_Tp...>>::type volatile& + { return std::get<_Ind>(const_cast&>(__tuple)); } + + // std::get for const-volatile-qualified tuples + template + inline auto + __volget(const volatile tuple<_Tp...>& __tuple) + -> typename tuple_element<_Ind, tuple<_Tp...>>::type const volatile& + { return std::get<_Ind>(const_cast&>(__tuple)); } + /// Type of the function object returned from bind(). template struct _Bind; @@ -1109,7 +1120,7 @@ _GLIBCXX_HAS_NESTED_TYPE(result_type) : public _Weak_result_type<_Functor> { typedef _Bind __self_type; - typedef typename _Build_index_tuple::__type + typedef typename _Build_index_tuple::__type _Bound_indexes; _Functor _M_f; @@ -1121,7 +1132,7 @@ _GLIBCXX_HAS_NESTED_TYPE(result_type) __call(tuple<_Args...>&& __args, _Index_tuple<_Indexes...>) { return _M_f(_Mu<_Bound_args>() - (get<_Indexes>(_M_bound_args), std::move(__args))...); + (get<_Indexes>(_M_bound_args), __args)...); } // Call as const @@ -1130,10 +1141,9 @@ _GLIBCXX_HAS_NESTED_TYPE(result_type) __call_c(tuple<_Args...>&& __args, _Index_tuple<_Indexes...>) const { return _M_f(_Mu<_Bound_args>() - (get<_Indexes>(_M_bound_args), std::move(__args))...); + (get<_Indexes>(_M_bound_args), __args)...); } -#if 0 // Call as volatile template _Result @@ -1141,7 +1151,7 @@ _GLIBCXX_HAS_NESTED_TYPE(result_type) _Index_tuple<_Indexes...>) volatile { return _M_f(_Mu<_Bound_args>() - (get<_Indexes>(_M_bound_args), std::move(__args))...); + (__volget<_Indexes>(_M_bound_args), __args)...); } // Call as const volatile @@ -1151,69 +1161,77 @@ _GLIBCXX_HAS_NESTED_TYPE(result_type) _Index_tuple<_Indexes...>) const volatile { return _M_f(_Mu<_Bound_args>() - (get<_Indexes>(_M_bound_args), std::move(__args))...); + (__volget<_Indexes>(_M_bound_args), __args)...); } -#endif public: - explicit _Bind(_Functor __f, _Bound_args... __bound_args) - : _M_f(std::forward<_Functor>(__f)), - _M_bound_args(std::forward<_Bound_args>(__bound_args)...) + template + explicit _Bind(const _Functor& __f, _Args&&... __args) + : _M_f(__f), _M_bound_args(std::forward<_Args>(__args)...) + { } + + template + explicit _Bind(_Functor&& __f, _Args&&... __args) + : _M_f(std::move(__f)), _M_bound_args(std::forward<_Args>(__args)...) + { } + + _Bind(const _Bind&) = default; + + _Bind(_Bind&& __b) + : _M_f(std::move(__b._M_f)), _M_bound_args(std::move(__b._M_bound_args)) { } // Call unqualified template()( _Mu<_Bound_args>()( std::declval<_Bound_args&>(), - std::declval&&>() )... ) )> + std::declval&>() )... ) )> _Result operator()(_Args&&... __args) { - return this->__call<_Result>(tuple<_Args...> - (std::forward<_Args>(__args)...), - _Bound_indexes()); + return this->__call<_Result>( + std::forward_as_tuple(std::forward<_Args>(__args)...), + _Bound_indexes()); } // Call as const template()( _Mu<_Bound_args>()( std::declval(), - std::declval&&>() )... ) )> + std::declval&>() )... ) )> _Result operator()(_Args&&... __args) const { - return this->__call_c<_Result>(tuple<_Args...> - (std::forward<_Args>(__args)...), - _Bound_indexes()); + return this->__call_c<_Result>( + std::forward_as_tuple(std::forward<_Args>(__args)...), + _Bound_indexes()); } -#if 0 // Call as volatile template()( _Mu<_Bound_args>()( std::declval(), - std::declval&&>() )... ) )> + std::declval&>() )... ) )> _Result operator()(_Args&&... __args) volatile { - return this->__call_v<_Result>(tuple<_Args...> - (std::forward<_Args>(__args)...), - _Bound_indexes()); + return this->__call_v<_Result>( + std::forward_as_tuple(std::forward<_Args>(__args)...), + _Bound_indexes()); } // Call as const volatile template()( _Mu<_Bound_args>()( std::declval(), - std::declval&&>() )... ) )> + std::declval&>() )... ) )> _Result operator()(_Args&&... __args) const volatile { - return this->__call_c_v<_Result>(tuple<_Args...> - (std::forward<_Args>(__args)...), - _Bound_indexes()); + return this->__call_c_v<_Result>( + std::forward_as_tuple(std::forward<_Args>(__args)...), + _Bound_indexes()); } -#endif }; /// Type of the function object returned from bind(). @@ -1243,7 +1261,7 @@ _GLIBCXX_HAS_NESTED_TYPE(result_type) typename __disable_if_void<_Res>::type = 0) { return _M_f(_Mu<_Bound_args>() - (get<_Indexes>(_M_bound_args), std::move(__args))...); + (get<_Indexes>(_M_bound_args), __args)...); } // Call unqualified, return void @@ -1253,7 +1271,7 @@ _GLIBCXX_HAS_NESTED_TYPE(result_type) typename __enable_if_void<_Res>::type = 0) { _M_f(_Mu<_Bound_args>() - (get<_Indexes>(_M_bound_args), std::move(__args))...); + (get<_Indexes>(_M_bound_args), __args)...); } // Call as const @@ -1263,7 +1281,7 @@ _GLIBCXX_HAS_NESTED_TYPE(result_type) typename __disable_if_void<_Res>::type = 0) const { return _M_f(_Mu<_Bound_args>() - (get<_Indexes>(_M_bound_args), std::move(__args))...); + (get<_Indexes>(_M_bound_args), __args)...); } // Call as const, return void @@ -1273,7 +1291,7 @@ _GLIBCXX_HAS_NESTED_TYPE(result_type) typename __enable_if_void<_Res>::type = 0) const { _M_f(_Mu<_Bound_args>() - (get<_Indexes>(_M_bound_args), std::move(__args))...); + (get<_Indexes>(_M_bound_args), __args)...); } // Call as volatile @@ -1283,7 +1301,7 @@ _GLIBCXX_HAS_NESTED_TYPE(result_type) typename __disable_if_void<_Res>::type = 0) volatile { return _M_f(_Mu<_Bound_args>() - (get<_Indexes>(_M_bound_args), std::move(__args))...); + (__volget<_Indexes>(_M_bound_args), __args)...); } // Call as volatile, return void @@ -1293,7 +1311,7 @@ _GLIBCXX_HAS_NESTED_TYPE(result_type) typename __enable_if_void<_Res>::type = 0) volatile { _M_f(_Mu<_Bound_args>() - (get<_Indexes>(_M_bound_args), std::move(__args))...); + (__volget<_Indexes>(_M_bound_args), __args)...); } // Call as const volatile @@ -1303,7 +1321,7 @@ _GLIBCXX_HAS_NESTED_TYPE(result_type) typename __disable_if_void<_Res>::type = 0) const volatile { return _M_f(_Mu<_Bound_args>() - (get<_Indexes>(_M_bound_args), std::move(__args))...); + (__volget<_Indexes>(_M_bound_args), __args)...); } // Call as const volatile, return void @@ -1314,16 +1332,26 @@ _GLIBCXX_HAS_NESTED_TYPE(result_type) typename __enable_if_void<_Res>::type = 0) const volatile { _M_f(_Mu<_Bound_args>() - (get<_Indexes>(_M_bound_args), std::move(__args))...); + (__volget<_Indexes>(_M_bound_args), __args)...); } public: typedef _Result result_type; - explicit - _Bind_result(_Functor __f, _Bound_args... __bound_args) - : _M_f(std::forward<_Functor>(__f)), - _M_bound_args(std::forward<_Bound_args>(__bound_args)...) + template + explicit _Bind_result(const _Functor& __f, _Args&&... __args) + : _M_f(__f), _M_bound_args(std::forward<_Args>(__args)...) + { } + + template + explicit _Bind_result(_Functor&& __f, _Args&&... __args) + : _M_f(std::move(__f)), _M_bound_args(std::forward<_Args>(__args)...) + { } + + _Bind_result(const _Bind_result&) = default; + + _Bind_result(_Bind_result&& __b) + : _M_f(std::move(__b._M_f)), _M_bound_args(std::move(__b._M_bound_args)) { } // Call unqualified @@ -1332,7 +1360,7 @@ _GLIBCXX_HAS_NESTED_TYPE(result_type) operator()(_Args&&... __args) { return this->__call<_Result>( - tuple<_Args...>(std::forward<_Args>(__args)...), + std::forward_as_tuple(std::forward<_Args>(__args)...), _Bound_indexes()); } @@ -1342,7 +1370,7 @@ _GLIBCXX_HAS_NESTED_TYPE(result_type) operator()(_Args&&... __args) const { return this->__call<_Result>( - tuple<_Args...>(std::forward<_Args>(__args)...), + std::forward_as_tuple(std::forward<_Args>(__args)...), _Bound_indexes()); } @@ -1352,7 +1380,7 @@ _GLIBCXX_HAS_NESTED_TYPE(result_type) operator()(_Args&&... __args) volatile { return this->__call<_Result>( - tuple<_Args...>(std::forward<_Args>(__args)...), + std::forward_as_tuple(std::forward<_Args>(__args)...), _Bound_indexes()); } @@ -1362,7 +1390,7 @@ _GLIBCXX_HAS_NESTED_TYPE(result_type) operator()(_Args&&... __args) const volatile { return this->__call<_Result>( - tuple<_Args...>(std::forward<_Args>(__args)...), + std::forward_as_tuple(std::forward<_Args>(__args)...), _Bound_indexes()); } }; @@ -1383,38 +1411,55 @@ _GLIBCXX_HAS_NESTED_TYPE(result_type) struct is_bind_expression<_Bind_result<_Result, _Signature> > : public true_type { }; + template + struct _Bind_helper + { + typedef _Maybe_wrap_member_pointer::type> + __maybe_type; + typedef typename __maybe_type::type __functor_type; + typedef _Bind<__functor_type(typename decay<_ArgTypes>::type...)> type; + }; + /** * @brief Function template for std::bind. * @ingroup binders */ template inline - _Bind::type(_ArgTypes...)> - bind(_Functor __f, _ArgTypes... __args) + typename _Bind_helper<_Functor, _ArgTypes...>::type + bind(_Functor&& __f, _ArgTypes&&... __args) { - typedef _Maybe_wrap_member_pointer<_Functor> __maybe_type; - typedef typename __maybe_type::type __functor_type; - typedef _Bind<__functor_type(_ArgTypes...)> __result_type; - return __result_type(__maybe_type::__do_wrap(__f), + typedef _Bind_helper<_Functor, _ArgTypes...> __helper_type; + typedef typename __helper_type::__maybe_type __maybe_type; + typedef typename __helper_type::type __result_type; + return __result_type(__maybe_type::__do_wrap(std::forward<_Functor>(__f)), std::forward<_ArgTypes>(__args)...); } + template + struct _Bindres_helper + { + typedef _Maybe_wrap_member_pointer::type> + __maybe_type; + typedef typename __maybe_type::type __functor_type; + typedef _Bind_result<_Result, + __functor_type(typename decay<_ArgTypes>::type...)> + type; + }; + /** - * @brief Function template for std::bind. + * @brief Function template for std::bind. * @ingroup binders */ template inline - _Bind_result<_Result, - typename _Maybe_wrap_member_pointer<_Functor>::type - (_ArgTypes...)> - bind(_Functor __f, _ArgTypes... __args) + typename _Bindres_helper<_Result, _Functor, _ArgTypes...>::type + bind(_Functor&& __f, _ArgTypes&&... __args) { - typedef _Maybe_wrap_member_pointer<_Functor> __maybe_type; - typedef typename __maybe_type::type __functor_type; - typedef _Bind_result<_Result, __functor_type(_ArgTypes...)> - __result_type; - return __result_type(__maybe_type::__do_wrap(__f), + typedef _Bindres_helper<_Result, _Functor, _ArgTypes...> __helper_type; + typedef typename __helper_type::__maybe_type __maybe_type; + typedef typename __helper_type::type __result_type; + return __result_type(__maybe_type::__do_wrap(std::forward<_Functor>(__f)), std::forward<_ArgTypes>(__args)...); } diff --git a/libstdc++-v3/include/std/future b/libstdc++-v3/include/std/future index c97682dfff1..803c912294e 100644 --- a/libstdc++-v3/include/std/future +++ b/libstdc++-v3/include/std/future @@ -309,7 +309,7 @@ namespace std bool __set = __ignore_failure; // all calls to this function are serialized, // side-effects of invoking __res only happen once - call_once(_M_once, mem_fn(&_State::_M_do_set), this, ref(__res), + call_once(_M_once, &_State::_M_do_set, this, ref(__res), ref(__set)); if (!__set) __throw_future_error(int(future_errc::promise_already_satisfied)); @@ -1155,7 +1155,7 @@ namespace std _M_run(_Args... __args) { // bound arguments decay so wrap lvalue references - auto __bound = std::bind<_Res>(_M_task, + auto __bound = std::bind<_Res>(std::ref(_M_task), _S_maybe_wrap_ref(std::forward<_Args>(__args))...); _Task_setter<_Task_state> __setter{ this, std::move(__bound) }; _M_set_result(std::move(__setter)); diff --git a/libstdc++-v3/include/std/mutex b/libstdc++-v3/include/std/mutex index b236f0db91d..c11ddd44668 100644 --- a/libstdc++-v3/include/std/mutex +++ b/libstdc++-v3/include/std/mutex @@ -690,7 +690,7 @@ namespace std template friend void - call_once(once_flag& __once, _Callable __f, _Args&&... __args); + call_once(once_flag& __once, _Callable&& __f, _Args&&... __args); }; #ifdef _GLIBCXX_HAVE_TLS @@ -718,15 +718,17 @@ namespace std /// call_once template void - call_once(once_flag& __once, _Callable __f, _Args&&... __args) + call_once(once_flag& __once, _Callable&& __f, _Args&&... __args) { #ifdef _GLIBCXX_HAVE_TLS - auto __bound_functor = std::bind(__f, __args...); + auto __bound_functor = std::bind(std::forward<_Callable>(__f), + std::forward<_Args>(__args)...); __once_callable = &__bound_functor; __once_call = &__once_call_impl; #else unique_lock __functor_lock(__get_once_mutex()); - __once_functor = std::bind(__f, __args...); + __once_functor = std::bind(std::forward<_Callable>(__f), + std::forward<_Args>(__args)...); __set_once_functor_lock_ptr(&__functor_lock); #endif diff --git a/libstdc++-v3/include/std/thread b/libstdc++-v3/include/std/thread index d5bbf6e0146..4a3818e7278 100644 --- a/libstdc++-v3/include/std/thread +++ b/libstdc++-v3/include/std/thread @@ -126,16 +126,14 @@ namespace std thread(thread&& __t) { swap(__t); } - template - explicit thread(_Callable __f) - { - _M_start_thread(_M_make_routine<_Callable> - (std::forward<_Callable>(__f))); - } - template + explicit thread(_Callable&& __f, _Args&&... __args) - { _M_start_thread(_M_make_routine(std::bind(__f, __args...))); } + { + _M_start_thread(_M_make_routine(std::bind( + std::forward<_Callable>(__f), + std::forward<_Args>(__args)...))); + } ~thread() { diff --git a/libstdc++-v3/testsuite/20_util/bind/cv_quals.cc b/libstdc++-v3/testsuite/20_util/bind/cv_quals.cc index b42fe9a6159..d597a56fd95 100644 --- a/libstdc++-v3/testsuite/20_util/bind/cv_quals.cc +++ b/libstdc++-v3/testsuite/20_util/bind/cv_quals.cc @@ -22,14 +22,24 @@ #include #include +// target must be invoked with cv-quals of call wrapper + struct X { int operator()() { return 0; } int operator()() const { return 1; } - // int operator()() volatile { return 2; } - // int operator()() const volatile { return 3; } + int operator()() volatile { return 2; } + int operator()() const volatile { return 3; } + + int operator()(int, int, int) { return 0; } + int operator()(int, int, int) const { return 1; } + int operator()(int, int, int) volatile { return 2; } + int operator()(int, int, int) const volatile { return 3; } }; +using std::placeholders::_1; +using std::placeholders::_2; + void test01() { bool test __attribute__((unused)) = true; @@ -40,15 +50,70 @@ void test01() const auto b1 = std::bind(X()); VERIFY( b1() == 1 ); - // volatile auto b2 = std::bind(X()); - // VERIFY( b2() == 2 ); + volatile auto b2 = std::bind(X()); + VERIFY( b2() == 2 ); - // const volatile auto b3 = std::bind(X()); - // VERIFY( b3() == 3 ); + const volatile auto b3 = std::bind(X()); + VERIFY( b3() == 3 ); } +void test02() +{ + bool test __attribute__((unused)) = true; + + auto b0 = std::bind(X()); + VERIFY( b0() == 0 ); + + const auto b1 = std::bind(X()); + VERIFY( b1() == 1 ); + + volatile auto b2 = std::bind(X()); + VERIFY( b2() == 2 ); + + const volatile auto b3 = std::bind(X()); + VERIFY( b3() == 3 ); +} + +void test03() +{ + bool test __attribute__((unused)) = true; + + auto b0 = std::bind(X(), 0, _1, _2); + VERIFY( b0(0, 0) == 0 ); + + const auto b1 = std::bind(X(), _1, 0, _2); + VERIFY( b1(0, 0) == 1 ); + + volatile auto b2 = std::bind(X(), _1, _2, 0); + VERIFY( b2(0, 0) == 2 ); + + const volatile auto b3 = std::bind(X(), _1, 0, _2); + VERIFY( b3(0, 0) == 3 ); +} + +void test04() +{ + bool test __attribute__((unused)) = true; + + auto b0 = std::bind(X(), 0, _1, _2); + VERIFY( b0(0, 0) == 0 ); + + const auto b1 = std::bind(X(), _1, 0, _2); + VERIFY( b1(0, 0) == 1 ); + + volatile auto b2 = std::bind(X(), _1, _2, 0); + VERIFY( b2(0, 0) == 2 ); + + const volatile auto b3 = std::bind(X(), _1, 0, _2); + VERIFY( b3(0, 0) == 3 ); +} + + int main() { test01(); + test02(); + test03(); + test04(); return 0; } diff --git a/libstdc++-v3/testsuite/20_util/bind/move.cc b/libstdc++-v3/testsuite/20_util/bind/move.cc new file mode 100644 index 00000000000..d9485ad3156 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/bind/move.cc @@ -0,0 +1,58 @@ +// { dg-options "-std=gnu++0x" } + +// Copyright (C) 2010 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 +// . + +#include +#include + +// PR libstdc++/45924 + +struct f +{ + f() : i(0) { } + f(f&& r) : i(1) { r.i = -1; } + f(const f&) = delete; + int operator()() { return i; } + int i; +}; + +void test01() +{ + auto b = std::bind(f()); + VERIFY( b() == 1 ); + auto bc(std::move(b)); + VERIFY( bc() == 1 ); + VERIFY( b() == -1 ); +} + +void test02() +{ + auto b = std::bind(f()); + VERIFY( b() == 1 ); + auto bc(std::move(b)); + VERIFY( bc() == 1 ); + VERIFY( b() == -1 ); +} + +int main() +{ + test01(); + test02(); + return 0; +} +