1 // Boost.Signals library 2 3 // Copyright Douglas Gregor 2001-2004. Use, modification and 4 // distribution is subject to the Boost Software License, Version 5 // 1.0. (See accompanying file LICENSE_1_0.txt or copy at 6 // http://www.boost.org/LICENSE_1_0.txt) 7 8 // For more information, see http://www.boost.org 9 10 // This file intentionally does not have include guards, because it is meant 11 // to be included multiple times (one for each signalN class). The 12 // BOOST_SIGNALS_SIGNAL_TEMPLATE_HEADER_INCLUDED macro merely serves to 13 // suppress reinclusion of the files that this header depends on. 14 15 #ifndef BOOST_SIGNALS_SIGNAL_TEMPLATE_HEADER_INCLUDED 16 #define BOOST_SIGNALS_SIGNAL_TEMPLATE_HEADER_INCLUDED 17 # include <boost/config.hpp> 18 # include <boost/signals/connection.hpp> 19 # include <boost/utility.hpp> 20 # include <boost/ref.hpp> 21 # include <boost/signals/slot.hpp> 22 # include <boost/last_value.hpp> 23 # include <boost/signals/detail/signal_base.hpp> 24 # include <boost/signals/detail/slot_call_iterator.hpp> 25 # include <boost/mpl/bool.hpp> 26 # include <boost/type_traits/is_convertible.hpp> 27 # include <cassert> 28 # include <functional> 29 # include <memory> 30 #endif // !BOOST_SIGNALS_SIGNAL_TEMPLATE_HEADER_INCLUDED 31 32 #ifdef BOOST_HAS_ABI_HEADERS 33 # include BOOST_ABI_PREFIX 34 #endif 35 36 // Include the appropriate functionN header 37 #define BOOST_SIGNAL_FUNCTION_N_HEADER BOOST_JOIN(<boost/function/function,BOOST_SIGNALS_NUM_ARGS.hpp>) 38 #include BOOST_SIGNAL_FUNCTION_N_HEADER 39 40 // Determine if a comma should follow a listing of the arguments/parameters 41 #if BOOST_SIGNALS_NUM_ARGS == 0 42 # define BOOST_SIGNALS_COMMA_IF_NONZERO_ARGS 43 #else 44 # define BOOST_SIGNALS_COMMA_IF_NONZERO_ARGS , 45 #endif // BOOST_SIGNALS_NUM_ARGS > 0 46 47 // Define class names used 48 #define BOOST_SIGNALS_SIGNAL BOOST_JOIN(signal,BOOST_SIGNALS_NUM_ARGS) 49 #define BOOST_SIGNALS_FUNCTION BOOST_JOIN(function,BOOST_SIGNALS_NUM_ARGS) 50 #define BOOST_SIGNALS_ARGS_STRUCT BOOST_JOIN(args,BOOST_SIGNALS_NUM_ARGS) 51 #define BOOST_SIGNALS_CALL_BOUND BOOST_JOIN(call_bound,BOOST_SIGNALS_NUM_ARGS) 52 53 // Define commonly-used instantiations 54 #define BOOST_SIGNALS_ARGS_STRUCT_INST \ 55 BOOST_SIGNALS_NAMESPACE::detail::BOOST_SIGNALS_ARGS_STRUCT<BOOST_SIGNALS_TEMPLATE_ARGS> 56 57 namespace boost { 58 namespace BOOST_SIGNALS_NAMESPACE { 59 namespace detail { 60 // Holds the arguments for a bound slot call in a single place 61 template<BOOST_SIGNALS_TEMPLATE_PARMS 62 BOOST_SIGNALS_COMMA_IF_NONZERO_ARGS 63 typename Dummy = int> 64 struct BOOST_SIGNALS_ARGS_STRUCT { BOOST_SIGNALS_ARGS_STRUCTboost::BOOST_SIGNALS_NAMESPACE::detail::BOOST_SIGNALS_ARGS_STRUCT65 BOOST_SIGNALS_ARGS_STRUCT(BOOST_SIGNALS_COPY_PARMS) 66 BOOST_SIGNALS_INIT_ARGS 67 { 68 } 69 70 BOOST_SIGNALS_ARGS_AS_MEMBERS 71 }; 72 73 // Function object that calls the function object given to it, passing 74 // the bound arguments along to that underlying function object 75 template<typename R> 76 struct BOOST_SIGNALS_CALL_BOUND { 77 template<BOOST_SIGNALS_TEMPLATE_PARMS 78 BOOST_SIGNALS_COMMA_IF_NONZERO_ARGS 79 typename F> 80 struct caller { 81 typedef BOOST_SIGNALS_ARGS_STRUCT<BOOST_SIGNALS_TEMPLATE_ARGS>* 82 args_type; 83 84 args_type args; 85 86 typedef R result_type; 87 callerboost::BOOST_SIGNALS_NAMESPACE::detail::BOOST_SIGNALS_CALL_BOUND::caller88 caller() {} callerboost::BOOST_SIGNALS_NAMESPACE::detail::BOOST_SIGNALS_CALL_BOUND::caller89 caller(args_type a) : args(a) {} 90 91 template<typename Pair> operator ()boost::BOOST_SIGNALS_NAMESPACE::detail::BOOST_SIGNALS_CALL_BOUND::caller92 R operator()(const Pair& slot) const 93 { 94 F* target = const_cast<F*>(unsafe_any_cast<F>(&slot.second)); 95 return (*target)(BOOST_SIGNALS_BOUND_ARGS); 96 } 97 }; 98 }; 99 100 template<> 101 struct BOOST_SIGNALS_CALL_BOUND<void> { 102 template<BOOST_SIGNALS_TEMPLATE_PARMS 103 BOOST_SIGNALS_COMMA_IF_NONZERO_ARGS 104 typename F> 105 struct caller { 106 typedef BOOST_SIGNALS_ARGS_STRUCT<BOOST_SIGNALS_TEMPLATE_ARGS>* 107 args_type; 108 109 args_type args; 110 111 typedef unusable result_type; 112 callerboost::BOOST_SIGNALS_NAMESPACE::detail::BOOST_SIGNALS_CALL_BOUND::caller113 caller(args_type a) : args(a) {} 114 115 template<typename Pair> operator ()boost::BOOST_SIGNALS_NAMESPACE::detail::BOOST_SIGNALS_CALL_BOUND::caller116 unusable operator()(const Pair& slot) const 117 { 118 F* target = const_cast<F*>(unsafe_any_cast<F>(&slot.second)); 119 (*target)(BOOST_SIGNALS_BOUND_ARGS); 120 return unusable(); 121 } 122 }; 123 }; 124 } // namespace detail 125 } // namespace BOOST_SIGNALS_NAMESPACE 126 127 // The actual signalN class 128 template< 129 typename R, 130 BOOST_SIGNALS_TEMPLATE_PARMS 131 BOOST_SIGNALS_COMMA_IF_NONZERO_ARGS 132 typename Combiner = last_value<R>, 133 typename Group = int, 134 typename GroupCompare = std::less<Group>, 135 typename SlotFunction = BOOST_SIGNALS_FUNCTION< 136 R BOOST_SIGNALS_COMMA_IF_NONZERO_ARGS 137 BOOST_SIGNALS_TEMPLATE_ARGS> 138 > 139 class BOOST_SIGNALS_SIGNAL : 140 public BOOST_SIGNALS_NAMESPACE::detail::signal_base, // management of slot list 141 public BOOST_SIGNALS_NAMESPACE::trackable // signals are trackable 142 { 143 public: 144 // The slot function type 145 typedef SlotFunction slot_function_type; 146 147 // Result type of a slot 148 typedef typename BOOST_SIGNALS_NAMESPACE::detail::slot_result_type<R>::type 149 slot_result_type; 150 151 // Argument types 152 BOOST_SIGNALS_ARG_TYPES 153 154 #if BOOST_SIGNALS_NUM_ARGS == 1 155 typedef T1 argument_type; 156 #elif BOOST_SIGNALS_NUM_ARGS == 2 157 typedef T1 first_argument_type; 158 typedef T2 second_argument_type; 159 #endif 160 161 private: 162 // The real slot name comparison object type 163 typedef BOOST_SIGNALS_NAMESPACE::detail::group_bridge_compare<GroupCompare, Group> 164 real_group_compare_type; 165 166 // The function object passed to the slot call iterator that will call 167 // the underlying slot function with its arguments bound 168 typedef BOOST_SIGNALS_NAMESPACE::detail::BOOST_SIGNALS_CALL_BOUND<R> 169 outer_bound_slot_caller; 170 typedef typename outer_bound_slot_caller::template 171 caller<BOOST_SIGNALS_TEMPLATE_ARGS 172 BOOST_SIGNALS_COMMA_IF_NONZERO_ARGS 173 slot_function_type> 174 call_bound_slot; 175 176 public: 177 // Combiner's result type 178 typedef typename Combiner::result_type result_type; 179 180 // Combiner type 181 typedef Combiner combiner_type; 182 183 // Slot type 184 typedef slot<slot_function_type> slot_type; 185 186 // Slot name type and comparison 187 typedef Group group_type; 188 typedef GroupCompare group_compare_type; 189 190 typedef BOOST_SIGNALS_NAMESPACE::detail::slot_call_iterator< 191 call_bound_slot, iterator> slot_call_iterator; 192 193 explicit BOOST_SIGNALS_SIGNAL(const Combiner & c=Combiner (),const GroupCompare & comp=GroupCompare ())194 BOOST_SIGNALS_SIGNAL(const Combiner& c = Combiner(), 195 const GroupCompare& comp = GroupCompare()) : 196 BOOST_SIGNALS_NAMESPACE::detail::signal_base(real_group_compare_type(comp), 197 c) 198 { 199 } 200 201 // Connect a slot to this signal 202 BOOST_SIGNALS_NAMESPACE::connection 203 connect(const slot_type&, 204 BOOST_SIGNALS_NAMESPACE::connect_position at 205 = BOOST_SIGNALS_NAMESPACE::at_back); 206 207 208 BOOST_SIGNALS_NAMESPACE::connection 209 connect(const group_type&, const slot_type&, 210 BOOST_SIGNALS_NAMESPACE::connect_position at 211 = BOOST_SIGNALS_NAMESPACE::at_back); 212 213 #if BOOST_WORKAROUND(BOOST_MSVC, <= 0x1700) 214 // MSVC 6.0 and 7.0 don't handle the is_convertible test well disconnect(const group_type & group)215 void disconnect(const group_type& group) 216 { 217 impl->disconnect(group); 218 } 219 #else 220 template<typename T> disconnect(const T & t)221 void disconnect(const T& t) 222 { 223 typedef mpl::bool_<(is_convertible<T, group_type>::value)> is_group; 224 this->do_disconnect(t, is_group()); 225 } 226 227 private: 228 // Disconnect a named slot do_disconnect(const group_type & group,mpl::bool_<true>)229 void do_disconnect(const group_type& group, mpl::bool_<true>) 230 { 231 impl->disconnect(group); 232 } 233 234 template<typename Function> do_disconnect(const Function & f,mpl::bool_<false>)235 void do_disconnect(const Function& f, mpl::bool_<false>) 236 { 237 // Notify the slot handling code that we are iterating through the slots 238 BOOST_SIGNALS_NAMESPACE::detail::call_notification notification(this->impl); 239 240 for (iterator i = impl->slots_.begin(); i != impl->slots_.end(); ++i) { 241 slot_function_type& s = *unsafe_any_cast<slot_function_type>(&i->second); 242 if (s == f) i->first.disconnect(); 243 } 244 } 245 #endif 246 247 public: 248 249 // Emit the signal 250 result_type operator()(BOOST_SIGNALS_PARMS); 251 result_type operator()(BOOST_SIGNALS_PARMS) const; 252 combiner()253 Combiner& combiner() 254 { return *unsafe_any_cast<Combiner>(&impl->combiner_); } 255 combiner() const256 const Combiner& combiner() const 257 { return *unsafe_any_cast<const Combiner>(&impl->combiner_); } 258 }; 259 260 template< 261 typename R, 262 BOOST_SIGNALS_TEMPLATE_PARMS 263 BOOST_SIGNALS_COMMA_IF_NONZERO_ARGS 264 typename Combiner, 265 typename Group, 266 typename GroupCompare, 267 typename SlotFunction 268 > 269 BOOST_SIGNALS_NAMESPACE::connection 270 BOOST_SIGNALS_SIGNAL< 271 R, BOOST_SIGNALS_TEMPLATE_ARGS 272 BOOST_SIGNALS_COMMA_IF_NONZERO_ARGS 273 Combiner, Group, GroupCompare, SlotFunction connect(const slot_type & in_slot,BOOST_SIGNALS_NAMESPACE::connect_position at)274 >::connect(const slot_type& in_slot, 275 BOOST_SIGNALS_NAMESPACE::connect_position at) 276 { 277 using boost::BOOST_SIGNALS_NAMESPACE::detail::stored_group; 278 279 // If the slot has been disconnected, just return a disconnected 280 // connection 281 if (!in_slot.is_active()) { 282 return BOOST_SIGNALS_NAMESPACE::connection(); 283 } 284 285 return impl->connect_slot(in_slot.get_slot_function(), stored_group(), 286 in_slot.get_data(), at); 287 } 288 289 template< 290 typename R, 291 BOOST_SIGNALS_TEMPLATE_PARMS 292 BOOST_SIGNALS_COMMA_IF_NONZERO_ARGS 293 typename Combiner, 294 typename Group, 295 typename GroupCompare, 296 typename SlotFunction 297 > 298 BOOST_SIGNALS_NAMESPACE::connection 299 BOOST_SIGNALS_SIGNAL< 300 R, BOOST_SIGNALS_TEMPLATE_ARGS 301 BOOST_SIGNALS_COMMA_IF_NONZERO_ARGS 302 Combiner, Group, GroupCompare, SlotFunction connect(const group_type & group,const slot_type & in_slot,BOOST_SIGNALS_NAMESPACE::connect_position at)303 >::connect(const group_type& group, 304 const slot_type& in_slot, 305 BOOST_SIGNALS_NAMESPACE::connect_position at) 306 { 307 // If the slot has been disconnected, just return a disconnected 308 // connection 309 if (!in_slot.is_active()) { 310 return BOOST_SIGNALS_NAMESPACE::connection(); 311 } 312 313 return impl->connect_slot(in_slot.get_slot_function(), group, 314 in_slot.get_data(), at); 315 } 316 317 template< 318 typename R, 319 BOOST_SIGNALS_TEMPLATE_PARMS 320 BOOST_SIGNALS_COMMA_IF_NONZERO_ARGS 321 typename Combiner, 322 typename Group, 323 typename GroupCompare, 324 typename SlotFunction 325 > 326 typename BOOST_SIGNALS_SIGNAL< 327 R, BOOST_SIGNALS_TEMPLATE_ARGS 328 BOOST_SIGNALS_COMMA_IF_NONZERO_ARGS 329 Combiner, Group, GroupCompare, SlotFunction>::result_type 330 BOOST_SIGNALS_SIGNAL< 331 R, BOOST_SIGNALS_TEMPLATE_ARGS 332 BOOST_SIGNALS_COMMA_IF_NONZERO_ARGS 333 Combiner, Group, GroupCompare, SlotFunction operator ()(BOOST_SIGNALS_PARMS)334 >::operator()(BOOST_SIGNALS_PARMS) 335 { 336 // Notify the slot handling code that we are making a call 337 BOOST_SIGNALS_NAMESPACE::detail::call_notification notification(this->impl); 338 339 // Construct a function object that will call the underlying slots 340 // with the given arguments. 341 #if BOOST_SIGNALS_NUM_ARGS == 0 342 BOOST_SIGNALS_ARGS_STRUCT_INST args; 343 #else 344 BOOST_SIGNALS_ARGS_STRUCT_INST args(BOOST_SIGNALS_ARGS); 345 #endif // BOOST_SIGNALS_NUM_ARGS > 0 346 call_bound_slot f(&args); 347 348 typedef typename call_bound_slot::result_type result_type; 349 optional<result_type> cache; 350 // Let the combiner call the slots via a pair of input iterators 351 return combiner()(slot_call_iterator(notification.impl->slots_.begin(), 352 impl->slots_.end(), f, cache), 353 slot_call_iterator(notification.impl->slots_.end(), 354 impl->slots_.end(), f, cache)); 355 } 356 357 template< 358 typename R, 359 BOOST_SIGNALS_TEMPLATE_PARMS 360 BOOST_SIGNALS_COMMA_IF_NONZERO_ARGS 361 typename Combiner, 362 typename Group, 363 typename GroupCompare, 364 typename SlotFunction 365 > 366 typename BOOST_SIGNALS_SIGNAL< 367 R, BOOST_SIGNALS_TEMPLATE_ARGS 368 BOOST_SIGNALS_COMMA_IF_NONZERO_ARGS 369 Combiner, Group, GroupCompare, SlotFunction>::result_type 370 BOOST_SIGNALS_SIGNAL< 371 R, BOOST_SIGNALS_TEMPLATE_ARGS 372 BOOST_SIGNALS_COMMA_IF_NONZERO_ARGS 373 Combiner, Group, GroupCompare, SlotFunction operator ()(BOOST_SIGNALS_PARMS) const374 >::operator()(BOOST_SIGNALS_PARMS) const 375 { 376 // Notify the slot handling code that we are making a call 377 BOOST_SIGNALS_NAMESPACE::detail::call_notification notification(this->impl); 378 379 // Construct a function object that will call the underlying slots 380 // with the given arguments. 381 #if BOOST_SIGNALS_NUM_ARGS == 0 382 BOOST_SIGNALS_ARGS_STRUCT_INST args; 383 #else 384 BOOST_SIGNALS_ARGS_STRUCT_INST args(BOOST_SIGNALS_ARGS); 385 #endif // BOOST_SIGNALS_NUM_ARGS > 0 386 387 call_bound_slot f(&args); 388 389 typedef typename call_bound_slot::result_type result_type; 390 optional<result_type> cache; 391 392 // Let the combiner call the slots via a pair of input iterators 393 return combiner()(slot_call_iterator(notification.impl->slots_.begin(), 394 impl->slots_.end(), f, cache), 395 slot_call_iterator(notification.impl->slots_.end(), 396 impl->slots_.end(), f, cache)); 397 } 398 } // namespace boost 399 400 #undef BOOST_SIGNAL_FUNCTION_N_HEADER 401 #undef BOOST_SIGNALS_ARGS_STRUCT_INST 402 #undef BOOST_SIGNALS_CALL_BOUND 403 #undef BOOST_SIGNALS_ARGS_STRUCT 404 #undef BOOST_SIGNALS_FUNCTION 405 #undef BOOST_SIGNALS_SIGNAL 406 #undef BOOST_SIGNALS_COMMA_IF_NONZERO_ARGS 407 408 #ifdef BOOST_HAS_ABI_HEADERS 409 # include BOOST_ABI_SUFFIX 410 #endif 411