3 #include "enum_class.h"
5 #include <boost/thread/future.hpp>
6 #include <boost/thread/thread.hpp>
7 #include <boost/shared_ptr.hpp>
13 struct launch_policy_def
21 typedef caspar::enum_class<launch_policy_def> launch;
26 struct future_object_helper
28 template<typename T, typename F>
29 static void nonlocking_invoke(T& future_object, F& f)
33 future_object.mark_finished_with_result_internal(f());
37 future_object.mark_exceptional_finish_internal(boost::current_exception());
41 template<typename T, typename F>
42 static void locking_invoke(T& future_object, F& f)
46 future_object.mark_finished_with_result(f());
50 future_object.mark_exceptional_finish();
56 struct future_object_helper<void>
58 template<typename T, typename F>
59 static void nonlocking_invoke(T& future_object, F& f)
64 future_object.mark_finished_with_result_internal();
68 future_object.mark_exceptional_finish_internal(boost::current_exception());
72 template<typename T, typename F>
73 static void locking_invoke(T& future_object, F& f)
78 future_object.mark_finished_with_result();
82 future_object.mark_exceptional_finish();
87 template<typename R, typename F>
88 struct deferred_future_object : public boost::detail::future_object<R>
94 deferred_future_object(F2&& f)
95 : f(std::forward<F2>(f))
98 set_wait_callback(std::mem_fn(&detail::deferred_future_object<R, F>::operator()), this);
101 ~deferred_future_object()
107 boost::lock_guard<boost::mutex> lock2(mutex);
112 future_object_helper<R>::nonlocking_invoke(*this, f);
118 template<typename R, typename F>
119 struct async_future_object : public boost::detail::future_object<R>
122 boost::thread thread;
124 template<typename F2>
125 async_future_object(F2&& f)
126 : f(std::forward<F2>(f))
127 , thread([this]{run();})
131 ~async_future_object()
138 future_object_helper<R>::locking_invoke(*this, f);
145 auto async(launch policy, F&& f) -> boost::unique_future<decltype(f())>
147 typedef decltype(f()) result_type;
148 typedef boost::detail::future_object<result_type> future_object_type;
150 boost::shared_ptr<future_object_type> future_object;
152 // HACK: This solution is a hack to avoid modifying boost code.
154 if((policy & launch::async) != 0)
155 future_object.reset(new detail::async_future_object<result_type, F>(std::forward<F>(f)), [](future_object_type* p){delete reinterpret_cast<detail::async_future_object<result_type, F>*>(p);});
156 else if((policy & launch::deferred) != 0)
157 future_object.reset(new detail::deferred_future_object<result_type, F>(std::forward<F>(f)), [](future_object_type* p){delete reinterpret_cast<detail::deferred_future_object<result_type, F>*>(p);});
159 throw std::invalid_argument("policy");
161 boost::unique_future<result_type> future;
163 static_assert(sizeof(future) == sizeof(future_object), "");
165 reinterpret_cast<boost::shared_ptr<future_object_type>&>(future) = std::move(future_object); // Get around the "private" encapsulation.
166 return std::move(future);
170 auto async(F&& f) -> boost::unique_future<decltype(f())>
172 return async(launch::async | launch::deferred, std::forward<F>(f));
176 auto make_shared(boost::unique_future<T>&& f) -> boost::shared_future<T>
178 return boost::shared_future<T>(std::move(f));
182 auto flatten(boost::unique_future<T>&& f) -> boost::unique_future<decltype(f.get().get())>
184 auto shared_f = make_shared(std::move(f));
185 return async(launch::deferred, [=]() mutable
187 return shared_f.get().get();