#ifndef __PROCESS_DEFER_HPP__ #define __PROCESS_DEFER_HPP__ #include #include #include #include #include namespace process { // The defer mechanism is very similar to the dispatch mechanism (see // dispatch.hpp), however, rather than scheduling the method to get // invoked, the defer mechanism returns a 'Deferred' object that when // invoked does the underlying dispatch. Similar to dispatch, we // provide the C++11 variadic template definitions first, and then use // Boost preprocessor macros to provide the actual definitions. // First, definitions of defer for methods returning void: // // template // Deferred void defer(const PID& pid, // void (T::*method)(P...), // P... p) // { // void (*dispatch)(const PID&, void (T::*)(P...), P...) = // &process::template dispatch; // return Deferred( // std::tr1::bind(dispatch, pid, method, std::forward

(p)...)); // } template _Defer, void (T::*)(void))) (const PID&, void (T::*)(void))> defer(const PID& pid, void (T::*method)(void)) { void (*dispatch)(const PID&, void (T::*)(void)) = &process::template dispatch; return std::tr1::bind(dispatch, pid, method); } template _Defer, void (T::*)(void))) (const PID&, void (T::*)(void))> defer(const Process& process, void (T::*method)(void)) { return defer(process.self(), method); } template _Defer, void (T::*)(void))) (const PID&, void (T::*)(void))> defer(const Process* process, void (T::*method)(void)) { return defer(process->self(), method); } #define TEMPLATE(Z, N, DATA) \ template \ _Defer, \ void (T::*)(ENUM_PARAMS(N, P)), \ ENUM_PARAMS(N, A))) \ (const PID&, \ void (T::*)(ENUM_PARAMS(N, P)), \ ENUM_PARAMS(N, P))> \ defer(const PID& pid, \ void (T::*method)(ENUM_PARAMS(N, P)), \ ENUM_BINARY_PARAMS(N, A, a)) \ { \ void (*dispatch)(const PID&, \ void (T::*)(ENUM_PARAMS(N, P)), \ ENUM_PARAMS(N, P)) = \ &process::template dispatch; \ return std::tr1::bind(dispatch, pid, method, ENUM_PARAMS(N, a)); \ } \ \ template \ _Defer, \ void (T::*)(ENUM_PARAMS(N, P)), \ ENUM_PARAMS(N, A))) \ (const PID&, \ void (T::*)(ENUM_PARAMS(N, P)), \ ENUM_PARAMS(N, P))> \ defer(const Process& process, \ void (T::*method)(ENUM_PARAMS(N, P)), \ ENUM_BINARY_PARAMS(N, A, a)) \ { \ return defer(process.self(), method, ENUM_PARAMS(N, a)); \ } \ \ template \ _Defer, \ void (T::*)(ENUM_PARAMS(N, P)), \ ENUM_PARAMS(N, A))) \ (const PID&, \ void (T::*)(ENUM_PARAMS(N, P)), \ ENUM_PARAMS(N, P))> \ defer(const Process* process, \ void (T::*method)(ENUM_PARAMS(N, P)), \ ENUM_BINARY_PARAMS(N, A, a)) \ { \ return defer(process->self(), method, ENUM_PARAMS(N, a)); \ } REPEAT_FROM_TO(1, 11, TEMPLATE, _) // Args A0 -> A9. #undef TEMPLATE // Next, definitions of defer for methods returning future: // // template // Deferred(void)> void defer(const PID& pid, // Future (T::*method)(P...), // P... p) // { // Future (*dispatch)(const PID&, Future (T::*)(P...), P...) = // &process::template dispatch; // // return Deferred(void)>( // std::tr1::bind(dispatch, pid, method, std::forward

(p)...)); // } template _Defer(*(PID, Future (T::*)(void))) (const PID&, Future (T::*)(void))> defer(const PID& pid, Future (T::*method)(void)) { Future (*dispatch)(const PID&, Future (T::*)(void)) = &process::template dispatch; return std::tr1::bind(dispatch, pid, method); } template _Defer(*(PID, Future (T::*)(void)))( const PID&, Future (T::*)(void))> defer(const Process& process, Future (T::*method)(void)) { return defer(process.self(), method); } template _Defer(*(PID, Future (T::*)(void))) (const PID&, Future (T::*)(void))> defer(const Process* process, Future (T::*method)(void)) { return defer(process->self(), method); } #define TEMPLATE(Z, N, DATA) \ template \ _Defer(*(PID, \ Future (T::*)(ENUM_PARAMS(N, P)), \ ENUM_PARAMS(N, A))) \ (const PID&, \ Future (T::*)(ENUM_PARAMS(N, P)), \ ENUM_PARAMS(N, P))> \ defer(const PID& pid, \ Future (T::*method)(ENUM_PARAMS(N, P)), \ ENUM_BINARY_PARAMS(N, A, a)) \ { \ Future (*dispatch)(const PID&, \ Future (T::*)(ENUM_PARAMS(N, P)), \ ENUM_PARAMS(N, P)) = \ &process::template dispatch; \ return std::tr1::bind(dispatch, pid, method, ENUM_PARAMS(N, a)); \ } \ \ template \ _Defer(*(PID, \ Future (T::*)(ENUM_PARAMS(N, P)), \ ENUM_PARAMS(N, A))) \ (const PID&, \ Future (T::*)(ENUM_PARAMS(N, P)), \ ENUM_PARAMS(N, P))> \ defer(const Process& process, \ Future (T::*method)(ENUM_PARAMS(N, P)), \ ENUM_BINARY_PARAMS(N, A, a)) \ { \ return defer(process.self(), method, ENUM_PARAMS(N, a)); \ } \ \ template \ _Defer(*(PID, \ Future (T::*)(ENUM_PARAMS(N, P)), \ ENUM_PARAMS(N, A))) \ (const PID&, \ Future (T::*)(ENUM_PARAMS(N, P)), \ ENUM_PARAMS(N, P))> \ defer(const Process* process, \ Future (T::*method)(ENUM_PARAMS(N, P)), \ ENUM_BINARY_PARAMS(N, A, a)) \ { \ return defer(process->self(), method, ENUM_PARAMS(N, a)); \ } REPEAT_FROM_TO(1, 11, TEMPLATE, _) // Args A0 -> A9. #undef TEMPLATE // Next, definitions of defer for methods returning a value: // // template // Deferred(void)> void defer(const PID& pid, // R (T::*method)(P...), // P... p) // { // Future (*dispatch)(const PID&, R (T::*)(P...), P...) = // &process::template dispatch; // // return Deferred(void)>( // std::tr1::bind(dispatch, pid, method, std::forward

(p)...)); // } template _Defer(*(PID, R (T::*)(void))) (const PID&, R (T::*)(void))> defer(const PID& pid, R (T::*method)(void)) { Future (*dispatch)(const PID&, R (T::*)(void)) = &process::template dispatch; return std::tr1::bind(dispatch, pid, method); } template _Defer(*(PID, R (T::*)(void))) (const PID&, R (T::*)(void))> defer(const Process& process, R (T::*method)(void)) { return defer(process.self(), method); } template _Defer(*(PID, R (T::*)(void))) (const PID&, R (T::*)(void))> defer(const Process* process, R (T::*method)(void)) { return defer(process->self(), method); } #define TEMPLATE(Z, N, DATA) \ template \ _Defer(*(PID, \ R (T::*)(ENUM_PARAMS(N, P)), \ ENUM_PARAMS(N, A))) \ (const PID&, \ R (T::*)(ENUM_PARAMS(N, P)), \ ENUM_PARAMS(N, P))> \ defer(const PID& pid, \ R (T::*method)(ENUM_PARAMS(N, P)), \ ENUM_BINARY_PARAMS(N, A, a)) \ { \ Future (*dispatch)(const PID&, \ R (T::*)(ENUM_PARAMS(N, P)), \ ENUM_PARAMS(N, P)) = \ &process::template dispatch; \ return std::tr1::bind(dispatch, pid, method, ENUM_PARAMS(N, a)); \ } \ \ template \ _Defer(*(PID, \ R (T::*)(ENUM_PARAMS(N, P)), \ ENUM_PARAMS(N, A))) \ (const PID&, \ R (T::*)(ENUM_PARAMS(N, P)), \ ENUM_PARAMS(N, P))> \ defer(const Process& process, \ R (T::*method)(ENUM_PARAMS(N, P)), \ ENUM_BINARY_PARAMS(N, A, a)) \ { \ return defer(process.self(), method, ENUM_PARAMS(N, a)); \ } \ \ template \ _Defer(*(PID, \ R (T::*)(ENUM_PARAMS(N, P)), \ ENUM_PARAMS(N, A))) \ (const PID&, \ R (T::*)(ENUM_PARAMS(N, P)), \ ENUM_PARAMS(N, P))> \ defer(const Process* process, \ R (T::*method)(ENUM_PARAMS(N, P)), \ ENUM_BINARY_PARAMS(N, A, a)) \ { \ return defer(process->self(), method, ENUM_PARAMS(N, a)); \ } REPEAT_FROM_TO(1, 11, TEMPLATE, _) // Args A0 -> A9. #undef TEMPLATE namespace internal { inline void invoker( ProcessBase* _, const std::tr1::function& f) { f(); } inline void dispatcher( const UPID& pid, const std::tr1::function& f) { std::tr1::shared_ptr > invoker( new std::tr1::function( std::tr1::bind(&internal::invoker, std::tr1::placeholders::_1, f))); internal::dispatch(pid, invoker); } #define TEMPLATE(Z, N, DATA) \ template \ void CAT(invoker, N)( \ ProcessBase* _, \ const std::tr1::function& f, \ ENUM_BINARY_PARAMS(N, A, a)) \ { \ f(ENUM_PARAMS(N, a)); \ } \ \ template \ void CAT(dispatcher, N)( \ const UPID& pid, \ const std::tr1::function& f, \ ENUM_BINARY_PARAMS(N, A, a)) \ { \ std::tr1::shared_ptr > invoker( \ new std::tr1::function( \ std::tr1::bind(&internal::CAT(invoker, N), \ std::tr1::placeholders::_1, \ f, \ ENUM_PARAMS(N, a)))); \ \ internal::dispatch(pid, invoker); \ } REPEAT_FROM_TO(1, 11, TEMPLATE, _) // Args A0 -> A9. #undef TEMPLATE // We can't easily use 'std::tr1::_Placeholder' when doing macro // expansion via ENUM_BINARY_PARAMS because compilers don't like it // when you try and concatenate '<' 'N' '>'. Thus, we typedef them. #define TEMPLATE(Z, N, DATA) \ typedef std::tr1::_Placeholder _ ## N; REPEAT(10, TEMPLATE, _) #undef TEMPLATE } // namespace internal { // Now we define defer calls for functions and bind statements. inline Deferred defer(const std::tr1::function& f) { if (__process__ != NULL) { // In C++11: // const UPID pid = __process__->self(); // return []() { // internal::dispatch(pid, [](ProcessBase* _) { f(); }); // } return std::tr1::function( std::tr1::bind(&internal::dispatcher, __process__->self(), f)); } return __executor__->defer(f); } #define TEMPLATE(Z, N, DATA) \ template \ Deferred defer( \ const std::tr1::function& f) \ { \ if (__process__ != NULL) { \ return std::tr1::function( \ std::tr1::bind(&internal::CAT(dispatcher, N), \ __process__->self(), \ f, \ ENUM_BINARY_PARAMS(N, internal::_, () INTERCEPT))); \ } \ \ return __executor__->defer(f); \ } \ \ template \ Deferred(ENUM_PARAMS(N, A))> defer( \ const std::tr1::function(ENUM_PARAMS(N, A))>& f) \ { \ if (__process__ != NULL) { \ return std::tr1::function(ENUM_PARAMS(N, A))>( \ std::tr1::bind(&internal::CAT(dispatcher, N), \ __process__->self(), \ f, \ ENUM_BINARY_PARAMS(N, internal::_, () INTERCEPT))); \ } \ \ return __executor__->defer(f); \ } REPEAT_FROM_TO(1, 11, TEMPLATE, _) // Args A0 -> A9. #undef TEMPLATE } // namespace process { #endif // __PROCESS_DEFER_HPP__