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
00019
00020
00021 template<typename MemberPtr>
00022 struct mirror_member;
00023
00024 namespace detail {
00025 namespace mirror_interface {
00026 #ifndef DOXYGEN
00027
00028
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
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103 struct mirror_interface
00104 {
00105
00106
00107
00108
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
00131
00132
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 } }
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
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
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
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 )
00280 boost::fusion::make_fused_function_object( boost::ref(m_signal) )(fp);
00281 return m_delegate( fp );
00282 }
00283
00284
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
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 ) {
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