This patch replaces some reference members with pointers, so that the types containing them become trivial and are more efficient to pass as function arguments and can use the small object optimization when stored in a std::function, so that promise::set_value() doesn't need to allocate any memory.
_Task_setter is also changed to store a pointer to the task, instead of using a std::function to hold it. Tested x86_64-linux, committed to trunk.
commit 09c2fd279f76b886efa8bdb0b9b2dcb0956ab7f5 Author: Jonathan Wakely <jwak...@redhat.com> Date: Sat May 17 14:09:40 2014 +0100 * include/std/future (_State_baseV2::_M_set_result): Pass pointers to _M_do_set. (_State_baseV2::_M_do_set): Change parameters to pointers. (_State_baseV2::_Setter): Change _M_arg from reference to pointer. (_State_baseV2::__setter): Initialize _Setter with pointers. (_State_baseV2::__setter(promise<void>*)): Remove overload. (promise::set_value, promise::set_exception): Pass setter directly to _M_set_result. (_State_baseV2::_Task_setter): Add template parameter for callable type and replace std::function member with pointer to that type. Change _M_result member from reference to pointer. (_State_baseV2::_S_task_setter): Change parameter to lvalue reference and initialize _Task_setter with pointers. (__location_invariant): Specialize for _Setter and _Task_setter. diff --git a/libstdc++-v3/include/std/future b/libstdc++-v3/include/std/future index be2ed96..c3aaaec 100644 --- a/libstdc++-v3/include/std/future +++ b/libstdc++-v3/include/std/future @@ -358,7 +358,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // all calls to this function are serialized, // side-effects of invoking __res only happen once call_once(_M_once, &_State_baseV2::_M_do_set, this, - ref(__res), ref(__lock)); + std::__addressof(__res), std::__addressof(__lock)); if (__lock.owns_lock()) _M_cond.notify_all(); else if (!__ignore_failure) @@ -396,19 +396,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION struct _Setter<_Res, _Arg&> { // check this is only used by promise<R>::set_value(const R&) - // or promise<R>::set_value(R&) + // or promise<R&>::set_value(R&) static_assert(is_same<_Res, _Arg&>::value // promise<R&> - || is_same<const _Res, _Arg>::value, // promise<R> + || is_same<const _Res, _Arg>::value, // promise<R> "Invalid specialisation"); typename promise<_Res>::_Ptr_type operator()() { _State_baseV2::_S_check(_M_promise->_M_future); - _M_promise->_M_storage->_M_set(_M_arg); + _M_promise->_M_storage->_M_set(*_M_arg); return std::move(_M_promise->_M_storage); } promise<_Res>* _M_promise; - _Arg& _M_arg; + _Arg* _M_arg; }; // set rvalues @@ -418,11 +418,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION typename promise<_Res>::_Ptr_type operator()() { _State_baseV2::_S_check(_M_promise->_M_future); - _M_promise->_M_storage->_M_set(std::move(_M_arg)); + _M_promise->_M_storage->_M_set(std::move(*_M_arg)); return std::move(_M_promise->_M_storage); } promise<_Res>* _M_promise; - _Res& _M_arg; + _Res* _M_arg; }; struct __exception_ptr_tag { }; @@ -434,31 +434,28 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION typename promise<_Res>::_Ptr_type operator()() { _State_baseV2::_S_check(_M_promise->_M_future); - _M_promise->_M_storage->_M_error = _M_ex; + _M_promise->_M_storage->_M_error = *_M_ex; return std::move(_M_promise->_M_storage); } promise<_Res>* _M_promise; - exception_ptr& _M_ex; + exception_ptr* _M_ex; }; template<typename _Res, typename _Arg> static _Setter<_Res, _Arg&&> __setter(promise<_Res>* __prom, _Arg&& __arg) { - return _Setter<_Res, _Arg&&>{ __prom, __arg }; + return _Setter<_Res, _Arg&&>{ __prom, &__arg }; } template<typename _Res> static _Setter<_Res, __exception_ptr_tag> __setter(exception_ptr& __ex, promise<_Res>* __prom) { - return _Setter<_Res, __exception_ptr_tag>{ __prom, __ex }; + return _Setter<_Res, __exception_ptr_tag>{ __prom, &__ex }; } - static _Setter<void, void> - __setter(promise<void>* __prom); - template<typename _Tp> static void _S_check(const shared_ptr<_Tp>& __p) @@ -469,10 +466,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION private: void - _M_do_set(function<_Ptr_type()>& __f, unique_lock<mutex>& __lock) + _M_do_set(function<_Ptr_type()>* __f, unique_lock<mutex>* __lock) { - _Ptr_type __res = __f(); // do not hold lock while running setter - __lock.lock(); + _Ptr_type __res = (*__f)(); // do not hold lock while running setter + __lock->lock(); _M_result.swap(__res); } @@ -514,15 +511,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION static std::shared_ptr<_State_base> _S_make_async_state(_BoundFn&& __fn); - template<typename _Res_ptr, + template<typename _Res_ptr, typename _Fn, typename _Res = typename _Res_ptr::element_type::result_type> struct _Task_setter; template<typename _Res_ptr, typename _BoundFn> - static _Task_setter<_Res_ptr> - _S_task_setter(_Res_ptr& __ptr, _BoundFn&& __call) + static _Task_setter<_Res_ptr, _BoundFn> + _S_task_setter(_Res_ptr& __ptr, _BoundFn& __call) { - return _Task_setter<_Res_ptr>{ __ptr, std::ref(__call) }; + return { std::__addressof(__ptr), std::__addressof(__call) }; } }; @@ -554,6 +551,18 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION void _M_destroy() { delete this; } }; + // Allow _Setter objects to be stored locally in std::function + template<typename _Res, typename _Arg> + struct __is_location_invariant + <__future_base::_State_base::_Setter<_Res, _Arg>> + : true_type { }; + + // Allow _Task_setter objects to be stored locally in std::function + template<typename _Res_ptr, typename _Fn, typename _Res> + struct __is_location_invariant + <__future_base::_Task_setter<_Res_ptr, _Fn, _Res>> + : true_type { }; + #ifndef _GLIBCXX_ASYNC_ABI_COMPAT /// Common implementation for future and shared_future. @@ -994,24 +1003,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // Setting the result void set_value(const _Res& __r) - { - auto __setter = _State::__setter(this, __r); - _M_future->_M_set_result(std::move(__setter)); - } + { _M_future->_M_set_result(_State::__setter(this, __r)); } void set_value(_Res&& __r) - { - auto __setter = _State::__setter(this, std::move(__r)); - _M_future->_M_set_result(std::move(__setter)); - } + { _M_future->_M_set_result(_State::__setter(this, std::move(__r))); } void set_exception(exception_ptr __p) - { - auto __setter = _State::__setter(__p, this); - _M_future->_M_set_result(std::move(__setter)); - } + { _M_future->_M_set_result(_State::__setter(__p, this)); } }; template<typename _Res> @@ -1092,17 +1092,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // Setting the result void set_value(_Res& __r) - { - auto __setter = _State::__setter(this, __r); - _M_future->_M_set_result(std::move(__setter)); - } + { _M_future->_M_set_result(_State::__setter(this, __r)); } void set_exception(exception_ptr __p) - { - auto __setter = _State::__setter(__p, this); - _M_future->_M_set_result(std::move(__setter)); - } + { _M_future->_M_set_result(_State::__setter(__p, this)); } }; /// Explicit specialization for promise<void> @@ -1177,10 +1171,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION void set_exception(exception_ptr __p) - { - auto __setter = _State::__setter(__p, this); - _M_future->_M_set_result(std::move(__setter)); - } + { _M_future->_M_set_result(_State::__setter(__p, this)); } }; // set void @@ -1196,28 +1187,18 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION promise<void>* _M_promise; }; - inline __future_base::_State_base::_Setter<void, void> - __future_base::_State_base::__setter(promise<void>* __prom) - { - return _Setter<void, void>{ __prom }; - } - inline void promise<void>::set_value() - { - auto __setter = _State::__setter(this); - _M_future->_M_set_result(std::move(__setter)); - } - + { _M_future->_M_set_result(_State::_Setter<void, void>{ this }); } - template<typename _Ptr_type, typename _Res> + template<typename _Ptr_type, typename _Fn, typename _Res> struct __future_base::_Task_setter { _Ptr_type operator()() { __try { - _M_result->_M_set(_M_fn()); + (*_M_result)->_M_set((*_M_fn)()); } __catch(const __cxxabiv1::__forced_unwind&) { @@ -1225,22 +1206,22 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } __catch(...) { - _M_result->_M_error = current_exception(); + (*_M_result)->_M_error = current_exception(); } - return std::move(_M_result); + return std::move(*_M_result); } - _Ptr_type& _M_result; - std::function<_Res()> _M_fn; + _Ptr_type* _M_result; + _Fn* _M_fn; }; - template<typename _Ptr_type> - struct __future_base::_Task_setter<_Ptr_type, void> + template<typename _Ptr_type, typename _Fn> + struct __future_base::_Task_setter<_Ptr_type, _Fn, void> { _Ptr_type operator()() { __try { - _M_fn(); + (*_M_fn)(); } __catch(const __cxxabiv1::__forced_unwind&) { @@ -1248,12 +1229,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } __catch(...) { - _M_result->_M_error = current_exception(); + (*_M_result)->_M_error = current_exception(); } - return std::move(_M_result); + return std::move(*_M_result); } - _Ptr_type& _M_result; - std::function<void()> _M_fn; + _Ptr_type* _M_result; + _Fn* _M_fn; }; template<typename _Res, typename... _Args> @@ -1294,8 +1275,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // bound arguments decay so wrap lvalue references auto __boundfn = std::__bind_simple(std::ref(_M_impl._M_fn), _S_maybe_wrap_ref(std::forward<_Args>(__args))...); - auto __setter = _S_task_setter(this->_M_result, std::move(__boundfn)); - this->_M_set_result(std::move(__setter)); + this->_M_set_result(_S_task_setter(this->_M_result, __boundfn)); } virtual shared_ptr<_Task_state_base<_Res(_Args...)>>