Boost Reflect Library 0.1.0
mirror_interface.hpp
Go to the documentation of this file.
00001 #ifndef BOOST_PP_IS_ITERATING
00002   #ifndef BOOST_REFLECT_MIRROR_INTERFACE_HPP
00003   #define BOOST_REFLECT_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 reflect {
00017     /**
00018      *  @brief Specialized to mirror the member 
00019      *         variable/method pointed to by MemberPtr
00020      */
00021     template<typename MemberPtr>
00022     struct mirror_member;
00023 
00024     namespace detail {
00025         namespace mirror_interface {
00026           #ifndef DOXYGEN
00027           /**
00028            *  Assigns VTableType's functors with values from T
00029            */
00030           template<typename T, typename VTableType>
00031           class set_visitor {
00032             public:
00033               set_visitor( VTableType& vt, T& self )
00034               :m_self(self),vtbl(vt){}
00035 
00036               template<typename M, typename InterfaceName, M (InterfaceName::*m)>
00037               void operator()( const char* name )const {
00038                 assign<M> a(m_self,vtbl.*m);
00039                 M::template get_member_ptr<T>( a );
00040               }
00041             private:
00042               template<typename Member>
00043               struct assign {
00044                 assign( T& _v, Member& _m ):v(_v),m(_m){}
00045 
00046                 template<typename MemberPtr>
00047                 void operator=( const MemberPtr& p ) {
00048                   m.set_delegate( &v, p );
00049                 }
00050                 private:
00051                   T&      v;
00052                   Member& m;
00053               };
00054               T&          m_self;
00055               VTableType& vtbl;
00056           };
00057           template<typename Interface, typename Delegate, typename VTableType>
00058           class set_visitor<vtable<Interface,Delegate>, VTableType> {
00059             public:
00060               typedef boost::reflect::vtable<Interface,Delegate> T;
00061 
00062               set_visitor( VTableType& vt, T& self )
00063               :m_self(self),vtbl(vt){}
00064 
00065               template<typename M, typename InterfaceName, M (InterfaceName::*m)>
00066               void operator()( const char* name )const {
00067                 assign<M> a(m_self,vtbl.*m);
00068                 M::template get_member_ptr<T>( a );
00069               }
00070             private:
00071               template<typename Member>
00072               struct assign {
00073                 assign( T& _v, Member& _m ):v(_v),m(_m){}
00074 
00075                 template<typename MemberPtr>
00076                 void operator=( MemberPtr p ) {
00077                     m = boost::bind(boost::ref(v.*p), _1 );
00078                 }
00079                 private:
00080                   T&      v;
00081                   Member& m;
00082               };
00083               T&    m_self;
00084               VTableType& vtbl;
00085           };
00086          
00087           #endif 
00088         }
00089     }
00090     
00091     /**
00092      *  @brief Interface Delegate that mirrors the 
00093      *         reflected interface without any transformation.
00094      *  
00095      *  To specialize how a particular member is mirrored define
00096      *  the partial specialization of mirror_member for your type.
00097      *
00098      *  @code
00099      *  template<typename Type, typename Class>
00100      *  mirror_member<Type(Class::*)> 
00101      *  @endcode
00102      */
00103     struct mirror_interface 
00104     {
00105       /**
00106        * @brief Implements the InterfaceDelegate meta-function to 
00107        *      determine what type to create to mirror MemberPointer 
00108        *      in boost::reflect::vtable used by boost::reflect::any_ptr
00109        */
00110       template<typename MemberPointer>
00111       struct calculate_type {
00112         typedef mirror_member<MemberPointer>  type; 
00113       };
00114 
00115       template<typename T, typename VTableType>
00116       static void set_vtable( VTableType& vtable, T& value ) {
00117         vtable_reflector<typename VTableType::interface_type>::visit( &vtable,
00118                     detail::mirror_interface::set_visitor<T,VTableType>(vtable,value) );
00119       }
00120       template<typename T, typename VTableType>
00121       static void set_vtable( VTableType& vtable, const T& value ) {
00122         vtable_reflector<typename VTableType::interface_type>::visit( &vtable,
00123                     detail::mirror_interface::set_visitor<T,VTableType>(vtable,value) );
00124       }
00125     };
00126 
00127     #ifndef DOXYGEN
00128 
00129     /**
00130      *  Blocks a signal if it is currently unblocked and 
00131      *  unblocks it when it goes out of scope if it was blocked
00132      *  when constructed. 
00133      */
00134     struct scoped_block_signal {
00135       scoped_block_signal( boost::signals::connection& _c )
00136       :c(_c),unblock(false){ 
00137         if( c != boost::signals::connection() && !c.blocked() )  {
00138           unblock = true;
00139           c.block();
00140         }
00141       }
00142       ~scoped_block_signal() { 
00143         if( unblock && c != boost::signals::connection() ) 
00144             c.unblock(); 
00145       }
00146       private:
00147         bool                        unblock;
00148         boost::signals::connection& c; 
00149     };
00150     #endif
00151 
00152 
00153   #define PARAM_NAME(z,n,type)         BOOST_PP_CAT(a,n)
00154   #define PARAM_PLACE_HOLDER(z,n,type) BOOST_PP_CAT(_,BOOST_PP_ADD(n,1) )
00155   #define PARAM_TYPE_NAME(z,n,type)   BOOST_PP_CAT(typename A,n)
00156   #define PARAM_TYPE(z,n,type)   BOOST_PP_CAT(A,n)
00157   #define PARAM_ARG(z,n,type)     PARAM_TYPE(z,n,type) PARAM_NAME(z,n,type)
00158 
00159 #        ifndef BOOST_REFLECT_MIRROR_IMPL_SIZE
00160 #           define BOOST_REFLECT_MIRROR_IMPL_SIZE 8
00161 #        endif
00162 
00163 #       include <boost/preprocessor/iteration/iterate.hpp>
00164 #       define BOOST_PP_ITERATION_LIMITS (0, BOOST_REFLECT_MIRROR_IMPL_SIZE -1 )
00165 #       define BOOST_PP_FILENAME_1 <boost/reflect/mirror_interface.hpp>
00166 #       include BOOST_PP_ITERATE()
00167 
00168   #undef PARAM_NAME
00169   #undef PARAM_TYPE
00170   #undef PARAM_ARG
00171 
00172   } } // namespace boost::reflect
00173   #endif // BOOST_REFLECT_MIRROR_INTERFACE_HPP
00174 
00175 #else // BOOST_PP_IS_ITERATING
00176 
00177 #define n BOOST_PP_ITERATION()
00178 #define PARAM_NAMES          BOOST_PP_ENUM(n,PARAM_NAME,A) // name_N
00179 #define PARAM_PLACE_HOLDERS  BOOST_PP_ENUM_TRAILING(n,PARAM_PLACE_HOLDER,A) // _(N+1)
00180 #define PARAM_ARGS           BOOST_PP_ENUM(n,PARAM_ARG,A) // TYPE_N name_N
00181 #define PARAM_TYPE_NAMES     BOOST_PP_ENUM(n,PARAM_TYPE_NAME,A) // typename TYPE_N
00182 #define PARAM_TYPES          BOOST_PP_ENUM(n,PARAM_TYPE,A) // TYPE_N
00183 
00184 template<typename R, typename Class BOOST_PP_COMMA_IF(n) PARAM_TYPE_NAMES>
00185 struct mirror_member<R(Class::*)(PARAM_TYPES)const> 
00186 {
00187   // boost::result_of
00188   typedef typename adapt_void<R>::result_type                    result_type;
00189   typedef mirror_member                                          self_type;
00190   typedef boost::fusion::vector<PARAM_TYPES>                     fused_params;
00191   typedef boost::function_traits<result_type(PARAM_TYPES)>       traits;
00192   static const bool                                              is_const = true;
00193   static const bool                                              is_signal = false;
00194 
00195   typedef typename boost::remove_pointer<result_type(*)(PARAM_TYPES)>::type   signature;
00196 
00197   result_type operator()( PARAM_ARGS )const {
00198     return m_delegate( boost::fusion::make_vector(PARAM_NAMES) );
00199   }
00200   result_type operator() ( const fused_params& fp )const {
00201     return m_delegate( fp );
00202   }
00203   mirror_member& operator=( const mirror_member& d )  {
00204     m_delegate = d.m_delegate;
00205     return *this;
00206   }
00207   template<typename T>
00208   mirror_member& operator=( const T& d )  {
00209     m_delegate = adapt_void<R,T>(d);
00210     return *this;
00211   }
00212   template<typename C, typename M>
00213   void set_delegate(  C* s, M m ) {
00214     m_delegate = adapt_void<R, boost::function<R(const fused_params&)> >(
00215                     boost::fusion::make_fused_function_object( 
00216                                     boost::bind(m,s PARAM_PLACE_HOLDERS ) ));
00217   }
00218   private:
00219     boost::function<result_type(const fused_params&)> m_delegate; 
00220 };
00221 
00222 template<typename R, typename Class  BOOST_PP_COMMA_IF(n) PARAM_TYPE_NAMES>
00223 struct mirror_member<R(Class::*)(PARAM_TYPES)> 
00224 {
00225   typedef typename adapt_void<R>::result_type                result_type;
00226                                                                                        
00227   typedef mirror_member                                      self_type;
00228   typedef boost::fusion::vector<PARAM_TYPES>                 fused_params;
00229   typedef boost::function_traits<result_type(PARAM_TYPES)>   traits;
00230   typedef boost::function<result_type(const fused_params&)>  delegate_type;
00231   static const bool                                          is_const  = false;
00232   static const bool                                          is_signal = false;
00233 
00234   // boost::result_of
00235   typedef typename boost::remove_pointer<result_type(*)(PARAM_TYPES)>::type signature;
00236 
00237   result_type operator()( PARAM_ARGS ) {
00238     return m_delegate( boost::fusion::make_vector(PARAM_NAMES) );
00239   }
00240   result_type operator() ( const fused_params& fp ) {
00241     return m_delegate( fp );
00242   }
00243   template<typename T>
00244   mirror_member& operator=( const T& d )  {
00245     m_delegate = adapt_void<R,T>(d);
00246     return *this;
00247   }
00248   template<typename C, typename M>
00249   void set_delegate(  C* s, M m ) {
00250     m_delegate = adapt_void<R, boost::function<R(const fused_params&)> >(
00251                       boost::fusion::make_fused_function_object( 
00252                                        boost::bind(m,s PARAM_PLACE_HOLDERS ) ));
00253   }
00254   private:
00255     delegate_type m_delegate; 
00256 };
00257 
00258 
00259 template<typename R, typename Class  BOOST_PP_COMMA_IF(n) PARAM_TYPE_NAMES>
00260 struct mirror_member< boost::signal<R(PARAM_TYPES)> (Class::*) > 
00261 {
00262   typedef typename adapt_void<R>::result_type                result_type;
00263   typedef mirror_member                                      self_type;
00264   typedef boost::fusion::vector<PARAM_TYPES>                 fused_params;
00265   typedef boost::function_traits<result_type(PARAM_TYPES)>   traits;
00266   typedef boost::signal<R(PARAM_TYPES)>                      signal_type;
00267   static const bool                                          is_const = false;
00268   static const bool                                          is_signal = true;
00269 
00270   // boost::result_of
00271   typedef typename boost::remove_pointer<result_type(*)(PARAM_TYPES)>::type   signature;
00272 
00273   result_type operator()( PARAM_ARGS ) {
00274     return (*this)( boost::fusion::make_vector(PARAM_NAMES) );
00275   }
00276 
00277   result_type operator() ( const fused_params& fp ) {
00278     scoped_block_signal block_reverse(m_reverse_con);
00279     if( int(m_signal.num_slots()) - 1 > 0 )  // do not count our reverse connection
00280         boost::fusion::make_fused_function_object( boost::ref(m_signal) )(fp);
00281     return m_delegate( fp );
00282   }
00283 
00284   // emits locally, but does not forward to delegate
00285   result_type emit( const fused_params& fp ) {
00286     scoped_block_signal block_reverse(m_reverse_con);
00287     return adapt_void<R,boost::function<R(const fused_params&)> >(
00288             boost::fusion::make_fused_function_object( boost::ref(m_signal) ) )(fp);
00289   }
00290 
00291   template<typename T>
00292   mirror_member& operator=( const T& d )  {
00293     m_delegate = adapt_void<R,T>(d);
00294     return *this;
00295   }
00296 
00297   template<typename Functor>
00298   boost::signals::connection connect( const Functor& f ) {
00299     boost::signals::connection c = m_signal.connect(adapt_void<R,Functor>(f) );
00300     if( m_connect_delegate )
00301         m_connect_delegate(m_signal.num_slots());
00302     return c;
00303   }
00304   void disconnect( const boost::signals::connection& c ) {
00305     c.disconnect();
00306     if( m_connect_delegate )
00307         m_connect_delegate(m_signal.num_slots());
00308   }
00309 
00310   void set_connect_delegate( const boost::function<void(int)>& f ) {
00311     m_connect_delegate = f;
00312   }
00313 
00314   // sets the delegate that will be called when the signal is 'emited'
00315   template<typename C, typename M>
00316   void set_delegate(  C* s, M m ) {
00317     m_signal.disconnect_all_slots();
00318     m_reverse_con = 
00319         (s->*m).connect( boost::fusion::make_unfused( 
00320                             boost::bind( &mirror_member::emit, this, _1) )  );
00321 
00322     m_delegate = emit_or_throw( s->*m );
00323   }
00324 
00325   ~mirror_member() {
00326     m_signal.disconnect_all_slots();
00327     if( m_reverse_con != boost::signals::connection() )
00328         m_reverse_con.disconnect();
00329   }
00330 
00331   private:
00332 
00333     struct emit_or_throw {
00334         struct no_connected_slots : public std::exception, public boost::exception {
00335           const char* what()const throw() { return "no connected slots"; }
00336         };
00337         emit_or_throw( signal_type& s ):sig(s){}
00338         result_type operator()( const fused_params& p ) {
00339           if( int(sig.num_slots()) -1 > 0 ) { // do not count our reverse connection
00340             return adapt_void<R, boost::function<R(const fused_params&)> >(
00341                       boost::fusion::make_fused_function_object(boost::ref(sig)))(p);
00342           }
00343           BOOST_THROW_EXCEPTION( no_connected_slots() );
00344         }
00345         signal_type&            sig;
00346     };
00347 
00348     boost::function<void(int)>                         m_connect_delegate;
00349     boost::function<result_type(const fused_params&)>  m_delegate; 
00350     boost::signals::connection                         m_reverse_con;
00351     boost::signal<R(PARAM_TYPES)>                      m_signal;
00352 };
00353 
00354 #undef n
00355 #undef PARAM_NAMES         
00356 #undef PARAM_PLACE_HOLDERS
00357 #undef PARAM_ARGS        
00358 #undef PARAM_TYPE_NAMES 
00359 #undef PARAM_TYPES     
00360 
00361 #endif // BOOST_PP_IS_ITERATING

© Daniel Larimer 2010-2011 - Licensed under Boost Software License, Version 1.0 Boost Reflect Library