00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #ifndef RHA_FUTURES_HPP
00016 #define RHA_FUTURES_HPP
00017
00018 #include <stdexcept>
00019
00020 #include <boost/thread/thread.hpp>
00021 #include <boost/thread/condition.hpp>
00022 #include <boost/variant/variant.hpp>
00023 #include <boost/variant/static_visitor.hpp>
00024 #include <boost/variant/apply_visitor.hpp>
00025 #include <boost/variant/get.hpp>
00026 #include <boost/mpl/front.hpp>
00027 #include <boost/mpl/pop_front.hpp>
00028 #include <boost/mpl/empty.hpp>
00029 #include <boost/mpl/vector.hpp>
00030 #include <boost/mpl/push_back.hpp>
00031 #include <boost/optional.hpp>
00032 #include <boost/call_traits.hpp>
00033 #include <boost/function.hpp>
00034 #include <boost/shared_ptr.hpp>
00035
00036 namespace Rha
00037 {
00043 class UnboundFuture :
00044 public std::runtime_error
00045 {
00046 public:
00047 UnboundFuture() :
00048 std::runtime_error("call to unbound future")
00049 { }
00050 };
00051
00052 namespace Details
00053 {
00054
00055
00056
00057 struct Unusable
00058 {
00059 Unusable() {}
00060 template<typename T> Unusable(const T&) {}
00061 };
00062
00063
00064
00065
00066
00067 template<typename ResultType>
00068 struct ReturnTypeHelper
00069 {
00070 typedef ResultType Type;
00071 };
00072
00073 template<>
00074 struct ReturnTypeHelper<void>
00075 {
00076 typedef Unusable Type;
00077 };
00078 }
00079
00086 template<typename E0 = boost::detail::variant::void_,
00087 typename E1 = boost::detail::variant::void_,
00088 typename E2 = boost::detail::variant::void_,
00089 typename E3 = boost::detail::variant::void_,
00090 typename E4 = boost::detail::variant::void_,
00091 typename E5 = boost::detail::variant::void_,
00092 typename E6 = boost::detail::variant::void_,
00093 typename E7 = boost::detail::variant::void_,
00094 typename E8 = boost::detail::variant::void_>
00095 struct FutureRegistry
00096 {
00097 typedef E0 Exception0;
00098 typedef E1 Exception1;
00099 typedef E2 Exception2;
00100 typedef E3 Exception3;
00101 typedef E4 Exception4;
00102 typedef E5 Exception5;
00103 typedef E6 Exception6;
00104 typedef E7 Exception7;
00105 typedef E8 Exception8;
00106 template<typename R> class Future;
00107 private:
00112 template<typename ReturnType>
00113 struct ReturnTypeList
00114 {
00115 typedef boost::variant<ReturnType,
00116 Exception0,
00117 Exception1,
00118 Exception2,
00119 Exception3,
00120 Exception4,
00121 Exception5,
00122 Exception6,
00123 Exception7,
00124 Exception8> Type;
00125 };
00126
00131 template<typename R>
00132 struct TaskContext
00133 {
00134 typedef R ReturnType;
00135
00136 TaskContext(const boost::function0<ReturnType>& functor) :
00137 MReleased(false),
00138 M_functor(functor)
00139 { }
00140
00141 bool MReleased;
00142 boost::function0<ReturnType> M_functor;
00143 typename ReturnTypeList<typename Details::ReturnTypeHelper<ReturnType>::Type>::Type MResult;
00144 boost::condition M_condition;
00145 boost::mutex M_mutex;
00146 };
00147
00152 template <bool isEmpty, class ExceptionTypeList, bool isVoid>
00153 struct CallerImpl
00154 {
00155 template<class _Fun, class ResList>
00156 static void call(_Fun f, ResList* res)
00157 {
00158 f();
00159 *res = Details::Unusable();
00160 }
00161 };
00162
00167 template <class ExceptionTypeList>
00168 struct CallerImpl<true, ExceptionTypeList, false>
00169 {
00170 template<class _Fun, class ResList>
00171 static void call(_Fun f, ResList* res)
00172 {
00173 *res = f();
00174 }
00175 };
00176
00181 template <class ExceptionTypeList, bool isVoid>
00182 struct CallerImpl<false, ExceptionTypeList, isVoid>
00183 {
00184 template<class _Fun, class ResList>
00185 static void call(_Fun f, ResList* res)
00186 {
00187 try
00188 {
00189 typedef typename boost::mpl::pop_front<ExceptionTypeList>::type popped;
00190 CallerImpl<boost::mpl::empty<popped>::value, popped, isVoid>::call(f, res);
00191 }
00192 catch (typename boost::mpl::front<ExceptionTypeList>::type e)
00193 {
00194 *res = e;
00195 }
00196 }
00197 };
00198
00202 template<typename R>
00203 class JoinableTask
00204 {
00205 public:
00206 typedef R ReturnType;
00207 class Proxy;
00208 friend class Future<ReturnType>;
00209
00210 JoinableTask(const boost::function0<ReturnType>& functor) :
00211 M_taskContext(new TaskContext<ReturnType> (functor))
00212 { }
00213
00214 Proxy proxy()
00215 {
00216 return Proxy(M_taskContext);
00217 }
00218
00219 private:
00225 class Proxy
00226 {
00227 public:
00228 Proxy(typename boost::call_traits<boost::shared_ptr<TaskContext<ReturnType> > >::param_type taskContext) :
00229 M_sentry(new _Sentry_(taskContext))
00230 { }
00231
00232 ~Proxy()
00233 { }
00234
00235 void operator()()
00236 {
00237 try
00238 {
00239
00240
00241 typedef typename boost::mpl::pop_front<typename ReturnTypeList<typename Details::ReturnTypeHelper<ReturnType>::Type>::Type::types>::type popped;
00242 CallerImpl<boost::mpl::empty<popped>::value, popped, ::boost::is_void<ReturnType>::value>::call(M_sentry->M_taskContext->M_functor, &M_sentry->M_taskContext->MResult);
00243 }
00244 catch (...)
00245 {
00246
00247
00248
00249 std::unexpected();
00250 }
00251 }
00252
00253 private:
00254 struct _Sentry_
00255 {
00256 _Sentry_(typename boost::call_traits<boost::shared_ptr<TaskContext<ReturnType> > >::param_type taskContext) :
00257 M_taskContext(taskContext)
00258 { }
00259
00260 ~_Sentry_()
00261 {
00262 boost::mutex::scoped_lock lock__(M_taskContext->M_mutex);
00263 M_taskContext->MReleased = true;
00264 M_taskContext->M_condition.notify_all();
00265 }
00266 boost::shared_ptr<TaskContext<ReturnType> > M_taskContext;
00267 };
00268 boost::shared_ptr<_Sentry_> M_sentry;
00269 };
00270 boost::shared_ptr<TaskContext<ReturnType> > M_taskContext;
00271 };
00272 public:
00279 template<typename R>
00280 class Future
00281 {
00282 public:
00283 typedef R ReturnType;
00284 typedef R result_type;
00285
00286 Future(Future const& future) :
00287 M_taskContext(future.M_taskContext)
00288 { }
00289
00290 template<class _Scheduler, class _Function>
00291 Future(_Scheduler& s, _Function f)
00292 {
00293 JoinableTask<ReturnType> jt(f);
00294 s.push(jt.proxy());
00295 M_taskContext = jt.M_taskContext;
00296 }
00297
00298 Future()
00299 { }
00300
00301 Future& operator=(Future const& r)
00302 {
00303 M_taskContext = r.M_taskContext;
00304 return (*this);
00305 }
00306
00307 typename Details::ReturnTypeHelper<ReturnType>::Type join()
00308 {
00309 if (!this->bound())
00310 throw UnboundFuture();
00311
00312
00313 if (!M_taskContext->MReleased)
00314 {
00315 boost::mutex::scoped_lock lock__(M_taskContext->M_mutex);
00316 while(!M_taskContext->MReleased)
00317 M_taskContext->M_condition.wait(lock__);
00318 }
00319 if (typename Details::ReturnTypeHelper<ReturnType>::Type const* p =
00320 boost::get<typename Details::ReturnTypeHelper<ReturnType>::Type>(&M_taskContext->MResult))
00321 {
00322 return *p;
00323 }
00324 boost::apply_visitor(Rethrower(), M_taskContext->MResult);
00325
00326
00327 std::unexpected();
00328 }
00329
00330 typename Details::ReturnTypeHelper<ReturnType>::Type operator*()
00331 {
00332 return join();
00333 }
00334
00335 bool bound()
00336 {
00337 return (M_taskContext);
00338 }
00339 private:
00340 struct Rethrower : boost::static_visitor<>
00341 {
00342 template<class Exception>
00343 void operator()(Exception& e) const
00344 {
00345 throw e;
00346 }
00347 };
00348
00349 boost::shared_ptr<TaskContext<ReturnType> > M_taskContext;
00350 };
00351 };
00352 }
00353
00354 #endif // RHA_FUTURES_HPP
00355