OLD | NEW |
1 // sigslot.h: Signal/Slot classes | 1 // sigslot.h: Signal/Slot classes |
2 // | 2 // |
3 // Written by Sarah Thompson (sarah@telergy.com) 2002. | 3 // Written by Sarah Thompson (sarah@telergy.com) 2002. |
4 // | 4 // |
5 // License: Public domain. You are free to use this code however you like, with
the proviso that | 5 // License: Public domain. You are free to use this code however you like, with
the proviso that |
6 // the author takes on no responsibility or liability for any use. | 6 // the author takes on no responsibility or liability for any use. |
7 // | 7 // |
8 // QUICK DOCUMENTATION | 8 // QUICK DOCUMENTATION |
9 // | 9 // |
10 // (see also the full documentation at http://sigsl
ot.sourceforge.net/) | 10 // (see also the full documentation at http://sigsl
ot.sourceforge.net/) |
(...skipping 376 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
387 (static_cast< DestT* >(self->pdest)->*(pm))(args...); | 387 (static_cast< DestT* >(self->pdest)->*(pm))(args...); |
388 } | 388 } |
389 }; | 389 }; |
390 | 390 |
391 template<class mt_policy> | 391 template<class mt_policy> |
392 class _signal_base : public _signal_base_interface, public mt_policy | 392 class _signal_base : public _signal_base_interface, public mt_policy |
393 { | 393 { |
394 protected: | 394 protected: |
395 typedef std::list< _opaque_connection > connections_list; | 395 typedef std::list< _opaque_connection > connections_list; |
396 | 396 |
397 » » _signal_base() : _signal_base_interface(&_signal_base::do_slot_d
isconnect, &_signal_base::do_slot_duplicate) | 397 » » _signal_base() : _signal_base_interface(&_signal_base::do_slot_d
isconnect, &_signal_base::do_slot_duplicate), |
| 398 m_current_iterator(m_connected_slots.end()) |
398 { | 399 { |
399 } | 400 } |
400 | 401 |
401 ~_signal_base() | 402 ~_signal_base() |
402 { | 403 { |
403 disconnect_all(); | 404 disconnect_all(); |
404 } | 405 } |
405 | 406 |
406 private: | 407 private: |
407 _signal_base& operator= (_signal_base const& that); | 408 _signal_base& operator= (_signal_base const& that); |
408 | 409 |
409 public: | 410 public: |
410 » » _signal_base(const _signal_base& o) : _signal_base_interface(&_s
ignal_base::do_slot_disconnect, &_signal_base::do_slot_duplicate) { | 411 » » _signal_base(const _signal_base& o) : _signal_base_interface(&_s
ignal_base::do_slot_disconnect, &_signal_base::do_slot_duplicate), |
| 412 m_current_iterator(m_connected_slots.end()) { |
411 lock_block<mt_policy> lock(this); | 413 lock_block<mt_policy> lock(this); |
412 for (const auto& connection : o.m_connected_slots) | 414 for (const auto& connection : o.m_connected_slots) |
413 { | 415 { |
414 connection.getdest()->signal_connect(this); | 416 connection.getdest()->signal_connect(this); |
415 m_connected_slots.push_back(connection); | 417 m_connected_slots.push_back(connection); |
416 } | 418 } |
417 } | 419 } |
418 | 420 |
419 bool is_empty() | 421 bool is_empty() |
420 { | 422 { |
421 lock_block<mt_policy> lock(this); | 423 lock_block<mt_policy> lock(this); |
422 return m_connected_slots.empty(); | 424 return m_connected_slots.empty(); |
423 } | 425 } |
424 | 426 |
425 void disconnect_all() | 427 void disconnect_all() |
426 { | 428 { |
427 lock_block<mt_policy> lock(this); | 429 lock_block<mt_policy> lock(this); |
428 | 430 |
429 while(!m_connected_slots.empty()) | 431 while(!m_connected_slots.empty()) |
430 { | 432 { |
431 has_slots_interface* pdest = m_connected_slots.f
ront().getdest(); | 433 has_slots_interface* pdest = m_connected_slots.f
ront().getdest(); |
432 m_connected_slots.pop_front(); | 434 m_connected_slots.pop_front(); |
433 pdest->signal_disconnect(static_cast< _signal_ba
se_interface* >(this)); | 435 pdest->signal_disconnect(static_cast< _signal_ba
se_interface* >(this)); |
434 } | 436 } |
| 437 // If disconnect_all is called while the signal is firing, advance the |
| 438 // current slot iterator to the end to avoid an invalidated iterator from |
| 439 // being dereferenced. |
| 440 m_current_iterator = m_connected_slots.end(); |
435 } | 441 } |
436 | 442 |
437 #if !defined(NDEBUG) | 443 #if !defined(NDEBUG) |
438 bool connected(has_slots_interface* pclass) | 444 bool connected(has_slots_interface* pclass) |
439 { | 445 { |
440 lock_block<mt_policy> lock(this); | 446 lock_block<mt_policy> lock(this); |
441 connections_list::const_iterator it = m_connected_slots.
begin(); | 447 connections_list::const_iterator it = m_connected_slots.
begin(); |
442 connections_list::const_iterator itEnd = m_connected_slo
ts.end(); | 448 connections_list::const_iterator itEnd = m_connected_slo
ts.end(); |
443 while(it != itEnd) | 449 while(it != itEnd) |
444 { | 450 { |
445 if (it->getdest() == pclass) | 451 if (it->getdest() == pclass) |
446 return true; | 452 return true; |
447 ++it; | 453 ++it; |
448 } | 454 } |
449 return false; | 455 return false; |
450 } | 456 } |
451 #endif | 457 #endif |
452 | 458 |
453 void disconnect(has_slots_interface* pclass) | 459 void disconnect(has_slots_interface* pclass) |
454 { | 460 { |
455 lock_block<mt_policy> lock(this); | 461 lock_block<mt_policy> lock(this); |
456 connections_list::iterator it = m_connected_slots.begin(
); | 462 connections_list::iterator it = m_connected_slots.begin(
); |
457 connections_list::iterator itEnd = m_connected_slots.end
(); | 463 connections_list::iterator itEnd = m_connected_slots.end
(); |
458 | 464 |
459 while(it != itEnd) | 465 while(it != itEnd) |
460 { | 466 { |
461 if(it->getdest() == pclass) | 467 if(it->getdest() == pclass) |
462 { | 468 { |
463 » » » » » m_connected_slots.erase(it); | 469 // If we're currently using this iterator because the signal is |
| 470 // firing, advance it to avoid it being invalidated. |
| 471 if (m_current_iterator == it) { |
| 472 m_current_iterator = m_connected_slots.erase(it); |
| 473 } else { |
| 474 m_connected_slots.erase(it); |
| 475 } |
464 pclass->signal_disconnect(static_cast< _
signal_base_interface* >(this)); | 476 pclass->signal_disconnect(static_cast< _
signal_base_interface* >(this)); |
465 return; | 477 return; |
466 } | 478 } |
467 | 479 |
468 ++it; | 480 ++it; |
469 } | 481 } |
470 } | 482 } |
471 | 483 |
472 private: | 484 private: |
473 static void do_slot_disconnect(_signal_base_interface* p, has_sl
ots_interface* pslot) | 485 static void do_slot_disconnect(_signal_base_interface* p, has_sl
ots_interface* pslot) |
474 { | 486 { |
475 _signal_base* const self = static_cast< _signal_base* >(
p); | 487 _signal_base* const self = static_cast< _signal_base* >(
p); |
476 lock_block<mt_policy> lock(self); | 488 lock_block<mt_policy> lock(self); |
477 connections_list::iterator it = self->m_connected_slots.
begin(); | 489 connections_list::iterator it = self->m_connected_slots.
begin(); |
478 connections_list::iterator itEnd = self->m_connected_slo
ts.end(); | 490 connections_list::iterator itEnd = self->m_connected_slo
ts.end(); |
479 | 491 |
480 while(it != itEnd) | 492 while(it != itEnd) |
481 { | 493 { |
482 connections_list::iterator itNext = it; | 494 connections_list::iterator itNext = it; |
483 ++itNext; | 495 ++itNext; |
484 | 496 |
485 if(it->getdest() == pslot) | 497 if(it->getdest() == pslot) |
486 { | 498 { |
487 » » » » » self->m_connected_slots.erase(it); | 499 // If we're currently using this iterator because the signal is |
488 » » » » } | 500 // firing, advance it to avoid it being invalidated. |
| 501 if (self->m_current_iterator == it) { |
| 502 self->m_current_iterator = self->m_connected_slots.erase(it); |
| 503 } else { |
| 504 self->m_connected_slots.erase(it); |
| 505 } |
| 506 } |
489 | 507 |
490 it = itNext; | 508 it = itNext; |
491 } | 509 } |
492 } | 510 } |
493 | 511 |
494 static void do_slot_duplicate(_signal_base_interface* p, const h
as_slots_interface* oldtarget, has_slots_interface* newtarget) | 512 static void do_slot_duplicate(_signal_base_interface* p, const h
as_slots_interface* oldtarget, has_slots_interface* newtarget) |
495 { | 513 { |
496 _signal_base* const self = static_cast< _signal_base* >(
p); | 514 _signal_base* const self = static_cast< _signal_base* >(
p); |
497 lock_block<mt_policy> lock(self); | 515 lock_block<mt_policy> lock(self); |
498 connections_list::iterator it = self->m_connected_slots.
begin(); | 516 connections_list::iterator it = self->m_connected_slots.
begin(); |
499 connections_list::iterator itEnd = self->m_connected_slo
ts.end(); | 517 connections_list::iterator itEnd = self->m_connected_slo
ts.end(); |
500 | 518 |
501 while(it != itEnd) | 519 while(it != itEnd) |
502 { | 520 { |
503 if(it->getdest() == oldtarget) | 521 if(it->getdest() == oldtarget) |
504 { | 522 { |
505 self->m_connected_slots.push_back(it->du
plicate(newtarget)); | 523 self->m_connected_slots.push_back(it->du
plicate(newtarget)); |
506 } | 524 } |
507 | 525 |
508 ++it; | 526 ++it; |
509 } | 527 } |
510 } | 528 } |
511 | 529 |
512 protected: | 530 protected: |
513 connections_list m_connected_slots; | 531 connections_list m_connected_slots; |
514 » }; | 532 |
| 533 // Used to handle a slot being disconnected while a signal is |
| 534 // firing (iterating m_connected_slots). |
| 535 connections_list::iterator m_current_iterator; |
| 536 }; |
515 | 537 |
516 template<class mt_policy = SIGSLOT_DEFAULT_MT_POLICY> | 538 template<class mt_policy = SIGSLOT_DEFAULT_MT_POLICY> |
517 class has_slots : public has_slots_interface, public mt_policy | 539 class has_slots : public has_slots_interface, public mt_policy |
518 { | 540 { |
519 private: | 541 private: |
520 typedef std::set< _signal_base_interface* > sender_set; | 542 typedef std::set< _signal_base_interface* > sender_set; |
521 typedef sender_set::const_iterator const_iterator; | 543 typedef sender_set::const_iterator const_iterator; |
522 | 544 |
523 public: | 545 public: |
524 has_slots() : has_slots_interface(&has_slots::do_signal_connect,
&has_slots::do_signal_disconnect, &has_slots::do_disconnect_all) | 546 has_slots() : has_slots_interface(&has_slots::do_signal_connect,
&has_slots::do_signal_disconnect, &has_slots::do_disconnect_all) |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
598 void connect(desttype* pclass, void (desttype::*pmemfun)(Args...
)) | 620 void connect(desttype* pclass, void (desttype::*pmemfun)(Args...
)) |
599 { | 621 { |
600 lock_block<mt_policy> lock(this); | 622 lock_block<mt_policy> lock(this); |
601 this->m_connected_slots.push_back(_opaque_connection(pcl
ass, pmemfun)); | 623 this->m_connected_slots.push_back(_opaque_connection(pcl
ass, pmemfun)); |
602 pclass->signal_connect(static_cast< _signal_base_interfa
ce* >(this)); | 624 pclass->signal_connect(static_cast< _signal_base_interfa
ce* >(this)); |
603 } | 625 } |
604 | 626 |
605 void emit(Args... args) | 627 void emit(Args... args) |
606 { | 628 { |
607 lock_block<mt_policy> lock(this); | 629 lock_block<mt_policy> lock(this); |
608 » » » typename connections_list::const_iterator it = this->m_c
onnected_slots.begin(); | 630 this->m_current_iterator = |
609 » » » typename connections_list::const_iterator itEnd = this->
m_connected_slots.end(); | 631 this->m_connected_slots.begin(); |
610 | 632 while (this->m_current_iterator != |
611 » » » while(it != itEnd) | 633 this->m_connected_slots.end()) { |
612 » » » { | 634 _opaque_connection const& conn = |
613 » » » » _opaque_connection const& conn = *it; | 635 *this->m_current_iterator; |
614 » » » » ++it; | 636 ++(this->m_current_iterator); |
615 | 637 conn.emit<Args...>(args...); |
616 » » » » conn.emit<Args...>(args...); | 638 } |
617 » » » } | |
618 } | 639 } |
619 | 640 |
620 void operator()(Args... args) | 641 void operator()(Args... args) |
621 { | 642 { |
622 emit(args...); | 643 emit(args...); |
623 } | 644 } |
624 }; | 645 }; |
625 | 646 |
626 // Alias with default thread policy. Needed because both default argumen
ts | 647 // Alias with default thread policy. Needed because both default argumen
ts |
627 // and variadic template arguments must go at the end of the list, so we | 648 // and variadic template arguments must go at the end of the list, so we |
(...skipping 28 matching lines...) Expand all Loading... |
656 | 677 |
657 template<typename A1, typename A2, typename A3, typename A4, typename A5
, typename A6, typename A7, typename mt_policy = SIGSLOT_DEFAULT_MT_POLICY> | 678 template<typename A1, typename A2, typename A3, typename A4, typename A5
, typename A6, typename A7, typename mt_policy = SIGSLOT_DEFAULT_MT_POLICY> |
658 using signal7 = signal_with_thread_policy<mt_policy, A1, A2, A3, A4, A5,
A6, A7>; | 679 using signal7 = signal_with_thread_policy<mt_policy, A1, A2, A3, A4, A5,
A6, A7>; |
659 | 680 |
660 template<typename A1, typename A2, typename A3, typename A4, typename A5
, typename A6, typename A7, typename A8, typename mt_policy = SIGSLOT_DEFAULT_MT
_POLICY> | 681 template<typename A1, typename A2, typename A3, typename A4, typename A5
, typename A6, typename A7, typename A8, typename mt_policy = SIGSLOT_DEFAULT_MT
_POLICY> |
661 using signal8 = signal_with_thread_policy<mt_policy, A1, A2, A3, A4, A5,
A6, A7, A8>; | 682 using signal8 = signal_with_thread_policy<mt_policy, A1, A2, A3, A4, A5,
A6, A7, A8>; |
662 | 683 |
663 } // namespace sigslot | 684 } // namespace sigslot |
664 | 685 |
665 #endif // WEBRTC_BASE_SIGSLOT_H__ | 686 #endif // WEBRTC_BASE_SIGSLOT_H__ |
OLD | NEW |