From 0ade0b2212ddf855780b4e2746534a2d93426193 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Dom=C3=ADnguez?= Date: Mon, 19 Aug 2024 00:17:08 +0200 Subject: [PATCH] Deduplicate SignalWithCombiner specialization --- libs/pbd/pbd/signals.h | 260 +++++++---------------------------------- 1 file changed, 45 insertions(+), 215 deletions(-) diff --git a/libs/pbd/pbd/signals.h b/libs/pbd/pbd/signals.h index 8fbb921fb0..48443cda16 100644 --- a/libs/pbd/pbd/signals.h +++ b/libs/pbd/pbd/signals.h @@ -137,7 +137,12 @@ public: const slot_function_type& slot, PBD::EventLoop* event_loop); - typename Combiner::result_type operator() (A... a); + /** If R is any kind of void type, + * then operator() return type must be R, + * else it must be Combiner::result_type. + */ + typename std::conditional_t, R, typename Combiner::result_type> + operator() (A... a); bool empty () const { Glib::Threads::Mutex::Lock lm (_mutex); @@ -158,59 +163,6 @@ private: }; -template -class SignalWithCombiner : public SignalBase -{ -public: - - typedef boost::function slot_function_type; - -private: - - /** The slots that this signal will call on emission */ - typedef std::map, slot_function_type> Slots; - Slots _slots; - -public: - - static void compositor (typename boost::function f, - EventLoop* event_loop, - EventLoop::InvalidationRecord* ir, A... a); - - ~SignalWithCombiner (); - - void connect_same_thread (ScopedConnection& c, const slot_function_type& slot); - void connect_same_thread (ScopedConnectionList& clist, const slot_function_type& slot); - void connect (ScopedConnectionList& clist, - PBD::EventLoop::InvalidationRecord* ir, - const slot_function_type& slot, - PBD::EventLoop* event_loop); - void connect (ScopedConnection& c, - PBD::EventLoop::InvalidationRecord* ir, - const slot_function_type& slot, - PBD::EventLoop* event_loop); - void operator() (A... a); - - bool empty () const { - Glib::Threads::Mutex::Lock lm (_mutex); - return _slots.empty (); - } - - size_t size () const { - Glib::Threads::Mutex::Lock lm (_mutex); - return _slots.size (); - } - -private: - - friend class Connection; - - std::shared_ptr _connect (PBD::EventLoop::InvalidationRecord* ir, - slot_function_type f); - void disconnect (std::shared_ptr c); - -}; - template using DefaultCombiner = OptionalLastValue; @@ -413,15 +365,6 @@ SignalWithCombiner::compositor (typename boost::functioncall_slot (ir, boost::bind (f, a...)); } -template -void -SignalWithCombiner::compositor (typename boost::function f, - EventLoop* event_loop, - EventLoop::InvalidationRecord* ir, A... a) -{ - event_loop->call_slot (ir, boost::bind (f, a...)); -} - template SignalWithCombiner::~SignalWithCombiner () { @@ -433,17 +376,6 @@ SignalWithCombiner::~SignalWithCombiner () } } -template -SignalWithCombiner::~SignalWithCombiner () -{ - _in_dtor.store (true, std::memory_order_release); - Glib::Threads::Mutex::Lock lm (_mutex); - /* Tell our connection objects that we are going away, so they don't try to call us */ - for (typename Slots::const_iterator i = _slots.begin(); i != _slots.end(); ++i) { - i->first->signal_going_away (); - } -} - /** Arrange for @a slot to be executed whenever this signal is emitted. * Store the connection that represents this arrangement in @a c. * @@ -459,14 +391,6 @@ SignalWithCombiner::connect_same_thread (ScopedConnection& c, c = _connect (0, slot); } -template -void -SignalWithCombiner::connect_same_thread (ScopedConnection& c, - const slot_function_type& slot) -{ - c = _connect (0, slot); -} - /** Arrange for @a slot to be executed whenever this signal is emitted. * Add the connection that represents this arrangement to @a clist. * @@ -482,14 +406,6 @@ SignalWithCombiner::connect_same_thread (ScopedConnectionList clist.add_connection (_connect (0, slot)); } -template -void -SignalWithCombiner::connect_same_thread (ScopedConnectionList& clist, - const slot_function_type& slot) -{ - clist.add_connection (_connect (0, slot)); -} - /** Arrange for @a slot to be executed in the context of @a event_loop * whenever this signal is emitted. Add the connection that represents * this arrangement to @a clist. @@ -531,22 +447,6 @@ SignalWithCombiner::connect (ScopedConnectionList& clist, })); } -template -void -SignalWithCombiner::connect (ScopedConnectionList& clist, - PBD::EventLoop::InvalidationRecord* ir, - const slot_function_type& slot, - PBD::EventLoop* event_loop) -{ - if (ir) { - ir->event_loop = event_loop; - } - - clist.add_connection (_connect (ir, [slot, event_loop, ir](A... a) { - return compositor(slot, event_loop, ir, a...); - })); -} - /** See notes for the ScopedConnectionList variant of this function. This * differs in that it stores the connection to the signal in a single * ScopedConnection rather than a ScopedConnectionList. @@ -568,29 +468,13 @@ SignalWithCombiner::connect (ScopedConnection& c, }); } -template -void -SignalWithCombiner::connect (ScopedConnection& c, - PBD::EventLoop::InvalidationRecord* ir, - const slot_function_type& slot, - PBD::EventLoop* event_loop) -{ - if (ir) { - ir->event_loop = event_loop; - } - - c = _connect (ir, [slot, event_loop, ir](A... a) { - return compositor(slot, event_loop, ir, a...); - }); -} - /** Emit this signal. This will cause all slots connected to it be executed * in the order that they were connected (cross-thread issues may alter * the precise execution time of cross-thread slots). */ template -typename Combiner::result_type +typename std::conditional_t, R, typename Combiner::result_type> SignalWithCombiner::operator() (A... a) { /* First, take a copy of our list of slots as it is now */ @@ -601,58 +485,47 @@ SignalWithCombiner::operator() (A... a) s = _slots; } - std::list r; - for (typename Slots::const_iterator i = s.begin(); i != s.end(); ++i) { + if constexpr (std::is_void_v) { + for (typename Slots::const_iterator i = s.begin(); i != s.end(); ++i) { - /* We may have just called a slot, and this may have resulted in - * disconnection of other slots from us. The list copy means that - * this won't cause any problems with invalidated iterators, but we - * must check to see if the slot we are about to call is still on the list. - */ - bool still_there = false; - { - Glib::Threads::Mutex::Lock lm (_mutex); - still_there = _slots.find (i->first) != _slots.end (); + /* We may have just called a slot, and this may have resulted in + * disconnection of other slots from us. The list copy means that + * this won't cause any problems with invalidated iterators, but we + * must check to see if the slot we are about to call is still on the list. + */ + bool still_there = false; + { + Glib::Threads::Mutex::Lock lm (_mutex); + still_there = _slots.find (i->first) != _slots.end (); + } + + if (still_there) { + (i->second)(a...); + } + } + } else { + std::list r; + for (typename Slots::const_iterator i = s.begin(); i != s.end(); ++i) { + + /* We may have just called a slot, and this may have resulted in + * disconnection of other slots from us. The list copy means that + * this won't cause any problems with invalidated iterators, but we + * must check to see if the slot we are about to call is still on the list. + */ + bool still_there = false; + { + Glib::Threads::Mutex::Lock lm (_mutex); + still_there = _slots.find (i->first) != _slots.end (); + } + + if (still_there) { + r.push_back ((i->second)(a...)); + } } - if (still_there) { - r.push_back ((i->second)(a...)); - } - } - - /* Call our combiner to do whatever is required to the result values */ - Combiner c; - return c (r.begin(), r.end()); -} - -template -void -SignalWithCombiner::operator() (A... a) -{ - /* First, take a copy of our list of slots as it is now */ - - Slots s; - { - Glib::Threads::Mutex::Lock lm (_mutex); - s = _slots; - } - - for (typename Slots::const_iterator i = s.begin(); i != s.end(); ++i) { - - /* We may have just called a slot, and this may have resulted in - * disconnection of other slots from us. The list copy means that - * this won't cause any problems with invalidated iterators, but we - * must check to see if the slot we are about to call is still on the list. - */ - bool still_there = false; - { - Glib::Threads::Mutex::Lock lm (_mutex); - still_there = _slots.find (i->first) != _slots.end (); - } - - if (still_there) { - (i->second)(a...); - } + /* Call our combiner to do whatever is required to the result values */ + Combiner c; + return c (r.begin(), r.end()); } } @@ -673,23 +546,6 @@ SignalWithCombiner::_connect (PBD::EventLoop::InvalidationRec return c; } -template -std::shared_ptr -SignalWithCombiner::_connect (PBD::EventLoop::InvalidationRecord* ir, - slot_function_type f) -{ - std::shared_ptr c (new Connection (this, ir)); - Glib::Threads::Mutex::Lock lm (_mutex); - _slots[c] = f; - #ifdef DEBUG_PBD_SIGNAL_CONNECTIONS - if (_debug_connection) { - std::cerr << "+++++++ CONNECT " << this << " size now " << _slots.size() << std::endl; - stacktrace (std::cerr, 10); - } - #endif - return c; -} - template void SignalWithCombiner::disconnect (std::shared_ptr c) @@ -716,31 +572,5 @@ SignalWithCombiner::disconnect (std::shared_ptr c #endif } -template -void -SignalWithCombiner::disconnect (std::shared_ptr c) -{ - /* ~ScopedConnection can call this concurrently with our d'tor */ - Glib::Threads::Mutex::Lock lm (_mutex, Glib::Threads::TRY_LOCK); - while (!lm.locked()) { - if (_in_dtor.load (std::memory_order_acquire)) { - /* d'tor signal_going_away() took care of everything already */ - return; - } - /* Spin */ - lm.try_acquire (); - } - _slots.erase (c); - lm.release (); - - c->disconnected (); - #ifdef DEBUG_PBD_SIGNAL_CONNECTIONS - if (_debug_connection) { - std::cerr << "------- DISCCONNECT " << this << " size now " << _slots.size() << std::endl; - stacktrace (std::cerr, 10); - } - #endif -} - } /* namespace */