Deduplicate SignalWithCombiner<Combiner, void, A...> specialization
This commit is contained in:
parent
6e19813c9b
commit
0ade0b2212
@ -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<std::is_void_v<R>, R, typename Combiner::result_type>
|
||||
operator() (A... a);
|
||||
|
||||
bool empty () const {
|
||||
Glib::Threads::Mutex::Lock lm (_mutex);
|
||||
@ -158,59 +163,6 @@ private:
|
||||
|
||||
};
|
||||
|
||||
template <typename Combiner, typename... A>
|
||||
class SignalWithCombiner<Combiner, void(A...)> : public SignalBase
|
||||
{
|
||||
public:
|
||||
|
||||
typedef boost::function<void(A...)> slot_function_type;
|
||||
|
||||
private:
|
||||
|
||||
/** The slots that this signal will call on emission */
|
||||
typedef std::map<std::shared_ptr<Connection>, slot_function_type> Slots;
|
||||
Slots _slots;
|
||||
|
||||
public:
|
||||
|
||||
static void compositor (typename boost::function<void(A...)> 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<Connection> _connect (PBD::EventLoop::InvalidationRecord* ir,
|
||||
slot_function_type f);
|
||||
void disconnect (std::shared_ptr<Connection> c);
|
||||
|
||||
};
|
||||
|
||||
template <typename R>
|
||||
using DefaultCombiner = OptionalLastValue<R>;
|
||||
|
||||
@ -413,15 +365,6 @@ SignalWithCombiner<Combiner, R(A...)>::compositor (typename boost::function<void
|
||||
event_loop->call_slot (ir, boost::bind (f, a...));
|
||||
}
|
||||
|
||||
template <typename Combiner, typename... A>
|
||||
void
|
||||
SignalWithCombiner<Combiner, void(A...)>::compositor (typename boost::function<void(A...)> f,
|
||||
EventLoop* event_loop,
|
||||
EventLoop::InvalidationRecord* ir, A... a)
|
||||
{
|
||||
event_loop->call_slot (ir, boost::bind (f, a...));
|
||||
}
|
||||
|
||||
template <typename Combiner, typename R, typename... A>
|
||||
SignalWithCombiner<Combiner, R(A...)>::~SignalWithCombiner ()
|
||||
{
|
||||
@ -433,17 +376,6 @@ SignalWithCombiner<Combiner, R(A...)>::~SignalWithCombiner ()
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Combiner, typename... A>
|
||||
SignalWithCombiner<Combiner, void(A...)>::~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<Combiner, R(A...)>::connect_same_thread (ScopedConnection& c,
|
||||
c = _connect (0, slot);
|
||||
}
|
||||
|
||||
template <typename Combiner, typename... A>
|
||||
void
|
||||
SignalWithCombiner<Combiner, void(A...)>::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<Combiner, R(A...)>::connect_same_thread (ScopedConnectionList
|
||||
clist.add_connection (_connect (0, slot));
|
||||
}
|
||||
|
||||
template <typename Combiner, typename... A>
|
||||
void
|
||||
SignalWithCombiner<Combiner, void(A...)>::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<Combiner, R(A...)>::connect (ScopedConnectionList& clist,
|
||||
}));
|
||||
}
|
||||
|
||||
template <typename Combiner, typename... A>
|
||||
void
|
||||
SignalWithCombiner<Combiner, void(A...)>::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<Combiner, R(A...)>::connect (ScopedConnection& c,
|
||||
});
|
||||
}
|
||||
|
||||
template <typename Combiner, typename... A>
|
||||
void
|
||||
SignalWithCombiner<Combiner, void(A...)>::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, typename R, typename... A>
|
||||
typename Combiner::result_type
|
||||
typename std::conditional_t<std::is_void_v<R>, R, typename Combiner::result_type>
|
||||
SignalWithCombiner<Combiner, R(A...)>::operator() (A... a)
|
||||
{
|
||||
/* First, take a copy of our list of slots as it is now */
|
||||
@ -601,58 +485,47 @@ SignalWithCombiner<Combiner, R(A...)>::operator() (A... a)
|
||||
s = _slots;
|
||||
}
|
||||
|
||||
std::list<R> r;
|
||||
for (typename Slots::const_iterator i = s.begin(); i != s.end(); ++i) {
|
||||
if constexpr (std::is_void_v<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 ();
|
||||
/* 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> 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 <typename Combiner, typename... A>
|
||||
void
|
||||
SignalWithCombiner<Combiner, void(A...)>::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<Combiner, R(A...)>::_connect (PBD::EventLoop::InvalidationRec
|
||||
return c;
|
||||
}
|
||||
|
||||
template <typename Combiner, typename... A>
|
||||
std::shared_ptr<Connection>
|
||||
SignalWithCombiner<Combiner, void(A...)>::_connect (PBD::EventLoop::InvalidationRecord* ir,
|
||||
slot_function_type f)
|
||||
{
|
||||
std::shared_ptr<Connection> 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 <typename Combiner, typename R, typename... A>
|
||||
void
|
||||
SignalWithCombiner<Combiner, R(A...)>::disconnect (std::shared_ptr<Connection> c)
|
||||
@ -716,31 +572,5 @@ SignalWithCombiner<Combiner, R(A...)>::disconnect (std::shared_ptr<Connection> c
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename Combiner, typename... A>
|
||||
void
|
||||
SignalWithCombiner<Combiner, void(A...)>::disconnect (std::shared_ptr<Connection> 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 */
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user