mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2024-11-23 13:50:11 +00:00
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
This commit is contained in:
parent
b8f65e25d8
commit
ec0810e1c8
@ -440,7 +440,7 @@ __invoke(_R (*__f)(_Param...), _Args&& ...__args)
|
||||
|
||||
template <class _F, class ..._T>
|
||||
inline _LIBCPP_INLINE_VISIBILITY
|
||||
typename result_of<_F(_T...)>::type
|
||||
typename __invoke_of<_F, _T...>::type
|
||||
__invoke(_F&& __f, _T&& ...__t)
|
||||
{
|
||||
return _STD::forward<_F>(__f)(_STD::forward<_T>(__t)...);
|
||||
@ -476,7 +476,7 @@ public:
|
||||
// invoke
|
||||
template <class... _ArgTypes>
|
||||
_LIBCPP_INLINE_VISIBILITY
|
||||
typename __invoke_return<type&, _ArgTypes...>::type
|
||||
typename __invoke_of<type&, _ArgTypes...>::type
|
||||
operator() (_ArgTypes&&... __args) const
|
||||
{
|
||||
return __invoke(get(), _STD::forward<_ArgTypes>(__args)...);
|
||||
|
@ -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),
|
||||
|
@ -485,7 +485,7 @@ private:
|
||||
_LIBCPP_INLINE_VISIBILITY
|
||||
void __execute(__tuple_indices<_Indices...>)
|
||||
{
|
||||
_STD::move(_STD::get<0>(__f_))(_STD::move(_STD::get<_Indices>(__f_))...);
|
||||
__invoke(_STD::move(_STD::get<0>(__f_)), _STD::move(_STD::get<_Indices>(__f_))...);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -325,7 +325,7 @@ inline _LIBCPP_INLINE_VISIBILITY
|
||||
void
|
||||
__threaad_execute(tuple<_F, _Args...>& __t, __tuple_indices<_Indices...>)
|
||||
{
|
||||
_STD::move(_STD::get<0>(__t))(_STD::move(_STD::get<_Indices>(__t))...);
|
||||
__invoke(_STD::move(_STD::get<0>(__t)), _STD::move(_STD::get<_Indices>(__t))...);
|
||||
}
|
||||
|
||||
template <class _F>
|
||||
|
@ -2772,7 +2772,132 @@ template <class _Tp> struct _LIBCPP_VISIBLE is_trivial
|
||||
is_trivially_default_constructible<_Tp>::value>
|
||||
#endif
|
||||
{};
|
||||
|
||||
|
||||
#ifndef _LIBCPP_HAS_NO_VARIADICS
|
||||
|
||||
// __invokable
|
||||
|
||||
template <unsigned, class _F, class ..._Args>
|
||||
struct __invokable_imp
|
||||
: false_type
|
||||
{
|
||||
};
|
||||
|
||||
// __invokable member function pointer
|
||||
|
||||
template <class _A0, class _F, class ..._Args>
|
||||
auto
|
||||
__invokable_mfp_test(_A0&& __a0, _F __f, _Args&& ...__args)
|
||||
-> decltype((_STD::forward<_A0>(__a0).*__f)(_STD::forward<_Args>(__args)...));
|
||||
|
||||
template <class _A0, class _F, class ..._Args>
|
||||
auto
|
||||
__invokable_mfp_test(_A0&& __a0, _F __f, _Args&& ...__args)
|
||||
-> decltype(((*_STD::forward<_A0>(__a0)).*__f)(_STD::forward<_Args>(__args)...));
|
||||
|
||||
template <class _F, class ..._Args>
|
||||
auto
|
||||
__invokable_mfp_test(__any, _F __f, _Args&& ...__args)
|
||||
-> __nat;
|
||||
|
||||
template <class _F, class _A0, class ..._Args>
|
||||
struct __invokable_imp<2, _F, _A0, _Args...>
|
||||
{
|
||||
typedef decltype(
|
||||
__invokable_mfp_test(_STD::declval<_A0>(), _STD::declval<_F>(),
|
||||
_STD::declval<_Args>()...)
|
||||
) type;
|
||||
static const bool value = !is_same<type, __nat>::value;
|
||||
};
|
||||
|
||||
// __invokable member object pointer
|
||||
|
||||
template <class _A0, class _F>
|
||||
auto
|
||||
__invokable_mop_test(_A0&& __a0, _F __f)
|
||||
-> decltype(_STD::forward<_A0>(__a0).*__f);
|
||||
|
||||
template <class _A0, class _F>
|
||||
auto
|
||||
__invokable_mop_test(_A0&& __a0, _F __f)
|
||||
-> decltype((*_STD::forward<_A0>(__a0)).*__f);
|
||||
|
||||
template <class _F>
|
||||
auto
|
||||
__invokable_mop_test(__any, _F __f)
|
||||
-> __nat;
|
||||
|
||||
template <class _F, class _A0>
|
||||
struct __invokable_imp<1, _F, _A0>
|
||||
{
|
||||
typedef decltype(
|
||||
__invokable_mop_test(_STD::declval<_A0>(), _STD::declval<_F>())
|
||||
) type;
|
||||
static const bool value = !is_same<type, __nat>::value;
|
||||
};
|
||||
|
||||
// __invokable other
|
||||
|
||||
template <class _F, class ..._Args>
|
||||
auto
|
||||
__invokable_other_test(_F&& __f, _Args&& ...__args)
|
||||
-> decltype(_STD::forward<_F>(__f)(_STD::forward<_Args>(__args)...));
|
||||
|
||||
template <class ..._Args>
|
||||
auto
|
||||
__invokable_other_test(__any, _Args&& ...__args)
|
||||
-> __nat;
|
||||
|
||||
template <class _F, class ..._Args>
|
||||
struct __invokable_imp<0, _F, _Args...>
|
||||
{
|
||||
typedef decltype(
|
||||
__invokable_other_test(_STD::declval<_F>(), _STD::declval<_Args>()...)
|
||||
) type;
|
||||
static const bool value = !is_same<type, __nat>::value;
|
||||
};
|
||||
|
||||
// __invokable_classify
|
||||
|
||||
template <class _F>
|
||||
struct __invokable_classify
|
||||
{
|
||||
typedef typename remove_reference<_F>::type _FR;
|
||||
static const unsigned value = is_member_function_pointer<_FR>::value ?
|
||||
2 :
|
||||
is_member_object_pointer<_FR>::value ?
|
||||
1 :
|
||||
0;
|
||||
};
|
||||
|
||||
template <class _F, class ..._Args>
|
||||
struct __invokable
|
||||
: public integral_constant<bool,
|
||||
__invokable_imp<__invokable_classify<_F>::value, _F, _Args...>::value>
|
||||
{
|
||||
};
|
||||
|
||||
// __invoke_of
|
||||
|
||||
template <bool _Invokable, class _F, class ..._Args>
|
||||
struct __invoke_of_imp // false
|
||||
{
|
||||
};
|
||||
|
||||
template <class _F, class ..._Args>
|
||||
struct __invoke_of_imp<true, _F, _Args...>
|
||||
{
|
||||
typedef typename __invokable_imp<__invokable_classify<_F>::value, _F, _Args...>::type type;
|
||||
};
|
||||
|
||||
template <class _F, class ..._Args>
|
||||
struct __invoke_of
|
||||
: public __invoke_of_imp<__invokable<_F, _Args...>::value, _F, _Args...>
|
||||
{
|
||||
};
|
||||
|
||||
#endif // _LIBCPP_HAS_NO_VARIADICS
|
||||
|
||||
template <class _Tp>
|
||||
inline _LIBCPP_INLINE_VISIBILITY
|
||||
void
|
||||
|
Loading…
Reference in New Issue
Block a user