diff options
author | Howard Hinnant <hhinnant@apple.com> | 2011-05-19 15:05:04 +0000 |
---|---|---|
committer | Howard Hinnant <hhinnant@apple.com> | 2011-05-19 15:05:04 +0000 |
commit | ec0810e1c8e690ebbf571670820392d52fb23b75 (patch) | |
tree | d4646969f53e635646ead35706b54fad1aa256ca /libcxx/include/future | |
parent | b8f65e25d8e1a9e45bee589a9238cf6fe8363b88 (diff) | |
download | bcm5719-llvm-ec0810e1c8e690ebbf571670820392d52fb23b75.tar.gz bcm5719-llvm-ec0810e1c8e690ebbf571670820392d52fb23b75.zip |
I had a giant misunderstanding of what 'synchronizes with' meant in [futures.async]/p5. This invalidated the current design of async in <future>. This is a new design, based on my new understanding, which has been confirmed on the lwg mailing list. The summary is that ~future() (and ~shared_future()) will block when they are created from within async, and the thread hasn't finished yet. As part of this work I created two new type traits: __invokable<F, Args...>::value and __invoke_of<F, Args...>::type. These are what result_of<F(Args...)> wanted to be when it grew up, but never will be. __invoke_of is carefully crafted so that it can serve as its own enable_if (type doesn't exist if the signature isn't invokable). All of this work is C++11 only.
llvm-svn: 131639
Diffstat (limited to 'libcxx/include/future')
-rw-r--r-- | libcxx/include/future | 204 |
1 files changed, 186 insertions, 18 deletions
diff --git a/libcxx/include/future b/libcxx/include/future index c60d3accf37..471e1f2e6d4 100644 --- a/libcxx/include/future +++ b/libcxx/include/future @@ -858,6 +858,115 @@ __deferred_assoc_state<void, _F>::__execute() #endif // _LIBCPP_NO_EXCEPTIONS } +template <class _R, class _F> +class __async_assoc_state + : public __assoc_state<_R> +{ + typedef __assoc_state<_R> base; + + _F __func_; + + virtual void __on_zero_shared(); +public: +#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES + explicit __async_assoc_state(_F&& __f); +#endif + + virtual void __execute(); +}; + +#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES + +template <class _R, class _F> +inline _LIBCPP_INLINE_VISIBILITY +__async_assoc_state<_R, _F>::__async_assoc_state(_F&& __f) + : __func_(_STD::forward<_F>(__f)) +{ +} + +#endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES + +template <class _R, class _F> +void +__async_assoc_state<_R, _F>::__execute() +{ +#ifndef _LIBCPP_NO_EXCEPTIONS + try + { +#endif // _LIBCPP_NO_EXCEPTIONS + this->set_value(__func_()); +#ifndef _LIBCPP_NO_EXCEPTIONS + } + catch (...) + { + this->set_exception(current_exception()); + } +#endif // _LIBCPP_NO_EXCEPTIONS +} + +template <class _R, class _F> +void +__async_assoc_state<_R, _F>::__on_zero_shared() +{ + this->wait(); + base::__on_zero_shared(); +} + +template <class _F> +class __async_assoc_state<void, _F> + : public __assoc_sub_state +{ + typedef __assoc_sub_state base; + + _F __func_; + + virtual void __on_zero_shared(); +public: +#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES + explicit __async_assoc_state(_F&& __f); +#endif + + virtual void __execute(); +}; + +#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES + +template <class _F> +inline _LIBCPP_INLINE_VISIBILITY +__async_assoc_state<void, _F>::__async_assoc_state(_F&& __f) + : __func_(_STD::forward<_F>(__f)) +{ +} + +#endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES + +template <class _F> +void +__async_assoc_state<void, _F>::__execute() +{ +#ifndef _LIBCPP_NO_EXCEPTIONS + try + { +#endif // _LIBCPP_NO_EXCEPTIONS + __func_(); + this->set_value(); +#ifndef _LIBCPP_NO_EXCEPTIONS + } + catch (...) + { + this->set_exception(current_exception()); + } +#endif // _LIBCPP_NO_EXCEPTIONS +} + +template <class _F> +void +__async_assoc_state<void, _F>::__on_zero_shared() +{ + this->wait(); + base::__on_zero_shared(); +} + template <class> class promise; template <class> class shared_future; template <class> class atomic_future; @@ -874,6 +983,14 @@ __make_deferred_assoc_state(_F&& __f); __make_deferred_assoc_state(_F __f); #endif +template <class _R, class _F> +future<_R> +#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES +__make_async_assoc_state(_F&& __f); +#else +__make_async_assoc_state(_F __f); +#endif + template <class _R> class _LIBCPP_VISIBLE future { @@ -885,11 +1002,16 @@ class _LIBCPP_VISIBLE future template <class> friend class shared_future; template <class> friend class atomic_future; - template <class _R1, class _F> #ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES + template <class _R1, class _F> friend future<_R1> __make_deferred_assoc_state(_F&& __f); + template <class _R1, class _F> + friend future<_R1> __make_async_assoc_state(_F&& __f); #else + template <class _R1, class _F> friend future<_R1> __make_deferred_assoc_state(_F __f); + template <class _R1, class _F> + friend future<_R1> __make_async_assoc_state(_F __f); #endif public: @@ -983,11 +1105,16 @@ class _LIBCPP_VISIBLE future<_R&> template <class> friend class shared_future; template <class> friend class atomic_future; - template <class _R1, class _F> #ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES + template <class _R1, class _F> friend future<_R1> __make_deferred_assoc_state(_F&& __f); + template <class _R1, class _F> + friend future<_R1> __make_async_assoc_state(_F&& __f); #else + template <class _R1, class _F> friend future<_R1> __make_deferred_assoc_state(_F __f); + template <class _R1, class _F> + friend future<_R1> __make_async_assoc_state(_F __f); #endif public: @@ -1076,11 +1203,16 @@ class _LIBCPP_VISIBLE future<void> template <class> friend class shared_future; template <class> friend class atomic_future; - template <class _R1, class _F> #ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES + template <class _R1, class _F> friend future<_R1> __make_deferred_assoc_state(_F&& __f); + template <class _R1, class _F> + friend future<_R1> __make_async_assoc_state(_F&& __f); #else + template <class _R1, class _F> friend future<_R1> __make_deferred_assoc_state(_F __f); + template <class _R1, class _F> + friend future<_R1> __make_async_assoc_state(_F __f); #endif public: @@ -2034,32 +2166,68 @@ __make_deferred_assoc_state(_F __f) return future<_R>(__h.get()); } +template <class _R, class _F> +future<_R> +#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES +__make_async_assoc_state(_F&& __f) +#else +__make_async_assoc_state(_F __f) +#endif +{ + unique_ptr<__async_assoc_state<_R, _F>, __release_shared_count> + __h(new __async_assoc_state<_R, _F>(_STD::forward<_F>(__f))); + _STD::thread(&__async_assoc_state<_R, _F>::__execute, __h.get()).detach(); + return future<_R>(__h.get()); +} + template <class _F, class... _Args> -future<typename result_of<_F(_Args...)>::type> +class __async_func +{ + tuple<_F, _Args...> __f_; + +public: + typedef typename __invoke_of<_F, _Args...>::type _R; + + _LIBCPP_INLINE_VISIBILITY + explicit __async_func(_F&& __f, _Args&&... __args) + : __f_(_STD::move(__f), _STD::move(__args)...) {} + + _LIBCPP_INLINE_VISIBILITY + __async_func(__async_func&& __f) : __f_(_STD::move(__f.__f_)) {} + + _R operator()() + { + typedef typename __make_tuple_indices<1+sizeof...(_Args), 1>::type _Index; + return __execute(_Index()); + } +private: + template <size_t ..._Indices> + _R + __execute(__tuple_indices<_Indices...>) + { + return __invoke(_STD::move(_STD::get<0>(__f_)), _STD::move(_STD::get<_Indices>(__f_))...); + } +}; + +template <class _F, class... _Args> +future<typename __invoke_of<typename decay<_F>::type, typename decay<_Args>::type...>::type> async(launch __policy, _F&& __f, _Args&&... __args) { - typedef typename result_of<_F(_Args...)>::type _R; + typedef __async_func<typename decay<_F>::type, typename decay<_Args>::type...> _BF; + typedef typename _BF::_R _R; future<_R> __r; if (__policy & launch::async) - { - packaged_task<_R()> __pk(bind(_STD::forward<_F>(__f), - _STD::forward<_Args>(__args)...)); - __r = __pk.get_future(); - thread(_STD::move(__pk)).detach(); - } + __r = _STD::__make_async_assoc_state<_R>(_BF(__decay_copy(_STD::forward<_F>(__f)), + __decay_copy(_STD::forward<_Args>(__args))...)); else if (__policy & launch::deferred) - __r = _STD::__make_deferred_assoc_state<_R>(bind(_STD::forward<_F>(__f), - _STD::forward<_Args>(__args)...)); + __r = _STD::__make_deferred_assoc_state<_R>(_BF(__decay_copy(_STD::forward<_F>(__f)), + __decay_copy(_STD::forward<_Args>(__args))...)); return __r; } template <class _F, class... _Args> inline _LIBCPP_INLINE_VISIBILITY -typename enable_if -< - !is_same<typename decay<_F>::type, launch>::value, - future<typename result_of<_F(_Args...)>::type> ->::type +future<typename __invoke_of<typename decay<_F>::type, typename decay<_Args>::type...>::type> async(_F&& __f, _Args&&... __args) { return _STD::async(launch::any, _STD::forward<_F>(__f), |