diff --git a/include/boost/thread/future.hpp b/include/boost/thread/future.hpp index 62067f53..3315238c 100644 --- a/include/boost/thread/future.hpp +++ b/include/boost/thread/future.hpp @@ -3751,11 +3751,11 @@ namespace detail { return BOOST_THREAD_MAKE_RV_REF(p.get_future()); } -#if defined BOOST_THREAD_USES_MOVE +#if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined BOOST_THREAD_USES_MOVE inline BOOST_THREAD_FUTURE make_ready_future() { promise p; p.set_value(); - return BOOST_THREAD_MAKE_RV_REF(p.get_future()); + return p.get_future(); } #endif @@ -3765,6 +3765,43 @@ namespace detail { p.set_exception(ex); return BOOST_THREAD_MAKE_RV_REF(p.get_future()); } + namespace detail { + template + struct make_ready_future_workaround { + template + BOOST_THREAD_FUTURE operator()(BOOST_THREAD_FUTURE fut, BOOST_THREAD_FWD_REF(F) fct) { + return make_ready_future(fct(boost::move(fut))); + } + }; +#if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined BOOST_THREAD_USES_MOVE + template + struct make_ready_future_workaround { + template + BOOST_THREAD_FUTURE operator()(BOOST_THREAD_FUTURE fut, BOOST_THREAD_FWD_REF(F) fct) { + fct(boost::move(fut)); + return make_ready_future(); + } + }; +#endif + template + struct make_ready_shared_future_workaround { + template + BOOST_THREAD_FUTURE operator()(shared_future fut, BOOST_THREAD_FWD_REF(F) fct) { + return make_ready_future(fct(boost::move(fut))); + } + }; +#if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined BOOST_THREAD_USES_MOVE + template + struct make_ready_shared_future_workaround { + template + BOOST_THREAD_FUTURE operator()(shared_future fut, BOOST_THREAD_FWD_REF(F) fct) { + fct(boost::move(fut)); + return make_ready_future(); + } + }; +#endif + + } template BOOST_THREAD_FUTURE make_exceptional_future(exception_ptr ex) { @@ -4340,7 +4377,11 @@ namespace detail BOOST_THREAD_ASSERT_PRECONDITION(this->future_!=0, future_uninitialized()); boost::unique_lock lock(this->future_->mutex); - if (underlying_cast(policy) & int(launch::async)) { + if (this->is_ready(lock)) { + lock.unlock(); + return boost::detail::make_ready_future_workaround)>::type, R>()( + boost::move(*this), boost::forward(func)); + } else if (underlying_cast(policy) & int(launch::async)) { return BOOST_THREAD_MAKE_RV_REF((boost::detail::make_future_async_continuation_shared_state, future_type, F>( lock, boost::move(*this), boost::forward(func) ))); @@ -4363,9 +4404,15 @@ namespace detail BOOST_THREAD_ASSERT_PRECONDITION(this->future_!=0, future_uninitialized()); boost::unique_lock lock(this->future_->mutex); - return BOOST_THREAD_MAKE_RV_REF((boost::detail::make_future_executor_continuation_shared_state, future_type, F>(ex, + if (this->is_ready(lock)) { + lock.unlock(); + return boost::detail::make_ready_future_workaround)>::type, R>()( + boost::move(*this), boost::forward(func)); + } else { + return BOOST_THREAD_MAKE_RV_REF((boost::detail::make_future_executor_continuation_shared_state, future_type, F>(ex, lock, boost::move(*this), boost::forward(func) ))); + } } #endif template @@ -4376,7 +4423,11 @@ namespace detail BOOST_THREAD_ASSERT_PRECONDITION(this->future_!=0, future_uninitialized()); boost::unique_lock lock(this->future_->mutex); - if (underlying_cast(this->launch_policy(lock)) & int(launch::async)) { + if (this->is_ready(lock)) { + lock.unlock(); + return boost::detail::make_ready_future_workaround)>::type, R>()( + boost::move(*this), boost::forward(func)); + } else if (underlying_cast(this->launch_policy(lock)) & int(launch::async)) { return boost::detail::make_future_async_continuation_shared_state, future_type, F>( lock, boost::move(*this), boost::forward(func) ); @@ -4406,7 +4457,11 @@ namespace detail BOOST_THREAD_ASSERT_PRECONDITION(this->future_!=0, future_uninitialized()); boost::unique_lock lock(this->future_->mutex); - if (underlying_cast(policy) & int(launch::async)) { + if (this->is_ready(lock)) { + lock.unlock(); + return boost::detail::make_ready_future_workaround)>::type, R>()( + boost::move(*this), boost::forward(func)); + } else if (underlying_cast(policy) & int(launch::async)) { return BOOST_THREAD_MAKE_RV_REF((boost::detail::make_future_async_continuation_shared_state, future_type, F>( lock, boost::move(*this), boost::forward(func) ))); @@ -4430,9 +4485,15 @@ namespace detail BOOST_THREAD_ASSERT_PRECONDITION(this->future_!=0, future_uninitialized()); boost::unique_lock lock(this->future_->mutex); - return BOOST_THREAD_MAKE_RV_REF((boost::detail::make_future_executor_continuation_shared_state, future_type, F>(ex, + if (this->is_ready(lock)) { + lock.unlock(); + return boost::detail::make_ready_future_workaround)>::type, R>()( + boost::move(*this), boost::forward(func)); + } else { + return BOOST_THREAD_MAKE_RV_REF((boost::detail::make_future_executor_continuation_shared_state, future_type, F>(ex, lock, boost::move(*this), boost::forward(func) ))); + } } #endif template @@ -4444,7 +4505,11 @@ namespace detail BOOST_THREAD_ASSERT_PRECONDITION(this->future_!=0, future_uninitialized()); boost::unique_lock lock(this->future_->mutex); - if (underlying_cast(this->launch_policy(lock)) & int(launch::async)) { + if (this->is_ready(lock)) { + lock.unlock(); + return boost::detail::make_ready_future_workaround)>::type, R>()( + boost::move(*this), boost::forward(func)); + } else if (underlying_cast(this->launch_policy(lock)) & int(launch::async)) { return boost::detail::make_future_async_continuation_shared_state, future_type, F>( lock, boost::move(*this), boost::forward(func) ); @@ -4474,8 +4539,11 @@ namespace detail BOOST_THREAD_ASSERT_PRECONDITION(this->future_!=0, future_uninitialized()); boost::unique_lock lock(this->future_->mutex); - - if (underlying_cast(policy) & int(launch::async)) { + if (this->is_ready(lock)) { + lock.unlock(); + return boost::detail::make_ready_shared_future_workaround)>::type, R>()( + boost::move(*this), boost::forward(func)); + } else if (underlying_cast(policy) & int(launch::async)) { return BOOST_THREAD_MAKE_RV_REF((boost::detail::make_shared_future_async_continuation_shared_state, future_type, F>( lock, *this, boost::forward(func) ))); @@ -4499,9 +4567,15 @@ namespace detail BOOST_THREAD_ASSERT_PRECONDITION(this->future_!=0, future_uninitialized()); boost::unique_lock lock(this->future_->mutex); - return BOOST_THREAD_MAKE_RV_REF((boost::detail::make_shared_future_executor_continuation_shared_state, future_type, F>(ex, + if (this->is_ready(lock)) { + lock.unlock(); + return boost::detail::make_ready_shared_future_workaround)>::type, R>()( + boost::move(*this), boost::forward(func)); + } else { + return BOOST_THREAD_MAKE_RV_REF((boost::detail::make_shared_future_executor_continuation_shared_state, future_type, F>(ex, lock, *this, boost::forward(func) ))); + } } #endif @@ -4514,7 +4588,11 @@ namespace detail BOOST_THREAD_ASSERT_PRECONDITION(this->future_!=0, future_uninitialized()); boost::unique_lock lock(this->future_->mutex); - if (underlying_cast(this->launch_policy(lock)) & int(launch::async)) { + if (this->is_ready(lock)) { + lock.unlock(); + return boost::detail::make_ready_shared_future_workaround)>::type, R>()( + boost::move(*this), boost::forward(func)); + } else if (underlying_cast(this->launch_policy(lock)) & int(launch::async)) { return boost::detail::make_shared_future_async_continuation_shared_state, future_type, F>( lock, *this, boost::forward(func)); } else if (underlying_cast(this->launch_policy(lock)) & int(launch::deferred)) { @@ -4551,7 +4629,7 @@ namespace detail : value_(v) {} - T operator()(BOOST_THREAD_FUTURE fut) { + T operator()(BOOST_THREAD_FUTURE fut) const { return fut.get_or(value_); } @@ -4628,6 +4706,18 @@ namespace detail { BOOST_THREAD_ASSERT_PRECONDITION(this->future_!=0, future_uninitialized()); boost::unique_lock lock(this->future_->mutex); + if (this->is_ready(lock)) { + lock.unlock(); +#if ! defined BOOST_NO_CXX11_RVALUE_REFERENCES + return boost::move(this->get()); +#elif defined BOOST_THREAD_USES_MOVE + BOOST_THREAD_FUTURE res = this->get(); + return boost::move(res); +#else + BOOST_THREAD_FUTURE res = this->get(); + return boost::move(res); +#endif + } return boost::detail::make_future_unwrap_shared_state >, R2>(lock, boost::move(*this)); } #endif diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 1db248d0..68d439bc 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -295,7 +295,8 @@ rule thread-compile ( sources : reqs * : name ) [ thread-run test_9319.cpp ] #[ thread-run test_9711.cpp ] this test is invalid and should not work :( [ thread-run test_9856.cpp ] - [ thread-compile test_10963.cpp : : test_10963_c ] + [ thread-compile test_10963.cpp : : test_10963_c ] + [ thread-run test_10964.cpp ] ;