Skip to content

Commit

Permalink
signal: Add connect_first()
Browse files Browse the repository at this point in the history
Add connect_first(const slot_base&) and connect_first(slot_base&&)
in internal::signal_impl, signal_base, signal_with_accumulator and
trackable_signal_with_accumulator.
Replace some calls to connect() by connect_first() in test_signal
and test_scoped_connection.
Fixes libsigcplusplus#81
  • Loading branch information
kjellahl committed Sep 7, 2023
1 parent 793d066 commit 720bfb6
Show file tree
Hide file tree
Showing 12 changed files with 193 additions and 46 deletions.
5 changes: 3 additions & 2 deletions sigc++/adaptors/bind.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,9 @@ namespace sigc
* sigc::bind(&foo,1,2,3)(); //fixes all three arguments and calls foo(1,2,3)
* @endcode
*
* The functor sigc::bind() returns can be passed into
* @ref sigc::signal_with_accumulator::connect() "sigc::signal::connect()" directly.
* The functor that sigc::bind() returns can be passed directly into
* @ref sigc::signal_with_accumulator::connect() "sigc::signal::connect()" or
* @ref sigc::signal_with_accumulator::connect_first() "sigc::signal::connect_first()".
*
* @par Example:
* @code
Expand Down
5 changes: 3 additions & 2 deletions sigc++/adaptors/compose.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,9 @@ namespace sigc
* square_root(9))
* @endcode
*
* The functor sigc::compose() returns can be passed directly into
* @ref sigc::signal_with_accumulator::connect() "sigc::signal::connect()".
* The functor that sigc::compose() returns can be passed directly into
* @ref sigc::signal_with_accumulator::connect() "sigc::signal::connect()" or
* @ref sigc::signal_with_accumulator::connect_first() "sigc::signal::connect_first()".
*
* @par Example:
* @code
Expand Down
5 changes: 3 additions & 2 deletions sigc++/adaptors/exception_catch.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,9 @@ namespace sigc
* sigc::exception_catch(&foo, my_catch())();
* @endcode
*
* The functor sigc::exception_catch() returns can be directly passed into
* @ref sigc::signal_with_accumulator::connect() "sigc::signal::connect()".
* The functor that sigc::exception_catch() returns can be passed directly into
* @ref sigc::signal_with_accumulator::connect() "sigc::signal::connect()" or
* @ref sigc::signal_with_accumulator::connect_first() "sigc::signal::connect_first()".
*
* @par Example:
* @code
Expand Down
5 changes: 3 additions & 2 deletions sigc++/adaptors/hide.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,9 @@ namespace sigc
* sigc::hide<2>(&foo)(1,2,3); // adds a dummy parameter at the back and calls foo(1,2)
* @endcode
*
* The functor sigc::hide() returns can be directly passed into
* @ref sigc::signal_with_accumulator::connect() "sigc::signal::connect()".
* The functor that sigc::hide() returns can be passed directly into
* @ref sigc::signal_with_accumulator::connect() "sigc::signal::connect()" or
* @ref sigc::signal_with_accumulator::connect_first() "sigc::signal::connect_first()".
*
* @par Example:
* @code
Expand Down
3 changes: 2 additions & 1 deletion sigc++/adaptors/retype.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ namespace sigc
* @endcode
*
* The functor that sigc::retype() returns can be passed directly into
* @ref sigc::signal_with_accumulator::connect() "sigc::signal::connect()".
* @ref sigc::signal_with_accumulator::connect() "sigc::signal::connect()" or
* @ref sigc::signal_with_accumulator::connect_first() "sigc::signal::connect_first()".
*
* @par Example:
* @code
Expand Down
5 changes: 3 additions & 2 deletions sigc++/connection.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,9 @@ namespace sigc
/** Convenience class for safe disconnection.
*
* This may be used to disconnect the referred slot at any time (disconnect()).
* @ref sigc::signal_with_accumulator::connect() "sigc::signal::connect()"
* returns a %sigc::connection.
* @ref sigc::signal_with_accumulator::connect() "sigc::signal::connect()" and
* @ref sigc::signal_with_accumulator::connect_first() "sigc::signal::connect_first()"
* return a %sigc::connection.
*
* @code
* sigc::connection conn = sig.connect(sigc::mem_fun(a, &A::foo));
Expand Down
5 changes: 3 additions & 2 deletions sigc++/scoped_connection.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,9 @@ namespace sigc
*
* You will use sigc::scoped_connection by constructing it from a ‘normal’,
* unscoped @ref sigc::connection, such as those returned by
* @ref sigc::signal_with_accumulator::connect() "sigc::signal::connect()", thus
* ‘wrapping’ the connection in a scoped_connection, adding auto-disconnection.
* @ref sigc::signal_with_accumulator::connect() "sigc::signal::connect()" and
* @ref sigc::signal_with_accumulator::connect_first() "sigc::signal::connect_first()",
* thus ‘wrapping’ the connection in a scoped_connection, adding auto-disconnection.
* It can also be assigned from an unscoped connection, in which case, if there
* was a previous slot referred to by the scoped connection, it is disconnected.
*
Expand Down
115 changes: 97 additions & 18 deletions sigc++/signal.h
Original file line number Diff line number Diff line change
Expand Up @@ -374,14 +374,14 @@ struct signal_emit<void, void, T_arg...>
/** Signal declaration.
* %signal_with_accumulator can be used to connect() slots that are invoked
* during subsequent calls to emit(). Any functor or slot
* can be passed into connect(). It is converted into a slot
* can be passed into connect() or connect_first(). It is converted into a slot
* implicitly.
*
* If you want to connect one signal to another, use make_slot()
* to retrieve a functor that emits the signal when invoked.
*
* Be careful if you directly pass one signal into the connect()
* method of another: a shallow copy of the signal is made and
* Be careful if you directly pass one signal into the connect() or
* connect_first() method of another: a shallow copy of the signal is made and
* the signal's slots are not disconnected until both the signal
* and its clone are destroyed, which is probably not what you want!
*
Expand All @@ -401,8 +401,8 @@ class signal_with_accumulator : public signal_base
public:
using slot_type = slot<T_return(T_arg...)>;

/** Add a slot to the list of slots.
* Any functor or slot may be passed into connect().
/** Add a slot at the end of the list of slots.
* Any functor or slot may be passed into %connect().
* It will be converted into a slot implicitly.
* The returned connection may be stored for disconnection
* of the slot at some later point. It stays valid until
Expand All @@ -426,7 +426,7 @@ class signal_with_accumulator : public signal_base
return connection(slot_base);
}

/** Add a slot to the list of slots.
/** Add a slot at the end of the list of slots.
* @see connect(const slot_type& slot_).
*
* @newin{2,8}
Expand All @@ -438,6 +438,45 @@ class signal_with_accumulator : public signal_base
return connection(slot_base);
}

/** Add a slot at the beginning of the list of slots.
* Any functor or slot may be passed into %connect_first().
* It will be converted into a slot implicitly.
* The returned connection may be stored for disconnection
* of the slot at some later point. It stays valid until
* the slot is disconnected from the signal.
* std::function<> and C++11 lambda expressions are functors.
* These are examples of functors that can be connected to a signal.
*
* %std::bind() creates a functor, but this functor typically has an
* %operator()() which is a variadic template.
* Our functor_trait can't deduce the result type
* of such a functor. If you first assign the return value of %std::bind()
* to a std::function, you can connect the std::function to a signal.
*
* @param slot_ The slot to add to the list of slots.
* @return A connection.
*
* @newin{3,6}
*/
connection connect_first(const slot_type& slot_)
{
auto iter = signal_base::connect_first(slot_);
auto& slot_base = *iter;
return connection(slot_base);
}

/** Add a slot at the beginning of the list of slots.
* @see connect_first(const slot_type& slot_).
*
* @newin{3,6}
*/
connection connect_first(slot_type&& slot_)
{
auto iter = signal_base::connect_first(std::move(slot_));
auto& slot_base = *iter;
return connection(slot_base);
}

/** Triggers the emission of the signal.
* During signal emission all slots that have been connected
* to the signal are invoked unless they are manually set into
Expand Down Expand Up @@ -505,14 +544,14 @@ class signal_with_accumulator : public signal_base

/** signal can be used to connect() slots that are invoked
* during subsequent calls to emit(). Any functor or slot
* can be passed into connect(). It is converted into a slot
* can be passed into connect() or connect_first(). It is converted into a slot
* implicitly.
*
* If you want to connect one signal to another, use make_slot()
* to retrieve a functor that emits the signal when invoked.
*
* Be careful if you directly pass one signal into the connect()
* method of another: a shallow copy of the signal is made and
* Be careful if you directly pass one signal into the connect() or
* connect_first() method of another: a shallow copy of the signal is made and
* the signal's slots are not disconnected until both the signal
* and its clone are destroyed, which is probably not what you want!
*
Expand Down Expand Up @@ -634,13 +673,14 @@ class signal<T_return(T_arg...)> : public signal_with_accumulator<T_return, void
/** Signal declaration.
* %trackable_signal_with_accumulator can be used to connect() slots that are invoked
* during subsequent calls to emit(). Any functor or slot
* can be passed into connect(). It is converted into a slot implicitly.
* can be passed into connect() or connect_first(). It is converted into a slot
* implicitly.
*
* If you want to connect one signal to another, use make_slot()
* to retrieve a functor that emits the signal when invoked.
*
* Be careful if you directly pass one signal into the connect()
* method of another: a shallow copy of the signal is made and
* Be careful if you directly pass one signal into the connect() or
* connect_first() method of another: a shallow copy of the signal is made and
* the signal's slots are not disconnected until both the signal
* and its clone are destroyed, which is probably not what you want!
*
Expand All @@ -664,8 +704,8 @@ class trackable_signal_with_accumulator
public:
using slot_type = slot<T_return(T_arg...)>;

/** Add a slot to the list of slots.
* Any functor or slot may be passed into connect().
/** Add a slot at the end of the list of slots.
* Any functor or slot may be passed into %connect().
* It will be converted into a slot implicitly.
* The returned connection may be stored for disconnection
* of the slot at some later point. It stays valid until
Expand All @@ -689,7 +729,7 @@ class trackable_signal_with_accumulator
return connection(slot_base);
}

/** Add a slot to the list of slots.
/** Add a slot at the end of the list of slots.
* @see connect(const slot_type& slot_).
*/
connection connect(slot_type&& slot_)
Expand All @@ -699,6 +739,45 @@ class trackable_signal_with_accumulator
return connection(slot_base);
}

/** Add a slot at the beginning of the list of slots.
* Any functor or slot may be passed into %connect_first().
* It will be converted into a slot implicitly.
* The returned connection may be stored for disconnection
* of the slot at some later point. It stays valid until
* the slot is disconnected from the signal.
* std::function<> and C++11 lambda expressions are functors.
* These are examples of functors that can be connected to a signal.
*
* %std::bind() creates a functor, but this functor typically has an
* %operator()() which is a variadic template.
* Our functor_trait can't deduce the result type
* of such a functor. If you first assign the return value of %std::bind()
* to a std::function, you can connect the std::function to a signal.
*
* @param slot_ The slot to add to the list of slots.
* @return A connection.
*
* @newin{3,6}
*/
connection connect_first(const slot_type& slot_)
{
auto iter = signal_base::connect_first(slot_);
auto& slot_base = *iter;
return connection(slot_base);
}

/** Add a slot at the beginning of the list of slots.
* @see connect_first(const slot_type& slot_).
*
* @newin{3,6}
*/
connection connect_first(slot_type&& slot_)
{
auto iter = signal_base::connect_first(std::move(slot_));
auto& slot_base = *iter;
return connection(slot_base);
}

/** Triggers the emission of the signal.
* During signal emission all slots that have been connected
* to the signal are invoked unless they are manually set into
Expand Down Expand Up @@ -772,14 +851,14 @@ class trackable_signal_with_accumulator

/** %trackable_signal can be used to connect() slots that are invoked
* during subsequent calls to emit(). Any functor or slot
* can be passed into connect(). It is converted into a slot
* can be passed into connect() or connect_first(). It is converted into a slot
* implicitly.
*
* If you want to connect one signal to another, use make_slot()
* to retrieve a functor that emits the signal when invoked.
*
* Be careful if you directly pass one signal into the connect()
* method of another: a shallow copy of the signal is made and
* Be careful if you directly pass one signal into the connect() or
* connect_first() method of another: a shallow copy of the signal is made and
* the signal's slots are not disconnected until both the signal
* and its clone are destroyed, which is probably not what you want!
*
Expand Down
24 changes: 24 additions & 0 deletions sigc++/signal_base.cc
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,18 @@ signal_impl::connect(slot_base&& slot_)
return insert(slots_.end(), std::move(slot_));
}

signal_impl::iterator_type
signal_impl::connect_first(const slot_base& slot_)
{
return insert(slots_.begin(), slot_);
}

signal_impl::iterator_type
signal_impl::connect_first(slot_base&& slot_)
{
return insert(slots_.begin(), std::move(slot_));
}

void
signal_impl::add_notification_to_iter(const signal_impl::iterator_type& iter)
{
Expand Down Expand Up @@ -260,6 +272,18 @@ signal_base::connect(slot_base&& slot_)
return impl()->connect(std::move(slot_));
}

signal_base::iterator_type
signal_base::connect_first(const slot_base& slot_)
{
return impl()->connect_first(slot_);
}

signal_base::iterator_type
signal_base::connect_first(slot_base&& slot_)
{
return impl()->connect_first(std::move(slot_));
}

signal_base::iterator_type
signal_base::insert(iterator_type i, const slot_base& slot_)
{
Expand Down
Loading

0 comments on commit 720bfb6

Please sign in to comment.