Bytemaster's Boost Libraries
|
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 { 00021 template<typename MemberPtr> 00022 struct mirror_member; 00023 00024 namespace detail { 00025 namespace mirror_interface { 00026 #ifndef DOXYGEN 00027 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 00103 struct mirror_interface 00104 { 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 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