1 /* 2 Template for Signa1, Signal2, ... classes that support signals 3 with 1, 2, ... parameters 4 5 Begin: 2007-01-23 6 */ 7 // Copyright Frank Mori Hess 2007-2008 8 // 9 // Use, modification and 10 // distribution is subject to the Boost Software License, Version 11 // 1.0. (See accompanying file LICENSE_1_0.txt or copy at 12 // http://www.boost.org/LICENSE_1_0.txt) 13 14 // This file is included iteratively, and should not be protected from multiple inclusion 15 16 #ifdef BOOST_NO_CXX11_VARIADIC_TEMPLATES 17 #define BOOST_SIGNALS2_NUM_ARGS BOOST_PP_ITERATION() 18 #else 19 #define BOOST_SIGNALS2_NUM_ARGS 1 20 #endif 21 22 // R, T1, T2, ..., TN, Combiner, Group, GroupCompare, SlotFunction, ExtendedSlotFunction, Mutex 23 #define BOOST_SIGNALS2_SIGNAL_TEMPLATE_INSTANTIATION \ 24 BOOST_SIGNALS2_SIGNATURE_TEMPLATE_INSTANTIATION(BOOST_SIGNALS2_NUM_ARGS), \ 25 Combiner, Group, GroupCompare, SlotFunction, ExtendedSlotFunction, Mutex 26 27 namespace boost 28 { 29 namespace signals2 30 { 31 namespace detail 32 { 33 // helper for bound_extended_slot_function that handles specialization for void return 34 template<typename R> BOOST_SIGNALS2_BOUND_EXTENDED_SLOT_FUNCTION_INVOKER_N(BOOST_SIGNALS2_NUM_ARGS)35 class BOOST_SIGNALS2_BOUND_EXTENDED_SLOT_FUNCTION_INVOKER_N(BOOST_SIGNALS2_NUM_ARGS) 36 { 37 public: 38 typedef R result_type; 39 template<typename ExtendedSlotFunction BOOST_SIGNALS2_PP_COMMA_IF(BOOST_SIGNALS2_NUM_ARGS) 40 BOOST_SIGNALS2_ARGS_TEMPLATE_DECL(BOOST_SIGNALS2_NUM_ARGS)> 41 result_type operator()(ExtendedSlotFunction &func, const connection &conn 42 BOOST_SIGNALS2_PP_COMMA_IF(BOOST_SIGNALS2_NUM_ARGS) 43 BOOST_SIGNALS2_FULL_FORWARD_ARGS(BOOST_SIGNALS2_NUM_ARGS)) const 44 { 45 return func(conn BOOST_SIGNALS2_PP_COMMA_IF(BOOST_SIGNALS2_NUM_ARGS) 46 BOOST_SIGNALS2_FORWARDED_ARGS(BOOST_SIGNALS2_NUM_ARGS)); 47 } 48 }; 49 #ifdef BOOST_NO_VOID_RETURNS 50 template<> 51 class BOOST_SIGNALS2_BOUND_EXTENDED_SLOT_FUNCTION_INVOKER_N(BOOST_SIGNALS2_NUM_ARGS)<void> 52 { 53 public: 54 typedef result_type_wrapper<void>::type result_type; 55 template<typename ExtendedSlotFunction BOOST_SIGNALS2_PP_COMMA_IF(BOOST_SIGNALS2_NUM_ARGS) 56 BOOST_SIGNALS2_ARGS_TEMPLATE_DECL(BOOST_SIGNALS2_NUM_ARGS)> 57 result_type operator()(ExtendedSlotFunction &func, const connection &conn 58 BOOST_SIGNALS2_PP_COMMA_IF(BOOST_SIGNALS2_NUM_ARGS) 59 BOOST_SIGNALS2_FULL_FORWARD_ARGS(BOOST_SIGNALS2_NUM_ARGS)) const 60 { 61 func(conn BOOST_SIGNALS2_PP_COMMA_IF(BOOST_SIGNALS2_NUM_ARGS) 62 BOOST_SIGNALS2_FORWARDED_ARGS(BOOST_SIGNALS2_NUM_ARGS)); 63 return result_type(); 64 } 65 }; 66 #endif 67 // wrapper around an signalN::extended_slot_function which binds the 68 // connection argument so it looks like a normal 69 // signalN::slot_function 70 71 template<typename ExtendedSlotFunction> 72 class BOOST_SIGNALS2_BOUND_EXTENDED_SLOT_FUNCTION_N(BOOST_SIGNALS2_NUM_ARGS) 73 { 74 public: 75 typedef typename result_type_wrapper<typename ExtendedSlotFunction::result_type>::type result_type; 76 BOOST_SIGNALS2_BOUND_EXTENDED_SLOT_FUNCTION_N(BOOST_SIGNALS2_NUM_ARGS)(const ExtendedSlotFunction &fun): 77 _fun(fun), _connection(new connection) 78 {} 79 void set_connection(const connection &conn) 80 { 81 *_connection = conn; 82 } 83 84 #if BOOST_SIGNALS2_NUM_ARGS > 0 85 template<BOOST_SIGNALS2_ARGS_TEMPLATE_DECL(BOOST_SIGNALS2_NUM_ARGS)> 86 #endif // BOOST_SIGNALS2_NUM_ARGS > 0 87 result_type operator()(BOOST_SIGNALS2_FULL_FORWARD_ARGS(BOOST_SIGNALS2_NUM_ARGS)) 88 { 89 return BOOST_SIGNALS2_BOUND_EXTENDED_SLOT_FUNCTION_INVOKER_N(BOOST_SIGNALS2_NUM_ARGS) 90 <typename ExtendedSlotFunction::result_type>() 91 (_fun, *_connection BOOST_SIGNALS2_PP_COMMA_IF(BOOST_SIGNALS2_NUM_ARGS) 92 BOOST_SIGNALS2_FORWARDED_ARGS(BOOST_SIGNALS2_NUM_ARGS)); 93 } 94 // const overload 95 #if BOOST_SIGNALS2_NUM_ARGS > 0 96 template<BOOST_SIGNALS2_ARGS_TEMPLATE_DECL(BOOST_SIGNALS2_NUM_ARGS)> 97 #endif // BOOST_SIGNALS2_NUM_ARGS > 0 98 result_type operator()(BOOST_SIGNALS2_FULL_FORWARD_ARGS(BOOST_SIGNALS2_NUM_ARGS)) const 99 { 100 return BOOST_SIGNALS2_BOUND_EXTENDED_SLOT_FUNCTION_INVOKER_N(BOOST_SIGNALS2_NUM_ARGS) 101 <typename ExtendedSlotFunction::result_type>() 102 (_fun, *_connection BOOST_SIGNALS2_PP_COMMA_IF(BOOST_SIGNALS2_NUM_ARGS) 103 BOOST_SIGNALS2_FORWARDED_ARGS(BOOST_SIGNALS2_NUM_ARGS)); 104 } 105 template<typename T> 106 bool operator==(const T &other) const 107 { 108 return _fun == other; 109 } 110 private: 111 BOOST_SIGNALS2_BOUND_EXTENDED_SLOT_FUNCTION_N(BOOST_SIGNALS2_NUM_ARGS)() 112 {} 113 114 ExtendedSlotFunction _fun; 115 boost::shared_ptr<connection> _connection; 116 }; 117 118 template<BOOST_SIGNALS2_SIGNAL_TEMPLATE_DECL(BOOST_SIGNALS2_NUM_ARGS)> 119 class BOOST_SIGNALS2_SIGNAL_IMPL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS); 120 121 template<BOOST_SIGNALS2_SIGNAL_TEMPLATE_SPECIALIZATION_DECL(BOOST_SIGNALS2_NUM_ARGS)> 122 class BOOST_SIGNALS2_SIGNAL_IMPL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS) BOOST_SIGNALS2_SIGNAL_TEMPLATE_SPECIALIZATION 123 { 124 public: 125 typedef SlotFunction slot_function_type; 126 // typedef slotN<Signature, SlotFunction> slot_type; 127 typedef BOOST_SIGNALS2_SLOT_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS) 128 <BOOST_SIGNALS2_SIGNATURE_TEMPLATE_INSTANTIATION(BOOST_SIGNALS2_NUM_ARGS), 129 slot_function_type> slot_type; 130 typedef ExtendedSlotFunction extended_slot_function_type; 131 // typedef slotN+1<R, const connection &, T1, T2, ..., TN, extended_slot_function_type> extended_slot_type; 132 typedef BOOST_SIGNALS2_EXTENDED_SLOT_TYPE(BOOST_SIGNALS2_NUM_ARGS) extended_slot_type; 133 typedef typename nonvoid<typename slot_function_type::result_type>::type nonvoid_slot_result_type; 134 private: 135 #ifdef BOOST_NO_CXX11_VARIADIC_TEMPLATES 136 class slot_invoker; 137 #else // BOOST_NO_CXX11_VARIADIC_TEMPLATES 138 typedef variadic_slot_invoker<nonvoid_slot_result_type, Args...> slot_invoker; 139 #endif // BOOST_NO_CXX11_VARIADIC_TEMPLATES 140 typedef slot_call_iterator_cache<nonvoid_slot_result_type, slot_invoker> slot_call_iterator_cache_type; 141 typedef typename group_key<Group>::type group_key_type; 142 typedef shared_ptr<connection_body<group_key_type, slot_type, Mutex> > connection_body_type; 143 typedef grouped_list<Group, GroupCompare, connection_body_type> connection_list_type; 144 typedef BOOST_SIGNALS2_BOUND_EXTENDED_SLOT_FUNCTION_N(BOOST_SIGNALS2_NUM_ARGS)<extended_slot_function_type> 145 bound_extended_slot_function_type; 146 public: 147 typedef Combiner combiner_type; 148 typedef typename result_type_wrapper<typename combiner_type::result_type>::type result_type; 149 typedef Group group_type; 150 typedef GroupCompare group_compare_type; 151 typedef typename detail::slot_call_iterator_t<slot_invoker, 152 typename connection_list_type::iterator, connection_body<group_key_type, slot_type, Mutex> > slot_call_iterator; 153 154 BOOST_SIGNALS2_SIGNAL_IMPL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)(const combiner_type &combiner_arg, 155 const group_compare_type &group_compare): 156 _shared_state(new invocation_state(connection_list_type(group_compare), combiner_arg)), 157 _garbage_collector_it(_shared_state->connection_bodies().end()), 158 _mutex(new mutex_type()) 159 {} 160 // connect slot 161 connection connect(const slot_type &slot, connect_position position = at_back) 162 { 163 garbage_collecting_lock<mutex_type> lock(*_mutex); 164 return nolock_connect(lock, slot, position); 165 } 166 connection connect(const group_type &group, 167 const slot_type &slot, connect_position position = at_back) 168 { 169 garbage_collecting_lock<mutex_type> lock(*_mutex); 170 return nolock_connect(lock, group, slot, position); 171 } 172 // connect extended slot 173 connection connect_extended(const extended_slot_type &ext_slot, connect_position position = at_back) 174 { 175 garbage_collecting_lock<mutex_type> lock(*_mutex); 176 bound_extended_slot_function_type bound_slot(ext_slot.slot_function()); 177 slot_type slot = replace_slot_function<slot_type>(ext_slot, bound_slot); 178 connection conn = nolock_connect(lock, slot, position); 179 bound_slot.set_connection(conn); 180 return conn; 181 } 182 connection connect_extended(const group_type &group, 183 const extended_slot_type &ext_slot, connect_position position = at_back) 184 { 185 garbage_collecting_lock<Mutex> lock(*_mutex); 186 bound_extended_slot_function_type bound_slot(ext_slot.slot_function()); 187 slot_type slot = replace_slot_function<slot_type>(ext_slot, bound_slot); 188 connection conn = nolock_connect(lock, group, slot, position); 189 bound_slot.set_connection(conn); 190 return conn; 191 } 192 // disconnect slot(s) 193 void disconnect_all_slots() 194 { 195 shared_ptr<invocation_state> local_state = 196 get_readable_state(); 197 typename connection_list_type::iterator it; 198 for(it = local_state->connection_bodies().begin(); 199 it != local_state->connection_bodies().end(); ++it) 200 { 201 (*it)->disconnect(); 202 } 203 } 204 void disconnect(const group_type &group) 205 { 206 shared_ptr<invocation_state> local_state = 207 get_readable_state(); 208 group_key_type group_key(grouped_slots, group); 209 typename connection_list_type::iterator it; 210 typename connection_list_type::iterator end_it = 211 local_state->connection_bodies().upper_bound(group_key); 212 for(it = local_state->connection_bodies().lower_bound(group_key); 213 it != end_it; ++it) 214 { 215 (*it)->disconnect(); 216 } 217 } 218 template <typename T> 219 void disconnect(const T &slot) 220 { 221 typedef mpl::bool_<(is_convertible<T, group_type>::value)> is_group; 222 do_disconnect(slot, is_group()); 223 } 224 // emit signal 225 result_type operator ()(BOOST_SIGNALS2_SIGNATURE_FULL_ARGS(BOOST_SIGNALS2_NUM_ARGS)) 226 { 227 shared_ptr<invocation_state> local_state; 228 typename connection_list_type::iterator it; 229 { 230 garbage_collecting_lock<mutex_type> list_lock(*_mutex); 231 // only clean up if it is safe to do so 232 if(_shared_state.unique()) 233 nolock_cleanup_connections(list_lock, false, 1); 234 /* Make a local copy of _shared_state while holding mutex, so we are 235 thread safe against the combiner or connection list getting modified 236 during invocation. */ 237 local_state = _shared_state; 238 } 239 slot_invoker invoker = slot_invoker(BOOST_SIGNALS2_SIGNATURE_ARG_NAMES(BOOST_SIGNALS2_NUM_ARGS)); 240 slot_call_iterator_cache_type cache(invoker); 241 invocation_janitor janitor(cache, *this, &local_state->connection_bodies()); 242 return detail::combiner_invoker<typename combiner_type::result_type>() 243 ( 244 local_state->combiner(), 245 slot_call_iterator(local_state->connection_bodies().begin(), local_state->connection_bodies().end(), cache), 246 slot_call_iterator(local_state->connection_bodies().end(), local_state->connection_bodies().end(), cache) 247 ); 248 } 249 result_type operator ()(BOOST_SIGNALS2_SIGNATURE_FULL_ARGS(BOOST_SIGNALS2_NUM_ARGS)) const 250 { 251 shared_ptr<invocation_state> local_state; 252 typename connection_list_type::iterator it; 253 { 254 garbage_collecting_lock<mutex_type> list_lock(*_mutex); 255 // only clean up if it is safe to do so 256 if(_shared_state.unique()) 257 nolock_cleanup_connections(list_lock, false, 1); 258 /* Make a local copy of _shared_state while holding mutex, so we are 259 thread safe against the combiner or connection list getting modified 260 during invocation. */ 261 local_state = _shared_state; 262 } 263 slot_invoker invoker = slot_invoker(BOOST_SIGNALS2_SIGNATURE_ARG_NAMES(BOOST_SIGNALS2_NUM_ARGS)); 264 slot_call_iterator_cache_type cache(invoker); 265 invocation_janitor janitor(cache, *this, &local_state->connection_bodies()); 266 return detail::combiner_invoker<typename combiner_type::result_type>() 267 ( 268 local_state->combiner(), 269 slot_call_iterator(local_state->connection_bodies().begin(), local_state->connection_bodies().end(), cache), 270 slot_call_iterator(local_state->connection_bodies().end(), local_state->connection_bodies().end(), cache) 271 ); 272 } 273 std::size_t num_slots() const 274 { 275 shared_ptr<invocation_state> local_state = 276 get_readable_state(); 277 typename connection_list_type::iterator it; 278 std::size_t count = 0; 279 for(it = local_state->connection_bodies().begin(); 280 it != local_state->connection_bodies().end(); ++it) 281 { 282 if((*it)->connected()) ++count; 283 } 284 return count; 285 } 286 bool empty() const 287 { 288 shared_ptr<invocation_state> local_state = 289 get_readable_state(); 290 typename connection_list_type::iterator it; 291 for(it = local_state->connection_bodies().begin(); 292 it != local_state->connection_bodies().end(); ++it) 293 { 294 if((*it)->connected()) return false; 295 } 296 return true; 297 } 298 combiner_type combiner() const 299 { 300 unique_lock<mutex_type> lock(*_mutex); 301 return _shared_state->combiner(); 302 } 303 void set_combiner(const combiner_type &combiner_arg) 304 { 305 unique_lock<mutex_type> lock(*_mutex); 306 if(_shared_state.unique()) 307 _shared_state->combiner() = combiner_arg; 308 else 309 _shared_state.reset(new invocation_state(*_shared_state, combiner_arg)); 310 } 311 private: 312 typedef Mutex mutex_type; 313 314 // slot_invoker is passed to slot_call_iterator_t to run slots 315 #ifdef BOOST_NO_CXX11_VARIADIC_TEMPLATES 316 class slot_invoker 317 { 318 public: 319 typedef nonvoid_slot_result_type result_type; 320 // typename add_reference<Tn>::type 321 #define BOOST_SIGNALS2_ADD_REF_TYPE(z, n, data) \ 322 typename add_reference<BOOST_PP_CAT(T, BOOST_PP_INC(n))>::type 323 // typename add_reference<Tn>::type argn 324 #define BOOST_SIGNALS2_ADD_REF_ARG(z, n, data) \ 325 BOOST_SIGNALS2_ADD_REF_TYPE(~, n, ~) \ 326 BOOST_SIGNALS2_SIGNATURE_ARG_NAME(~, n, ~) 327 // typename add_reference<T1>::type arg1, typename add_reference<T2>::type arg2, ..., typename add_reference<Tn>::type argn 328 #define BOOST_SIGNALS2_ADD_REF_ARGS(arity) \ 329 BOOST_PP_ENUM(arity, BOOST_SIGNALS2_ADD_REF_ARG, ~) 330 slot_invoker(BOOST_SIGNALS2_ADD_REF_ARGS(BOOST_SIGNALS2_NUM_ARGS)) BOOST_PP_EXPR_IF(BOOST_SIGNALS2_NUM_ARGS, :) 331 #undef BOOST_SIGNALS2_ADD_REF_ARGS 332 333 // m_argn 334 #define BOOST_SIGNALS2_M_ARG_NAME(z, n, data) BOOST_PP_CAT(m_arg, BOOST_PP_INC(n)) 335 // m_argn ( argn ) 336 #define BOOST_SIGNALS2_MISC_STATEMENT(z, n, data) \ 337 BOOST_SIGNALS2_M_ARG_NAME(~, n, ~) ( BOOST_SIGNALS2_SIGNATURE_ARG_NAME(~, n, ~) ) 338 // m_arg1(arg1), m_arg2(arg2), ..., m_argn(argn) 339 BOOST_PP_ENUM(BOOST_SIGNALS2_NUM_ARGS, BOOST_SIGNALS2_MISC_STATEMENT, ~) 340 #undef BOOST_SIGNALS2_MISC_STATEMENT 341 {} 342 result_type operator ()(const connection_body_type &connectionBody) const 343 { 344 return m_invoke<typename slot_type::result_type>(connectionBody); 345 } 346 private: 347 // declare assignment operator private since this class might have reference or const members 348 slot_invoker & operator=(const slot_invoker &); 349 350 #define BOOST_SIGNALS2_ADD_REF_M_ARG_STATEMENT(z, n, data) \ 351 BOOST_SIGNALS2_ADD_REF_TYPE(~, n, ~) BOOST_SIGNALS2_M_ARG_NAME(~, n, ~) ; 352 BOOST_PP_REPEAT(BOOST_SIGNALS2_NUM_ARGS, BOOST_SIGNALS2_ADD_REF_M_ARG_STATEMENT, ~) 353 #undef BOOST_SIGNALS2_ADD_REF_M_ARG_STATEMENT 354 #undef BOOST_SIGNALS2_ADD_REF_ARG 355 #undef BOOST_SIGNALS2_ADD_REF_TYPE 356 357 // m_arg1, m_arg2, ..., m_argn 358 #define BOOST_SIGNALS2_M_ARG_NAMES(arity) BOOST_PP_ENUM(arity, BOOST_SIGNALS2_M_ARG_NAME, ~) 359 template<typename SlotResultType> 360 result_type m_invoke(const connection_body_type &connectionBody, 361 typename boost::enable_if<boost::is_void<SlotResultType> >::type * = 0) const 362 { 363 connectionBody->slot().slot_function()(BOOST_SIGNALS2_M_ARG_NAMES(BOOST_SIGNALS2_NUM_ARGS)); 364 return void_type(); 365 } 366 template<typename SlotResultType> 367 result_type m_invoke(const connection_body_type &connectionBody, 368 typename boost::disable_if<boost::is_void<SlotResultType> >::type * = 0) const 369 { 370 return connectionBody->slot().slot_function()(BOOST_SIGNALS2_M_ARG_NAMES(BOOST_SIGNALS2_NUM_ARGS)); 371 } 372 }; 373 #undef BOOST_SIGNALS2_M_ARG_NAMES 374 #undef BOOST_SIGNALS2_M_ARG_NAME 375 376 #endif // BOOST_NO_CXX11_VARIADIC_TEMPLATES 377 // a struct used to optimize (minimize) the number of shared_ptrs that need to be created 378 // inside operator() 379 class invocation_state 380 { 381 public: 382 invocation_state(const connection_list_type &connections_in, 383 const combiner_type &combiner_in): _connection_bodies(new connection_list_type(connections_in)), 384 _combiner(new combiner_type(combiner_in)) 385 {} 386 invocation_state(const invocation_state &other, const connection_list_type &connections_in): 387 _connection_bodies(new connection_list_type(connections_in)), 388 _combiner(other._combiner) 389 {} 390 invocation_state(const invocation_state &other, const combiner_type &combiner_in): 391 _connection_bodies(other._connection_bodies), 392 _combiner(new combiner_type(combiner_in)) 393 {} 394 connection_list_type & connection_bodies() { return *_connection_bodies; } 395 const connection_list_type & connection_bodies() const { return *_connection_bodies; } 396 combiner_type & combiner() { return *_combiner; } 397 const combiner_type & combiner() const { return *_combiner; } 398 private: 399 invocation_state(const invocation_state &); 400 401 shared_ptr<connection_list_type> _connection_bodies; 402 shared_ptr<combiner_type> _combiner; 403 }; 404 // Destructor of invocation_janitor does some cleanup when a signal invocation completes. 405 // Code can't be put directly in signal's operator() due to complications from void return types. 406 class invocation_janitor: noncopyable 407 { 408 public: 409 typedef BOOST_SIGNALS2_SIGNAL_IMPL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS) signal_type; 410 invocation_janitor 411 ( 412 const slot_call_iterator_cache_type &cache, 413 const signal_type &sig, 414 const connection_list_type *connection_bodies 415 ):_cache(cache), _sig(sig), _connection_bodies(connection_bodies) 416 {} 417 ~invocation_janitor() 418 { 419 // force a full cleanup of disconnected slots if there are too many 420 if(_cache.disconnected_slot_count > _cache.connected_slot_count) 421 { 422 _sig.force_cleanup_connections(_connection_bodies); 423 } 424 } 425 private: 426 const slot_call_iterator_cache_type &_cache; 427 const signal_type &_sig; 428 const connection_list_type *_connection_bodies; 429 }; 430 431 // clean up disconnected connections 432 void nolock_cleanup_connections_from(garbage_collecting_lock<mutex_type> &lock, 433 bool grab_tracked, 434 const typename connection_list_type::iterator &begin, unsigned count = 0) const 435 { 436 BOOST_ASSERT(_shared_state.unique()); 437 typename connection_list_type::iterator it; 438 unsigned i; 439 for(it = begin, i = 0; 440 it != _shared_state->connection_bodies().end() && (count == 0 || i < count); 441 ++i) 442 { 443 bool connected; 444 if(grab_tracked) 445 (*it)->disconnect_expired_slot(lock); 446 connected = (*it)->nolock_nograb_connected(); 447 if(connected == false) 448 { 449 it = _shared_state->connection_bodies().erase((*it)->group_key(), it); 450 }else 451 { 452 ++it; 453 } 454 } 455 _garbage_collector_it = it; 456 } 457 // clean up a few connections in constant time 458 void nolock_cleanup_connections(garbage_collecting_lock<mutex_type> &lock, 459 bool grab_tracked, unsigned count) const 460 { 461 BOOST_ASSERT(_shared_state.unique()); 462 typename connection_list_type::iterator begin; 463 if(_garbage_collector_it == _shared_state->connection_bodies().end()) 464 { 465 begin = _shared_state->connection_bodies().begin(); 466 }else 467 { 468 begin = _garbage_collector_it; 469 } 470 nolock_cleanup_connections_from(lock, grab_tracked, begin, count); 471 } 472 /* Make a new copy of the slot list if it is currently being read somewhere else 473 */ 474 void nolock_force_unique_connection_list(garbage_collecting_lock<mutex_type> &lock) 475 { 476 if(_shared_state.unique() == false) 477 { 478 _shared_state.reset(new invocation_state(*_shared_state, _shared_state->connection_bodies())); 479 nolock_cleanup_connections_from(lock, true, _shared_state->connection_bodies().begin()); 480 }else 481 { 482 /* We need to try and check more than just 1 connection here to avoid corner 483 cases where certain repeated connect/disconnect patterns cause the slot 484 list to grow without limit. */ 485 nolock_cleanup_connections(lock, true, 2); 486 } 487 } 488 // force a full cleanup of the connection list 489 void force_cleanup_connections(const connection_list_type *connection_bodies) const 490 { 491 garbage_collecting_lock<mutex_type> list_lock(*_mutex); 492 // if the connection list passed in as a parameter is no longer in use, 493 // we don't need to do any cleanup. 494 if(&_shared_state->connection_bodies() != connection_bodies) 495 { 496 return; 497 } 498 if(_shared_state.unique() == false) 499 { 500 _shared_state.reset(new invocation_state(*_shared_state, _shared_state->connection_bodies())); 501 } 502 nolock_cleanup_connections_from(list_lock, false, _shared_state->connection_bodies().begin()); 503 } 504 shared_ptr<invocation_state> get_readable_state() const 505 { 506 unique_lock<mutex_type> list_lock(*_mutex); 507 return _shared_state; 508 } 509 connection_body_type create_new_connection(garbage_collecting_lock<mutex_type> &lock, 510 const slot_type &slot) 511 { 512 nolock_force_unique_connection_list(lock); 513 return connection_body_type(new connection_body<group_key_type, slot_type, Mutex>(slot, _mutex)); 514 } 515 void do_disconnect(const group_type &group, mpl::bool_<true> /* is_group */) 516 { 517 disconnect(group); 518 } 519 template<typename T> 520 void do_disconnect(const T &slot, mpl::bool_<false> /* is_group */) 521 { 522 shared_ptr<invocation_state> local_state = 523 get_readable_state(); 524 typename connection_list_type::iterator it; 525 for(it = local_state->connection_bodies().begin(); 526 it != local_state->connection_bodies().end(); ++it) 527 { 528 garbage_collecting_lock<connection_body_base> lock(**it); 529 if((*it)->nolock_nograb_connected() == false) continue; 530 if((*it)->slot().slot_function() == slot) 531 { 532 (*it)->nolock_disconnect(lock); 533 }else 534 { 535 // check for wrapped extended slot 536 bound_extended_slot_function_type *fp; 537 fp = (*it)->slot().slot_function().template target<bound_extended_slot_function_type>(); 538 if(fp && *fp == slot) 539 { 540 (*it)->nolock_disconnect(lock); 541 } 542 } 543 } 544 } 545 // connect slot 546 connection nolock_connect(garbage_collecting_lock<mutex_type> &lock, 547 const slot_type &slot, connect_position position) 548 { 549 connection_body_type newConnectionBody = 550 create_new_connection(lock, slot); 551 group_key_type group_key; 552 if(position == at_back) 553 { 554 group_key.first = back_ungrouped_slots; 555 _shared_state->connection_bodies().push_back(group_key, newConnectionBody); 556 }else 557 { 558 group_key.first = front_ungrouped_slots; 559 _shared_state->connection_bodies().push_front(group_key, newConnectionBody); 560 } 561 newConnectionBody->set_group_key(group_key); 562 return connection(newConnectionBody); 563 } 564 connection nolock_connect(garbage_collecting_lock<mutex_type> &lock, 565 const group_type &group, 566 const slot_type &slot, connect_position position) 567 { 568 connection_body_type newConnectionBody = 569 create_new_connection(lock, slot); 570 // update map to first connection body in group if needed 571 group_key_type group_key(grouped_slots, group); 572 newConnectionBody->set_group_key(group_key); 573 if(position == at_back) 574 { 575 _shared_state->connection_bodies().push_back(group_key, newConnectionBody); 576 }else // at_front 577 { 578 _shared_state->connection_bodies().push_front(group_key, newConnectionBody); 579 } 580 return connection(newConnectionBody); 581 } 582 583 // _shared_state is mutable so we can do force_cleanup_connections during a const invocation 584 mutable shared_ptr<invocation_state> _shared_state; 585 mutable typename connection_list_type::iterator _garbage_collector_it; 586 // connection list mutex must never be locked when attempting a blocking lock on a slot, 587 // or you could deadlock. 588 const boost::shared_ptr<mutex_type> _mutex; 589 }; 590 591 template<BOOST_SIGNALS2_SIGNAL_TEMPLATE_DECL(BOOST_SIGNALS2_NUM_ARGS)> 592 class BOOST_SIGNALS2_WEAK_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS); 593 } 594 595 template<BOOST_SIGNALS2_SIGNAL_TEMPLATE_DEFAULTED_DECL(BOOST_SIGNALS2_NUM_ARGS)> 596 class BOOST_SIGNALS2_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS); 597 598 template<BOOST_SIGNALS2_SIGNAL_TEMPLATE_SPECIALIZATION_DECL(BOOST_SIGNALS2_NUM_ARGS)> 599 class BOOST_SIGNALS2_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS) 600 BOOST_SIGNALS2_SIGNAL_TEMPLATE_SPECIALIZATION: public signal_base, 601 public detail::BOOST_SIGNALS2_STD_FUNCTIONAL_BASE 602 { 603 typedef detail::BOOST_SIGNALS2_SIGNAL_IMPL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS) 604 <BOOST_SIGNALS2_SIGNAL_TEMPLATE_INSTANTIATION> impl_class; 605 public: 606 typedef detail::BOOST_SIGNALS2_WEAK_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS) 607 <BOOST_SIGNALS2_SIGNAL_TEMPLATE_INSTANTIATION> weak_signal_type; 608 friend class detail::BOOST_SIGNALS2_WEAK_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS) 609 <BOOST_SIGNALS2_SIGNAL_TEMPLATE_INSTANTIATION>; 610 611 typedef SlotFunction slot_function_type; 612 // typedef slotN<Signature, SlotFunction> slot_type; 613 typedef typename impl_class::slot_type slot_type; 614 typedef typename impl_class::extended_slot_function_type extended_slot_function_type; 615 typedef typename impl_class::extended_slot_type extended_slot_type; 616 typedef typename slot_function_type::result_type slot_result_type; 617 typedef Combiner combiner_type; 618 typedef typename impl_class::result_type result_type; 619 typedef Group group_type; 620 typedef GroupCompare group_compare_type; 621 typedef typename impl_class::slot_call_iterator 622 slot_call_iterator; 623 typedef typename mpl::identity<BOOST_SIGNALS2_SIGNATURE_FUNCTION_TYPE(BOOST_SIGNALS2_NUM_ARGS)>::type signature_type; 624 625 #ifdef BOOST_NO_CXX11_VARIADIC_TEMPLATES 626 627 // typedef Tn argn_type; 628 #define BOOST_SIGNALS2_MISC_STATEMENT(z, n, data) \ 629 typedef BOOST_PP_CAT(T, BOOST_PP_INC(n)) BOOST_PP_CAT(BOOST_PP_CAT(arg, BOOST_PP_INC(n)), _type); 630 BOOST_PP_REPEAT(BOOST_SIGNALS2_NUM_ARGS, BOOST_SIGNALS2_MISC_STATEMENT, ~) 631 #undef BOOST_SIGNALS2_MISC_STATEMENT 632 #if BOOST_SIGNALS2_NUM_ARGS == 1 633 typedef arg1_type argument_type; 634 #elif BOOST_SIGNALS2_NUM_ARGS == 2 635 typedef arg1_type first_argument_type; 636 typedef arg2_type second_argument_type; 637 #endif 638 639 template<unsigned n> class arg : public 640 detail::BOOST_SIGNALS2_PREPROCESSED_ARG_N_TYPE_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS) 641 <n BOOST_SIGNALS2_PP_COMMA_IF(BOOST_SIGNALS2_NUM_ARGS) 642 BOOST_SIGNALS2_ARGS_TEMPLATE_INSTANTIATION(BOOST_SIGNALS2_NUM_ARGS)> 643 {}; 644 645 BOOST_STATIC_CONSTANT(int, arity = BOOST_SIGNALS2_NUM_ARGS); 646 647 #else // BOOST_NO_CXX11_VARIADIC_TEMPLATES 648 649 template<unsigned n> class arg 650 { 651 public: 652 typedef typename detail::variadic_arg_type<n, Args...>::type type; 653 }; 654 BOOST_STATIC_CONSTANT(int, arity = sizeof...(Args)); 655 656 #endif // BOOST_NO_CXX11_VARIADIC_TEMPLATES 657 658 BOOST_SIGNALS2_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)(const combiner_type &combiner_arg = combiner_type(), 659 const group_compare_type &group_compare = group_compare_type()): 660 _pimpl(new impl_class(combiner_arg, group_compare)) 661 {} 662 virtual ~BOOST_SIGNALS2_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)() 663 { 664 } 665 666 //move support 667 #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) 668 BOOST_SIGNALS2_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)( 669 BOOST_SIGNALS2_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS) && other) BOOST_NOEXCEPT 670 { 671 using std::swap; 672 swap(_pimpl, other._pimpl); 673 } 674 675 BOOST_SIGNALS2_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS) & 676 operator=(BOOST_SIGNALS2_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS) && rhs) BOOST_NOEXCEPT 677 { 678 if(this == &rhs) 679 { 680 return *this; 681 } 682 _pimpl.reset(); 683 using std::swap; 684 swap(_pimpl, rhs._pimpl); 685 return *this; 686 } 687 #endif // !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) 688 689 connection connect(const slot_type &slot, connect_position position = at_back) 690 { 691 return (*_pimpl).connect(slot, position); 692 } 693 connection connect(const group_type &group, 694 const slot_type &slot, connect_position position = at_back) 695 { 696 return (*_pimpl).connect(group, slot, position); 697 } 698 connection connect_extended(const extended_slot_type &slot, connect_position position = at_back) 699 { 700 return (*_pimpl).connect_extended(slot, position); 701 } 702 connection connect_extended(const group_type &group, 703 const extended_slot_type &slot, connect_position position = at_back) 704 { 705 return (*_pimpl).connect_extended(group, slot, position); 706 } 707 void disconnect_all_slots() 708 { 709 (*_pimpl).disconnect_all_slots(); 710 } 711 void disconnect(const group_type &group) 712 { 713 (*_pimpl).disconnect(group); 714 } 715 template <typename T> 716 void disconnect(const T &slot) 717 { 718 (*_pimpl).disconnect(slot); 719 } 720 result_type operator ()(BOOST_SIGNALS2_SIGNATURE_FULL_ARGS(BOOST_SIGNALS2_NUM_ARGS)) 721 { 722 return (*_pimpl)(BOOST_SIGNALS2_SIGNATURE_ARG_NAMES(BOOST_SIGNALS2_NUM_ARGS)); 723 } 724 result_type operator ()(BOOST_SIGNALS2_SIGNATURE_FULL_ARGS(BOOST_SIGNALS2_NUM_ARGS)) const 725 { 726 return (*_pimpl)(BOOST_SIGNALS2_SIGNATURE_ARG_NAMES(BOOST_SIGNALS2_NUM_ARGS)); 727 } 728 std::size_t num_slots() const 729 { 730 return (*_pimpl).num_slots(); 731 } 732 bool empty() const 733 { 734 return (*_pimpl).empty(); 735 } 736 combiner_type combiner() const 737 { 738 return (*_pimpl).combiner(); 739 } 740 void set_combiner(const combiner_type &combiner_arg) 741 { 742 return (*_pimpl).set_combiner(combiner_arg); 743 } 744 void swap(BOOST_SIGNALS2_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS) & other) BOOST_NOEXCEPT 745 { 746 using std::swap; 747 swap(_pimpl, other._pimpl); 748 } 749 protected: 750 virtual shared_ptr<void> lock_pimpl() const 751 { 752 return _pimpl; 753 } 754 private: 755 shared_ptr<impl_class> 756 _pimpl; 757 }; 758 759 #ifdef BOOST_NO_CXX11_VARIADIC_TEMPLATES 760 // free swap function for signalN classes, findable by ADL 761 template<BOOST_SIGNALS2_SIGNAL_TEMPLATE_DECL(BOOST_SIGNALS2_NUM_ARGS)> 762 void swap( 763 BOOST_SIGNALS2_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS) <BOOST_SIGNALS2_SIGNAL_TEMPLATE_INSTANTIATION> &sig1, 764 BOOST_SIGNALS2_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS) <BOOST_SIGNALS2_SIGNAL_TEMPLATE_INSTANTIATION> &sig2 ) BOOST_NOEXCEPT 765 { 766 sig1.swap(sig2); 767 } 768 #endif 769 770 namespace detail 771 { 772 // wrapper class for storing other signals as slots with automatic lifetime tracking 773 template<BOOST_SIGNALS2_SIGNAL_TEMPLATE_DECL(BOOST_SIGNALS2_NUM_ARGS)> 774 class BOOST_SIGNALS2_WEAK_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS); 775 776 template<BOOST_SIGNALS2_SIGNAL_TEMPLATE_SPECIALIZATION_DECL(BOOST_SIGNALS2_NUM_ARGS)> 777 class BOOST_SIGNALS2_WEAK_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS) 778 BOOST_SIGNALS2_SIGNAL_TEMPLATE_SPECIALIZATION 779 { 780 public: 781 typedef typename BOOST_SIGNALS2_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS) 782 <BOOST_SIGNALS2_SIGNAL_TEMPLATE_INSTANTIATION>::result_type 783 result_type; 784 785 BOOST_SIGNALS2_WEAK_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS) 786 (const BOOST_SIGNALS2_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS) 787 <BOOST_SIGNALS2_SIGNAL_TEMPLATE_INSTANTIATION> 788 &signal): 789 _weak_pimpl(signal._pimpl) 790 {} 791 result_type operator ()(BOOST_SIGNALS2_SIGNATURE_FULL_ARGS(BOOST_SIGNALS2_NUM_ARGS)) 792 { 793 shared_ptr<detail::BOOST_SIGNALS2_SIGNAL_IMPL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS) 794 <BOOST_SIGNALS2_SIGNAL_TEMPLATE_INSTANTIATION> > 795 shared_pimpl(_weak_pimpl.lock()); 796 return (*shared_pimpl)(BOOST_SIGNALS2_SIGNATURE_ARG_NAMES(BOOST_SIGNALS2_NUM_ARGS)); 797 } 798 result_type operator ()(BOOST_SIGNALS2_SIGNATURE_FULL_ARGS(BOOST_SIGNALS2_NUM_ARGS)) const 799 { 800 shared_ptr<detail::BOOST_SIGNALS2_SIGNAL_IMPL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS) 801 <BOOST_SIGNALS2_SIGNAL_TEMPLATE_INSTANTIATION> > 802 shared_pimpl(_weak_pimpl.lock()); 803 return (*shared_pimpl)(BOOST_SIGNALS2_SIGNATURE_ARG_NAMES(BOOST_SIGNALS2_NUM_ARGS)); 804 } 805 private: 806 boost::weak_ptr<detail::BOOST_SIGNALS2_SIGNAL_IMPL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS) 807 <BOOST_SIGNALS2_SIGNAL_TEMPLATE_INSTANTIATION> > _weak_pimpl; 808 }; 809 810 #ifndef BOOST_NO_CXX11_VARIADIC_TEMPLATES 811 template<int arity, typename Signature> 812 class extended_signature: public variadic_extended_signature<Signature> 813 {}; 814 #else // BOOST_NO_CXX11_VARIADIC_TEMPLATES 815 template<int arity, typename Signature> 816 class extended_signature; 817 // partial template specialization 818 template<typename Signature> 819 class extended_signature<BOOST_SIGNALS2_NUM_ARGS, Signature> 820 { 821 public: 822 // typename function_traits<Signature>::result_type ( 823 // const boost::signals2::connection &, 824 // typename function_traits<Signature>::arg1_type, 825 // typename function_traits<Signature>::arg2_type, 826 // ..., 827 // typename function_traits<Signature>::argn_type) 828 #define BOOST_SIGNALS2_EXT_SIGNATURE(arity, Signature) \ 829 typename function_traits<Signature>::result_type ( \ 830 const boost::signals2::connection & BOOST_SIGNALS2_PP_COMMA_IF(BOOST_SIGNALS2_NUM_ARGS) \ 831 BOOST_PP_ENUM(arity, BOOST_SIGNALS2_SIGNATURE_TO_ARGN_TYPE, Signature) ) 832 typedef function<BOOST_SIGNALS2_EXT_SIGNATURE(BOOST_SIGNALS2_NUM_ARGS, Signature)> function_type; 833 #undef BOOST_SIGNALS2_EXT_SIGNATURE 834 }; 835 836 template<unsigned arity, typename Signature, typename Combiner, 837 typename Group, typename GroupCompare, typename SlotFunction, 838 typename ExtendedSlotFunction, typename Mutex> 839 class signalN; 840 // partial template specialization 841 template<typename Signature, typename Combiner, typename Group, 842 typename GroupCompare, typename SlotFunction, 843 typename ExtendedSlotFunction, typename Mutex> 844 class signalN<BOOST_SIGNALS2_NUM_ARGS, Signature, Combiner, Group, 845 GroupCompare, SlotFunction, ExtendedSlotFunction, Mutex> 846 { 847 public: 848 typedef BOOST_SIGNALS2_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)< 849 BOOST_SIGNALS2_PORTABLE_SIGNATURE(BOOST_SIGNALS2_NUM_ARGS, Signature), 850 Combiner, Group, 851 GroupCompare, SlotFunction, ExtendedSlotFunction, Mutex> type; 852 }; 853 854 #endif // BOOST_NO_CXX11_VARIADIC_TEMPLATES 855 856 } // namespace detail 857 } // namespace signals2 858 } // namespace boost 859 860 #undef BOOST_SIGNALS2_NUM_ARGS 861 #undef BOOST_SIGNALS2_SIGNAL_TEMPLATE_INSTANTIATION 862