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