X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=common%2Ffuture.h;h=65bea20b56b42e347a2fe89a841fa2b7d4adb5f1;hb=f529ebe9cc9c0a58a6ba4a1ebcd377b4dabf830a;hp=1a07026b3785afb0eb9602ba4c7feb7ea7bb9d2e;hpb=479d8b9aba0c4fdebf23171736dd2b098043b9e6;p=casparcg diff --git a/common/future.h b/common/future.h index 1a07026b3..65bea20b5 100644 --- a/common/future.h +++ b/common/future.h @@ -1,312 +1,29 @@ #pragma once -#include "enum_class.h" - -#include -#include -#include +#include +#include +#include #include +#include namespace caspar { - -struct launch_policy_def -{ - enum type - { - async = 1, - deferred = 2 - }; -}; -typedef caspar::enum_class launch; - -namespace detail { - -template -struct future_object_helper -{ - template - static void nonlocking_invoke(T& future_object, F& f) - { - try - { - future_object.mark_finished_with_result_internal(f()); - } - catch(...) - { - future_object.mark_exceptional_finish_internal(boost::current_exception()); - } - } - - template - static void locking_invoke(T& future_object, F& f) - { - try - { - future_object.mark_finished_with_result(f()); - } - catch(...) - { - future_object.mark_exceptional_finish(); - } - } -}; - -template<> -struct future_object_helper -{ - template - static void nonlocking_invoke(T& future_object, F& f) - { - try - { - f(); - future_object.mark_finished_with_result_internal(); - } - catch(...) - { - future_object.mark_exceptional_finish_internal(boost::current_exception()); - } - } - - template - static void locking_invoke(T& future_object, F& f) - { - try - { - f(); - future_object.mark_finished_with_result(); - } - catch(...) - { - future_object.mark_exceptional_finish(); - } - } -}; - -template -struct deferred_future_object : public boost::detail::future_object -{ - F f; - bool done; - - template - deferred_future_object(F2&& f) - : f(std::forward(f)) - , done(false) - { - set_wait_callback(std::mem_fn(&detail::deferred_future_object::operator()), this); - } - - ~deferred_future_object() - { - } - - void operator()() - { - boost::lock_guard lock2(mutex); - - if(done) - return; - - future_object_helper::nonlocking_invoke(*this, f); - - done = true; - } -}; - -template -struct async_future_object : public boost::detail::future_object -{ - F f; - boost::thread thread; - - template - async_future_object(F2&& f) - : f(std::forward(f)) - , thread([this]{run();}) - { - } - - ~async_future_object() - { - thread.join(); - } - - void run() - { - future_object_helper::locking_invoke(*this, f); - } -}; - -} - -template -auto async(launch policy, F&& f) -> boost::unique_future -{ - typedef decltype(f()) result_type; - typedef boost::detail::future_object future_object_type; - - boost::shared_ptr future_object; - - // HACK: This solution is a hack to avoid modifying boost code. - - if((policy & launch::async) != 0) - future_object.reset(new detail::async_future_object(std::forward(f)), [](future_object_type* p){delete reinterpret_cast*>(p);}); - else if((policy & launch::deferred) != 0) - future_object.reset(new detail::deferred_future_object(std::forward(f)), [](future_object_type* p){delete reinterpret_cast*>(p);}); - else - throw std::invalid_argument("policy"); - - boost::unique_future future; - - static_assert(sizeof(future) == sizeof(future_object), ""); - - reinterpret_cast&>(future) = std::move(future_object); // Get around the "private" encapsulation. - return std::move(future); -} - -template -auto async(F&& f) -> boost::unique_future -{ - return async(launch::async | launch::deferred, std::forward(f)); -} template -auto make_shared(boost::unique_future&& f) -> boost::shared_future -{ - return boost::shared_future(std::move(f)); -} - -template -auto flatten(boost::unique_future&& f) -> boost::unique_future +auto flatten(std::future&& f) -> std::future::type> { - auto shared_f = make_shared(std::move(f)); - return async(launch::deferred, [=]() mutable + auto shared_f = f.share(); + return std::async(std::launch::deferred, [=]() mutable -> typename std::decay::type { return shared_f.get().get(); }); } -/** - * A utility that helps the producer side of a future when the task is not - * able to complete immediately but there are known retry points in the code. - */ -template -class retry_task +template +bool is_ready(const F& future) { -public: - typedef boost::function ()> func_type; - - retry_task() : done_(false) {} - - /** - * Reset the state with a new task. If the previous task has not completed - * the old one will be discarded. - * - * @param func The function that tries to calculate future result. If the - * optional return value is set the future is marked as ready. - */ - void set_task(const func_type& func) - { - boost::mutex::scoped_lock lock(mutex_); - - func_ = func; - done_ = false; - promise_ = boost::promise(); - } - - /** - * Take ownership of the future for the current task. Cannot only be called - * once for each task. - * - * @return the future. - */ - boost::unique_future get_future() - { - boost::mutex::scoped_lock lock(mutex_); - - return promise_.get_future(); - } - - /** - * Call this when it is guaranteed or probable that the task will be able - * to complete. - * - * @return true if the task completed (the future will have a result). - */ - bool try_completion() - { - boost::mutex::scoped_lock lock(mutex_); - - return try_completion_internal(); - } - - /** - * Call this when it is certain that the result should be ready, and if not - * it should be regarded as an unrecoverable error (retrying again would - * be useless), so the future will be marked as failed. - * - * @param exception The exception to mark the future with *if* the task - * completion fails. - */ - template - void try_or_fail(const E& exception) - { - boost::mutex::scoped_lock lock(mutex_); - - if (!try_completion_internal()) - { - try - { - throw exception; - } - catch (...) - { - CASPAR_LOG_CURRENT_EXCEPTION(); - promise_.set_exception(boost::current_exception()); - done_ = true; - } - } - } -private: - bool try_completion_internal() - { - if (!func_) - return false; - - if (done_) - return true; - - boost::optional result; - - try - { - result = func_(); - } - catch (...) - { - CASPAR_LOG_CURRENT_EXCEPTION(); - promise_.set_exception(boost::current_exception()); - done_ = true; - - return true; - } - - if (result) - { - promise_.set_value(*result); - done_ = true; - } - - return done_; - } -private: - boost::mutex mutex_; - func_type func_; - boost::promise promise_; - bool done_; -}; + return future.wait_for(std::chrono::seconds(0)) == std::future_status::ready; +} /** * Wrap a value in a future with an already known result. @@ -319,13 +36,22 @@ private: * @return The future with the result set. */ template -boost::unique_future wrap_as_future(R&& value) +std::future make_ready_future(R&& value) { - boost::promise p; + std::promise p; p.set_value(value); return p.get_future(); } +static std::future make_ready_future() +{ + std::promise p; + + p.set_value(); + + return p.get_future(); +} + } \ No newline at end of file