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()) | |
399 { | 398 { |
400 } | 399 } |
401 | 400 |
402 ~_signal_base() | 401 ~_signal_base() |
403 { | 402 { |
404 disconnect_all(); | 403 disconnect_all(); |
405 } | 404 } |
406 | 405 |
407 private: | 406 private: |
408 _signal_base& operator= (_signal_base const& that); | 407 _signal_base& operator= (_signal_base const& that); |
409 | 408 |
410 public: | 409 public: |
411 » » _signal_base(const _signal_base& o) : _signal_base_interface(&_s
ignal_base::do_slot_disconnect, &_signal_base::do_slot_duplicate), | 410 » » _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()) { | |
413 lock_block<mt_policy> lock(this); | 411 lock_block<mt_policy> lock(this); |
414 for (const auto& connection : o.m_connected_slots) | 412 for (const auto& connection : o.m_connected_slots) |
415 { | 413 { |
416 connection.getdest()->signal_connect(this); | 414 connection.getdest()->signal_connect(this); |
417 m_connected_slots.push_back(connection); | 415 m_connected_slots.push_back(connection); |
418 } | 416 } |
419 } | 417 } |
420 | 418 |
421 bool is_empty() | 419 bool is_empty() |
422 { | 420 { |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
455 void disconnect(has_slots_interface* pclass) | 453 void disconnect(has_slots_interface* pclass) |
456 { | 454 { |
457 lock_block<mt_policy> lock(this); | 455 lock_block<mt_policy> lock(this); |
458 connections_list::iterator it = m_connected_slots.begin(
); | 456 connections_list::iterator it = m_connected_slots.begin(
); |
459 connections_list::iterator itEnd = m_connected_slots.end
(); | 457 connections_list::iterator itEnd = m_connected_slots.end
(); |
460 | 458 |
461 while(it != itEnd) | 459 while(it != itEnd) |
462 { | 460 { |
463 if(it->getdest() == pclass) | 461 if(it->getdest() == pclass) |
464 { | 462 { |
465 // If we're currently using this iterator, | 463 » » » » » m_connected_slots.erase(it); |
466 // don't erase it and invalidate it yet; set a | |
467 // flag to do so afterwards. | |
468 if (m_current_iterator == it) { | |
469 m_erase_current_iterator = true; | |
470 } else { | |
471 m_connected_slots.erase(it); | |
472 } | |
473 pclass->signal_disconnect(static_cast< _
signal_base_interface* >(this)); | 464 pclass->signal_disconnect(static_cast< _
signal_base_interface* >(this)); |
474 return; | 465 return; |
475 } | 466 } |
476 | 467 |
477 ++it; | 468 ++it; |
478 } | 469 } |
479 } | 470 } |
480 | 471 |
481 private: | 472 private: |
482 static void do_slot_disconnect(_signal_base_interface* p, has_sl
ots_interface* pslot) | 473 static void do_slot_disconnect(_signal_base_interface* p, has_sl
ots_interface* pslot) |
483 { | 474 { |
484 _signal_base* const self = static_cast< _signal_base* >(
p); | 475 _signal_base* const self = static_cast< _signal_base* >(
p); |
485 lock_block<mt_policy> lock(self); | 476 lock_block<mt_policy> lock(self); |
486 connections_list::iterator it = self->m_connected_slots.
begin(); | 477 connections_list::iterator it = self->m_connected_slots.
begin(); |
487 connections_list::iterator itEnd = self->m_connected_slo
ts.end(); | 478 connections_list::iterator itEnd = self->m_connected_slo
ts.end(); |
488 | 479 |
489 while(it != itEnd) | 480 while(it != itEnd) |
490 { | 481 { |
491 connections_list::iterator itNext = it; | 482 connections_list::iterator itNext = it; |
492 ++itNext; | 483 ++itNext; |
493 | 484 |
494 if(it->getdest() == pslot) | 485 if(it->getdest() == pslot) |
495 { | 486 { |
496 // If we're currently using this iterator, | 487 » » » » » self->m_connected_slots.erase(it); |
497 // don't erase it and invalidate it yet; set a | 488 » » » » } |
498 // flag to do so afterwards. | |
499 if (self->m_current_iterator == it) { | |
500 self->m_erase_current_iterator = true; | |
501 } else { | |
502 self->m_connected_slots.erase(it); | |
503 } | |
504 } | |
505 | 489 |
506 it = itNext; | 490 it = itNext; |
507 } | 491 } |
508 } | 492 } |
509 | 493 |
510 static void do_slot_duplicate(_signal_base_interface* p, const h
as_slots_interface* oldtarget, has_slots_interface* newtarget) | 494 static void do_slot_duplicate(_signal_base_interface* p, const h
as_slots_interface* oldtarget, has_slots_interface* newtarget) |
511 { | 495 { |
512 _signal_base* const self = static_cast< _signal_base* >(
p); | 496 _signal_base* const self = static_cast< _signal_base* >(
p); |
513 lock_block<mt_policy> lock(self); | 497 lock_block<mt_policy> lock(self); |
514 connections_list::iterator it = self->m_connected_slots.
begin(); | 498 connections_list::iterator it = self->m_connected_slots.
begin(); |
515 connections_list::iterator itEnd = self->m_connected_slo
ts.end(); | 499 connections_list::iterator itEnd = self->m_connected_slo
ts.end(); |
516 | 500 |
517 while(it != itEnd) | 501 while(it != itEnd) |
518 { | 502 { |
519 if(it->getdest() == oldtarget) | 503 if(it->getdest() == oldtarget) |
520 { | 504 { |
521 self->m_connected_slots.push_back(it->du
plicate(newtarget)); | 505 self->m_connected_slots.push_back(it->du
plicate(newtarget)); |
522 } | 506 } |
523 | 507 |
524 ++it; | 508 ++it; |
525 } | 509 } |
526 } | 510 } |
527 | 511 |
528 protected: | 512 protected: |
529 connections_list m_connected_slots; | 513 connections_list m_connected_slots; |
530 | 514 » }; |
531 // Used to handle a slot being disconnected while a signal is | |
532 // firing (iterating m_connected_slots). | |
533 connections_list::iterator m_current_iterator; | |
534 bool m_erase_current_iterator = false; | |
535 }; | |
536 | 515 |
537 template<class mt_policy = SIGSLOT_DEFAULT_MT_POLICY> | 516 template<class mt_policy = SIGSLOT_DEFAULT_MT_POLICY> |
538 class has_slots : public has_slots_interface, public mt_policy | 517 class has_slots : public has_slots_interface, public mt_policy |
539 { | 518 { |
540 private: | 519 private: |
541 typedef std::set< _signal_base_interface* > sender_set; | 520 typedef std::set< _signal_base_interface* > sender_set; |
542 typedef sender_set::const_iterator const_iterator; | 521 typedef sender_set::const_iterator const_iterator; |
543 | 522 |
544 public: | 523 public: |
545 has_slots() : has_slots_interface(&has_slots::do_signal_connect,
&has_slots::do_signal_disconnect, &has_slots::do_disconnect_all) | 524 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... |
619 void connect(desttype* pclass, void (desttype::*pmemfun)(Args...
)) | 598 void connect(desttype* pclass, void (desttype::*pmemfun)(Args...
)) |
620 { | 599 { |
621 lock_block<mt_policy> lock(this); | 600 lock_block<mt_policy> lock(this); |
622 this->m_connected_slots.push_back(_opaque_connection(pcl
ass, pmemfun)); | 601 this->m_connected_slots.push_back(_opaque_connection(pcl
ass, pmemfun)); |
623 pclass->signal_connect(static_cast< _signal_base_interfa
ce* >(this)); | 602 pclass->signal_connect(static_cast< _signal_base_interfa
ce* >(this)); |
624 } | 603 } |
625 | 604 |
626 void emit(Args... args) | 605 void emit(Args... args) |
627 { | 606 { |
628 lock_block<mt_policy> lock(this); | 607 lock_block<mt_policy> lock(this); |
629 this->m_current_iterator = | 608 » » » typename connections_list::const_iterator it = this->m_c
onnected_slots.begin(); |
630 this->m_connected_slots.begin(); | 609 » » » typename connections_list::const_iterator itEnd = this->
m_connected_slots.end(); |
631 while (this->m_current_iterator != | 610 |
632 this->m_connected_slots.end()) { | 611 » » » while(it != itEnd) |
633 _opaque_connection const& conn = | 612 » » » { |
634 *this->m_current_iterator; | 613 » » » » _opaque_connection const& conn = *it; |
635 conn.emit<Args...>(args...); | 614 » » » » ++it; |
636 if (this->m_erase_current_iterator) { | 615 |
637 this->m_current_iterator = | 616 » » » » conn.emit<Args...>(args...); |
638 this->m_connected_slots.erase( | 617 » » » } |
639 this->m_current_iterator); | |
640 this->m_erase_current_iterator = false; | |
641 } else { | |
642 ++(this->m_current_iterator); | |
643 } | |
644 } | |
645 } | 618 } |
646 | 619 |
647 void operator()(Args... args) | 620 void operator()(Args... args) |
648 { | 621 { |
649 emit(args...); | 622 emit(args...); |
650 } | 623 } |
651 }; | 624 }; |
652 | 625 |
653 // Alias with default thread policy. Needed because both default argumen
ts | 626 // Alias with default thread policy. Needed because both default argumen
ts |
654 // and variadic template arguments must go at the end of the list, so we | 627 // and variadic template arguments must go at the end of the list, so we |
(...skipping 28 matching lines...) Expand all Loading... |
683 | 656 |
684 template<typename A1, typename A2, typename A3, typename A4, typename A5
, typename A6, typename A7, typename mt_policy = SIGSLOT_DEFAULT_MT_POLICY> | 657 template<typename A1, typename A2, typename A3, typename A4, typename A5
, typename A6, typename A7, typename mt_policy = SIGSLOT_DEFAULT_MT_POLICY> |
685 using signal7 = signal_with_thread_policy<mt_policy, A1, A2, A3, A4, A5,
A6, A7>; | 658 using signal7 = signal_with_thread_policy<mt_policy, A1, A2, A3, A4, A5,
A6, A7>; |
686 | 659 |
687 template<typename A1, typename A2, typename A3, typename A4, typename A5
, typename A6, typename A7, typename A8, typename mt_policy = SIGSLOT_DEFAULT_MT
_POLICY> | 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> |
688 using signal8 = signal_with_thread_policy<mt_policy, A1, A2, A3, A4, A5,
A6, A7, A8>; | 661 using signal8 = signal_with_thread_policy<mt_policy, A1, A2, A3, A4, A5,
A6, A7, A8>; |
689 | 662 |
690 } // namespace sigslot | 663 } // namespace sigslot |
691 | 664 |
692 #endif // WEBRTC_BASE_SIGSLOT_H__ | 665 #endif // WEBRTC_BASE_SIGSLOT_H__ |
OLD | NEW |