Bytemaster's Boost Libraries
/Users/dlarimer/dev/libs/rpc/include/boost/rpc/mirror_interface.hpp
00001 #ifndef BOOST_PP_IS_ITERATING
00002   #ifndef BOOST_RPC_MIRROR_INTERFACE_HPP
00003   #define BOOST_RPC_MIRROR_INTERFACE_HPP
00004   #include <boost/bind.hpp>
00005   #include <boost/preprocessor/repetition.hpp>
00006   #include <boost/preprocessor/seq/for_each.hpp>
00007 
00008   #include <boost/fusion/container/vector.hpp>
00009   #include <boost/fusion/container/generation/make_vector.hpp>
00010   #include <boost/fusion/functional/generation/make_fused_function_object.hpp>
00011   #include <boost/fusion/functional/generation/make_unfused.hpp>
00012   #include <boost/reflect/void.hpp>
00013   #include <boost/signals.hpp>
00014   #include <boost/reflect/vtable.hpp>
00015 
00016   namespace boost { namespace rpc {
00021     template<typename MemberPtr>
00022     struct mirror_member;
00023     
00044     struct mirror_interface 
00045     {
00051       template<typename MemberPointer>
00052       struct calculate_type {
00053         typedef mirror_member<MemberPointer>  type; 
00054       };
00055 
00056       #ifndef DOXYGEN
00057       template<typename T, typename VTableType>
00058       class set_visitor {
00059         public:
00060           set_visitor( VTableType& vt, T& self )
00061           :m_self(self),vtable(vt){}
00062 
00063           template<typename InterfaceName, typename M>
00064           void operator()( M InterfaceName::* m, const char* name )const {
00065             assign<M> a(m_self,vtable.*m);
00066             M::template get_member_ptr<T>( a );
00067           }
00068         private:
00069           template<typename Member>
00070           struct assign {
00071             assign( T& _v, Member& _m ):v(_v),m(_m){}
00072 
00073             template<typename MemberPtr>
00074             void operator=( const MemberPtr& p ) {
00075               m.set_delegate( &v, p );
00076             }
00077             private:
00078               T&      v;
00079               Member& m;
00080           };
00081           T&          m_self;
00082           VTableType& vtable;
00083       };
00084       #endif 
00085       template<typename T, typename VTableType>
00086       static void set_vtable( VTableType& vtable, T& value ) {
00087         boost::reflect::vtable_reflector<typename VTableType::interface_type>::visit( &vtable,
00088                     set_visitor<T,VTableType>(vtable,value) );
00089       }
00090       template<typename T, typename VTableType>
00091       static void set_vtable( VTableType& vtable, const T& value ) {
00092         boost::reflect::vtable_reflector<typename VTableType::interface_type>::visit( &vtable,
00093                     set_visitor<T,VTableType>(vtable,value) );
00094       }
00095     };
00096 
00097     #ifndef DOXYGEN
00098 
00104     struct scoped_block_signal {
00105       scoped_block_signal( boost::signals::connection& _c )
00106       :c(_c),unblock(false){ 
00107         if( c != boost::signals::connection() && !c.blocked() )  {
00108           unblock = true;
00109           c.block();
00110         }
00111       }
00112       ~scoped_block_signal() { 
00113         if( unblock && c != boost::signals::connection() ) 
00114             c.unblock(); 
00115       }
00116       private:
00117         bool                        unblock;
00118         boost::signals::connection& c; 
00119     };
00120     #endif
00121 
00122 
00123   #define PARAM_NAME(z,n,type)         BOOST_PP_CAT(a,n)
00124   #define PARAM_PLACE_HOLDER(z,n,type) BOOST_PP_CAT(_,BOOST_PP_ADD(n,1) )
00125   #define PARAM_TYPE_NAME(z,n,type)   BOOST_PP_CAT(typename A,n)
00126   #define PARAM_TYPE(z,n,type)   BOOST_PP_CAT(A,n)
00127   #define PARAM_ARG(z,n,type)     PARAM_TYPE(z,n,type) PARAM_NAME(z,n,type)
00128 
00129 #        ifndef BOOST_RPC_IMPL_SIZE
00130 #           define BOOST_RPC_IMPL_SIZE 8
00131 #        endif
00132 
00133 #       include <boost/preprocessor/iteration/iterate.hpp>
00134 #       define BOOST_PP_ITERATION_LIMITS (0, BOOST_RPC_IMPL_SIZE -1 )
00135 #       define BOOST_PP_FILENAME_1 <boost/rpc/mirror_interface.hpp>
00136 #       include BOOST_PP_ITERATE()
00137 
00138   #undef PARAM_NAME
00139   #undef PARAM_TYPE
00140   #undef PARAM_ARG
00141 
00142   } } // namespace boost::reflect
00143   #endif // BOOST_RPC_MIRROR_INTERFACE_HPP
00144 
00145 #else // BOOST_PP_IS_ITERATING
00146 
00147 #define n BOOST_PP_ITERATION()
00148 #define PARAM_NAMES          BOOST_PP_ENUM(n,PARAM_NAME,A) // name_N
00149 #define PARAM_PLACE_HOLDERS  BOOST_PP_ENUM_TRAILING(n,PARAM_PLACE_HOLDER,A) // _(N+1)
00150 #define PARAM_ARGS           BOOST_PP_ENUM(n,PARAM_ARG,A) // TYPE_N name_N
00151 #define PARAM_TYPE_NAMES     BOOST_PP_ENUM(n,PARAM_TYPE_NAME,A) // typename TYPE_N
00152 #define PARAM_TYPES          BOOST_PP_ENUM(n,PARAM_TYPE,A) // TYPE_N
00153 
00154 template<typename R, typename Class BOOST_PP_COMMA_IF(n) PARAM_TYPE_NAMES>
00155 struct mirror_member<R(Class::*)(PARAM_TYPES)const> {
00156   typedef boost::cmt::future<R>                                               result_type;
00157   typedef mirror_member                                                       self_type;
00158   typedef boost::fusion::vector<PARAM_TYPES>                                  fused_params;
00159   typedef boost::function_traits<result_type(PARAM_TYPES)>                    traits;
00160   static const bool                                                           is_const = true;
00161   static const bool                                                           is_signal = false;
00162   typedef typename boost::remove_pointer<result_type(*)(PARAM_TYPES)>::type   signature;
00163 
00164   result_type operator()( PARAM_ARGS )const {
00165     return m_delegate( fused_params(PARAM_NAMES) );
00166   }
00167   result_type operator() ( const fused_params& fp )const {
00168     return m_delegate( fp );
00169   }
00170   mirror_member& operator=( const mirror_member& d )  {
00171     m_delegate = d.m_delegate;
00172     return *this;
00173   }
00174   template<typename T>
00175   mirror_member& operator=( const T& d )  {
00176     m_delegate = d;
00177     return *this;
00178   }
00179   private:
00180     boost::function<result_type(const fused_params&)> m_delegate; 
00181 };
00182 
00183 template<typename R, typename Class  BOOST_PP_COMMA_IF(n) PARAM_TYPE_NAMES>
00184 struct mirror_member<R(Class::*)(PARAM_TYPES)> {
00185   typedef boost::cmt::future<R>                                             result_type;
00186   typedef mirror_member                                                     self_type;
00187   typedef boost::fusion::vector<PARAM_TYPES>                                fused_params;
00188   typedef boost::function_traits<R(PARAM_TYPES)>                            traits;
00189   typedef boost::function<result_type(const fused_params&)>                 delegate_type;
00190   static const bool                                                         is_const  = false;
00191   static const bool                                                         is_signal = false;
00192   typedef typename boost::remove_pointer<result_type(*)(PARAM_TYPES)>::type signature;
00193 
00194   result_type operator()( PARAM_ARGS ) {
00195     return m_delegate( fused_params(PARAM_NAMES) );
00196   }
00197   result_type operator() ( const fused_params& fp ) {
00198     return m_delegate( fp );
00199   }
00200   mirror_member& operator=( const mirror_member& d )  {
00201     m_delegate = d.m_delegate;
00202     return *this;
00203   }
00204   template<typename T>
00205   mirror_member& operator=( const T& d )  {
00206     m_delegate = d;
00207     return *this;
00208   }
00209   private:
00210     delegate_type m_delegate; 
00211 };
00212 
00213 
00214 template<typename R, typename Class  BOOST_PP_COMMA_IF(n) PARAM_TYPE_NAMES>
00215 struct mirror_member< boost::signal<R(PARAM_TYPES)> (Class::*) > 
00216 {
00217   typedef boost::cmt::future<typename boost::reflect::adapt_void<R>::result_type> result_type;
00218   typedef mirror_member                                                           self_type;
00219   typedef boost::fusion::vector<PARAM_TYPES>                                      fused_params;
00220   typedef boost::function_traits<result_type(PARAM_TYPES)>                        traits;
00221   typedef boost::signal<R(PARAM_TYPES)>                                           signal_type;
00222   static const bool                                                               is_const = false;
00223   static const bool                                                               is_signal = true;
00224 
00225   // boost::result_of
00226   typedef typename boost::remove_pointer<result_type(*)(PARAM_TYPES)>::type   signature;
00227 
00228   result_type operator()( PARAM_ARGS ) {
00229     return (*this)( fused_params(PARAM_NAMES) );
00230   }
00231 
00232   result_type operator() ( const fused_params& fp ) {
00233     scoped_block_signal block_reverse(m_reverse_con);
00234     if( int(m_signal.num_slots()) - 1 > 0 )  // do not count our reverse connection
00235         boost::fusion::make_fused_function_object( boost::ref(m_signal) )(fp);
00236     return m_delegate( fp );
00237   }
00238 
00239   // emits locally, but does not forward to delegate
00240   typename boost::reflect::adapt_void<R>::result_type emit( const fused_params& fp ) {
00241     scoped_block_signal block_reverse(m_reverse_con);
00242     return boost::reflect::adapt_void<R,boost::function<R(const fused_params&)> >(
00243             boost::fusion::make_fused_function_object( boost::ref(m_signal) ) )(fp);
00244   }
00245 
00246   template<typename T>
00247   mirror_member& operator=( const T& d )  {
00248     m_delegate = d;
00249     /*
00250     m_signal.disconnect_all_slots();
00251     m_reverse_con = 
00252         d.connect( boost::fusion::make_unfused( 
00253                             boost::bind( &mirror_member::emit, this, _1) )  );
00254     m_delegate = emit_or_throw(boost::reflect::adapt_void<R,T>(d));
00255                             */
00256     return *this;
00257   }
00258 
00259   template<typename Functor>
00260   boost::signals::connection connect( const Functor& f ) {
00261     boost::signals::connection c = m_signal.connect(boost::reflect::adapt_void<R,Functor>(f) );
00262     if( m_connect_delegate )
00263         m_connect_delegate(m_signal.num_slots());
00264     return c;
00265   }
00266   void disconnect( const boost::signals::connection& c ) {
00267     c.disconnect();
00268     if( m_connect_delegate )
00269         m_connect_delegate(m_signal.num_slots());
00270   }
00271 
00272   void set_connect_delegate( const boost::function<void(int)>& f ) {
00273     m_connect_delegate = f;
00274   }
00275 
00276   // sets the delegate that will be called when the signal is 'emited'
00277   template<typename C, typename M>
00278   void set_delegate(  C* s, M m ) {
00279     m_signal.disconnect_all_slots();
00280     m_reverse_con = 
00281         (s->*m).connect( boost::fusion::make_unfused( 
00282                             boost::bind( &mirror_member::emit, this, _1) )  );
00283 
00284     m_delegate = emit_or_throw( s->*m );
00285   }
00286 
00287   ~mirror_member() {
00288     m_signal.disconnect_all_slots();
00289     if( m_reverse_con != boost::signals::connection() )
00290         m_reverse_con.disconnect();
00291   }
00292 
00293   private:
00294 
00295     struct emit_or_throw {
00296         struct no_connected_slots : public std::exception, public boost::exception {
00297           const char* what()const throw() { return "no connected slots"; }
00298         };
00299 
00300         emit_or_throw( signal_type& s ):sig(s){}
00301         result_type operator()( const fused_params& p ) {
00302           if( int(sig.num_slots()) -1 > 0 ) { // do not count our reverse connection
00303             return boost::reflect::adapt_void<R, boost::function<R(const fused_params&)> >(
00304                       boost::fusion::make_fused_function_object(boost::ref(sig)))(p);
00305           }
00306           BOOST_THROW_EXCEPTION( no_connected_slots() );
00307         }
00308         signal_type&            sig;
00309     };
00310 
00311     boost::function<void(int)>                         m_connect_delegate;
00312     boost::function<result_type(const fused_params&)>  m_delegate; 
00313     boost::signals::connection                         m_reverse_con;
00314     boost::signal<R(PARAM_TYPES)>                      m_signal;
00315 };
00316 
00317 #undef n
00318 #undef PARAM_NAMES         
00319 #undef PARAM_PLACE_HOLDERS
00320 #undef PARAM_ARGS        
00321 #undef PARAM_TYPE_NAMES 
00322 #undef PARAM_TYPES     
00323 
00324 #endif // BOOST_PP_IS_ITERATING
 All Classes Namespaces Files Functions Variables Typedefs Defines