35 #include <boost/bind/protect.hpp>
36 #include <boost/enable_shared_from_this.hpp>
45 #define DEBUG_PBD_SIGNAL_CONNECTIONS
46 #define DEBUG_PBD_SIGNAL_EMISSION
49 #ifdef DEBUG_PBD_SIGNAL_CONNECTIONS
55 using namespace std::placeholders;
59 #ifdef DEBUG_PBD_SIGNAL_CONNECTIONS
75 , _debug_connection (false)
78 , _debug_emission (false)
82 virtual void disconnect (std::shared_ptr<Connection>) = 0;
83 #ifdef DEBUG_PBD_SIGNAL_CONNECTIONS
86 #ifdef DEBUG_PBD_SIGNAL_EMISSION
93 #ifdef DEBUG_PBD_SIGNAL_CONNECTIONS
96 #ifdef DEBUG_PBD_SIGNAL_EMISSION
107 template <
typename Iter>
110 while (first != last) {
119 template <
typename Combiner,
typename _Signature>
122 template <
typename Combiner,
typename R,
typename... A>
137 static void compositor (
typename std::function<
void(A...)> f,
158 typename std::conditional_t<std::is_void_v<R>, R,
typename Combiner::result_type>
163 return _slots.empty ();
168 return _slots.size ();
176 void disconnect (std::shared_ptr<Connection> c);
180 template <
typename R>
183 template <
typename _Signature>
186 template <
typename R,
typename... A>
194 , _invalidation_record (ir)
196 if (_invalidation_record) {
197 _invalidation_record->ref ();
204 SignalBase* signal = _signal.exchange (0, std::memory_order_acq_rel);
219 if (_invalidation_record) {
220 _invalidation_record->unref ();
227 if (!_signal.exchange (0, std::memory_order_acq_rel)) {
237 if (_invalidation_record) {
238 _invalidation_record->unref ();
294 std::list<ScopedConnectionList*>::size_type
size()
const {
PBD::Mutex::Lock lm (_scoped_connection_lock);
return _scoped_connection_list.size(); }
314 template <
typename Combiner,
typename R,
typename... A>
320 event_loop->
call_slot (ir, std::bind (f, a...));
323 template <
typename Combiner,
typename R,
typename... A>
326 _in_dtor.store (
true, std::memory_order_release);
329 for (
typename Slots::const_iterator i = _slots.begin(); i != _slots.end(); ++i) {
330 i->first->signal_going_away ();
341 template <
typename Combiner,
typename R,
typename... A>
346 c = _connect (0, slot);
356 template <
typename Combiner,
typename R,
typename... A>
389 template <
typename Combiner,
typename R,
typename... A>
400 clist.
add_connection (_connect (ir, [slot, event_loop, ir](A... a) {
401 return compositor(slot, event_loop, ir, a...);
410 template <
typename Combiner,
typename R,
typename... A>
421 c = _connect (ir, [slot, event_loop, ir](A... a) {
422 return compositor(slot, event_loop, ir, a...);
431 template <
typename Combiner,
typename R,
typename... A>
432 typename std::conditional_t<std::is_void_v<R>, R,
typename Combiner::result_type>
435 #ifdef DEBUG_PBD_SIGNAL_EMISSION
436 if (_debug_emission) {
437 std::cerr <<
"------ Signal @ " <<
this <<
" emission process begins with " << _slots.size() << std::endl;
452 std::vector<Connection*> s;
454 const std::size_t nslots = 512;
455 std::vector<Connection*,PBD::StackAllocator<Connection*,nslots> > s;
473 for (
auto const & [connection,functor] : _slots) {
474 s.push_back (connection.get());
478 if constexpr (std::is_void_v<R>) {
481 for (
auto const & c : s) {
490 bool still_there =
false;
494 typename Slots::const_iterator f = std::find_if (_slots.begin(), _slots.end(), [&](
typename Slots::value_type
const & elem) { return elem.first.get() == c; });
495 if (f != _slots.end()) {
502 #ifdef DEBUG_PBD_SIGNAL_EMISSION
503 if (_debug_emission) {
504 std::cerr <<
"signal @ " <<
this <<
" calling slot for connection @ " << c <<
" of " << _slots.size() << std::endl;
509 #ifdef DEBUG_PBD_SIGNAL_EMISSION
510 if (_debug_emission) {
511 std::cerr <<
"signal @ " <<
this <<
" connection " << c <<
" of " << _slots.size() <<
" was no longer in the slot list\n";
517 #ifdef DEBUG_PBD_SIGNAL_EMISSION
518 if (_debug_emission) {
519 std::cerr <<
"------ Signal @ " <<
this <<
" emission process ends\n";
526 return typename Combiner::result_type ();
551 r.reserve (s.size());
554 for (
auto const & c : s) {
561 bool still_there =
false;
565 typename Slots::const_iterator f = std::find_if (_slots.begin(), _slots.end(), [&](
typename Slots::value_type
const & elem) { return elem.first.get() == c; });
567 if (f != _slots.end()) {
573 #ifdef DEBUG_PBD_SIGNAL_EMISSION
574 if (_debug_emission) {
575 std::cerr <<
"signal @ " <<
this <<
" calling non-void slot for connection @ " << c <<
" of " << _slots.size() << std::endl;
578 r.push_back (functor (a...));
581 #ifdef DEBUG_PBD_SIGNAL_EMISSION
582 if (_debug_emission) {
583 std::cerr <<
"------ Signal @ " <<
this <<
" emission process ends\n";
589 return c (r.begin(), r.end());
593 template <
typename Combiner,
typename R,
typename... A>
594 std::shared_ptr<Connection>
598 std::shared_ptr<Connection> c (
new Connection (
this, ir));
602 #ifdef DEBUG_PBD_SIGNAL_CONNECTIONS
606 if (_debug_connection) {
607 std::cerr <<
"+++++++ CONNECT " <<
this <<
" via connection @ " << c <<
" size now " << _slots.size() << std::endl;
614 template <
typename Combiner,
typename R,
typename... A>
621 if (_in_dtor.load (std::memory_order_acquire)) {
632 #ifdef DEBUG_PBD_SIGNAL_CONNECTIONS
633 if (_debug_connection) {
634 std::cerr <<
"------- DISCCONNECT " <<
this <<
" size now " << _slots.size() << std::endl;
std::atomic< SignalBase * > _signal
PBD::EventLoop::InvalidationRecord * _invalidation_record
Connection(SignalBase *b, PBD::EventLoop::InvalidationRecord *ir)
virtual bool call_slot(InvalidationRecord *, const std::function< void()> &)=0
std::optional< R > result_type
std::list< ScopedConnectionList * >::size_type size() const
void add_connection(const UnscopedConnection &c)
ConnectionList _scoped_connection_list
std::list< ScopedConnection * > ConnectionList
virtual ~ScopedConnectionList()
ScopedConnectionList(const ScopedConnectionList &)=delete
PBD::Mutex _scoped_connection_lock
ScopedConnection(UnscopedConnection c)
UnscopedConnection const & the_connection() const
std::atomic< bool > _in_dtor
virtual void disconnect(std::shared_ptr< Connection >)=0
void set_debug_connection(bool yn)
void set_debug_emission(bool yn)
std::map< std::shared_ptr< Connection >, slot_function_type > Slots
std::function< R(A...)> slot_function_type
std::shared_ptr< Connection > UnscopedConnection
static std::size_t max_signal_subscribers
void stacktrace(std::ostream &out, int levels=0, size_t start_level=0)
#define DEBUG_PBD_SIGNAL_EMISSION
#define DEBUG_PBD_SIGNAL_CONNECTIONS
PBD::EventLoop * event_loop