X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=common%2Ffuture.h;h=65bea20b56b42e347a2fe89a841fa2b7d4adb5f1;hb=cc2e93138f0dd58a750b974c3cb7f548d1b26661;hp=17ff97782e0e5b9fffd0e8f75a10f7d02a528340;hpb=44dede2da63c289838cab72f9f19f831bc2e8d1d;p=casparcg diff --git a/common/future.h b/common/future.h index 17ff97782..65bea20b5 100644 --- a/common/future.h +++ b/common/future.h @@ -1,187 +1,57 @@ -#pragma once - -#include "enum_class.h" - -#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); - } - - 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 = boost::static_pointer_cast(boost::make_shared>(std::forward(f))); - else if((policy & launch::deferred) != 0) - future_object = boost::static_pointer_cast(boost::make_shared>(std::forward(f))); - 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 shared_f = make_shared(std::move(f)); - return async(launch::deferred, [=]() mutable - { - return shared_f.get().get(); - }); -} - +#pragma once + +#include +#include +#include + +#include +#include + +namespace caspar { + +template +auto flatten(std::future&& f) -> std::future::type> +{ + auto shared_f = f.share(); + return std::async(std::launch::deferred, [=]() mutable -> typename std::decay::type + { + return shared_f.get().get(); + }); +} + +template +bool is_ready(const F& future) +{ + return future.wait_for(std::chrono::seconds(0)) == std::future_status::ready; +} + +/** + * Wrap a value in a future with an already known result. + *

+ * Useful when the result of an operation is already known at the time of + * calling. + * + * @param value The r-value to wrap. + * + * @return The future with the result set. + */ +template +std::future make_ready_future(R&& value) +{ + 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