blob: 0f8af30074c36e471c29192324a2f0c23ee7a6fc [file] [log] [blame]
/*
Template for Signa1, Signal2, ... classes that support signals
with 1, 2, ... parameters
Begin: 2007-01-23
*/
// Copyright Frank Mori Hess 2007-2008
//
// Use, modification and
// distribution is subject to the Boost Software License, Version
// 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
// This file is included iteratively, and should not be protected from multiple inclusion
#ifdef BOOST_NO_VARIADIC_TEMPLATES
#define BOOST_SIGNALS2_NUM_ARGS BOOST_PP_ITERATION()
#else
#define BOOST_SIGNALS2_NUM_ARGS 1
#endif
// R, T1, T2, ..., TN, Combiner, Group, GroupCompare, SlotFunction, ExtendedSlotFunction, Mutex
#define BOOST_SIGNALS2_SIGNAL_TEMPLATE_INSTANTIATION \
BOOST_SIGNALS2_SIGNATURE_TEMPLATE_INSTANTIATION(BOOST_SIGNALS2_NUM_ARGS), \
Combiner, Group, GroupCompare, SlotFunction, ExtendedSlotFunction, Mutex
namespace boost
{
namespace signals2
{
namespace detail
{
// helper for bound_extended_slot_function that handles specialization for void return
template<typename R>
class BOOST_SIGNALS2_BOUND_EXTENDED_SLOT_FUNCTION_INVOKER_N(BOOST_SIGNALS2_NUM_ARGS)
{
public:
typedef R result_type;
template<typename ExtendedSlotFunction BOOST_SIGNALS2_PP_COMMA_IF(BOOST_SIGNALS2_NUM_ARGS)
BOOST_SIGNALS2_ARGS_TEMPLATE_DECL(BOOST_SIGNALS2_NUM_ARGS)>
result_type operator()(ExtendedSlotFunction &func, const connection &conn
BOOST_SIGNALS2_PP_COMMA_IF(BOOST_SIGNALS2_NUM_ARGS)
BOOST_SIGNALS2_FULL_REF_ARGS(BOOST_SIGNALS2_NUM_ARGS)) const
{
return func(conn BOOST_SIGNALS2_PP_COMMA_IF(BOOST_SIGNALS2_NUM_ARGS)
BOOST_SIGNALS2_SIGNATURE_ARG_NAMES(BOOST_SIGNALS2_NUM_ARGS));
}
};
#ifdef BOOST_NO_VOID_RETURNS
template<>
class BOOST_SIGNALS2_BOUND_EXTENDED_SLOT_FUNCTION_INVOKER_N(BOOST_SIGNALS2_NUM_ARGS)<void>
{
public:
typedef result_type_wrapper<void>::type result_type;
template<typename ExtendedSlotFunction BOOST_SIGNALS2_PP_COMMA_IF(BOOST_SIGNALS2_NUM_ARGS)
BOOST_SIGNALS2_ARGS_TEMPLATE_DECL(BOOST_SIGNALS2_NUM_ARGS)>
result_type operator()(ExtendedSlotFunction &func, const connection &conn
BOOST_SIGNALS2_PP_COMMA_IF(BOOST_SIGNALS2_NUM_ARGS)
BOOST_SIGNALS2_FULL_REF_ARGS(BOOST_SIGNALS2_NUM_ARGS)) const
{
func(conn BOOST_SIGNALS2_PP_COMMA_IF(BOOST_SIGNALS2_NUM_ARGS)
BOOST_SIGNALS2_SIGNATURE_ARG_NAMES(BOOST_SIGNALS2_NUM_ARGS));
return result_type();
}
};
#endif
// wrapper around an signalN::extended_slot_function which binds the
// connection argument so it looks like a normal
// signalN::slot_function
template<typename ExtendedSlotFunction>
class BOOST_SIGNALS2_BOUND_EXTENDED_SLOT_FUNCTION_N(BOOST_SIGNALS2_NUM_ARGS)
{
public:
typedef typename result_type_wrapper<typename ExtendedSlotFunction::result_type>::type result_type;
BOOST_SIGNALS2_BOUND_EXTENDED_SLOT_FUNCTION_N(BOOST_SIGNALS2_NUM_ARGS)(const ExtendedSlotFunction &fun):
_fun(fun), _connection(new connection)
{}
void set_connection(const connection &conn)
{
*_connection = conn;
}
#if BOOST_SIGNALS2_NUM_ARGS > 0
template<BOOST_SIGNALS2_ARGS_TEMPLATE_DECL(BOOST_SIGNALS2_NUM_ARGS)>
#endif // BOOST_SIGNALS2_NUM_ARGS > 0
result_type operator()(BOOST_SIGNALS2_FULL_REF_ARGS(BOOST_SIGNALS2_NUM_ARGS))
{
return BOOST_SIGNALS2_BOUND_EXTENDED_SLOT_FUNCTION_INVOKER_N(BOOST_SIGNALS2_NUM_ARGS)
<typename ExtendedSlotFunction::result_type>()
(_fun, *_connection BOOST_SIGNALS2_PP_COMMA_IF(BOOST_SIGNALS2_NUM_ARGS)
BOOST_SIGNALS2_SIGNATURE_ARG_NAMES(BOOST_SIGNALS2_NUM_ARGS));
}
// const overload
#if BOOST_SIGNALS2_NUM_ARGS > 0
template<BOOST_SIGNALS2_ARGS_TEMPLATE_DECL(BOOST_SIGNALS2_NUM_ARGS)>
#endif // BOOST_SIGNALS2_NUM_ARGS > 0
result_type operator()(BOOST_SIGNALS2_FULL_REF_ARGS(BOOST_SIGNALS2_NUM_ARGS)) const
{
return BOOST_SIGNALS2_BOUND_EXTENDED_SLOT_FUNCTION_INVOKER_N(BOOST_SIGNALS2_NUM_ARGS)
<typename ExtendedSlotFunction::result_type>()
(_fun, *_connection BOOST_SIGNALS2_PP_COMMA_IF(BOOST_SIGNALS2_NUM_ARGS)
BOOST_SIGNALS2_SIGNATURE_ARG_NAMES(BOOST_SIGNALS2_NUM_ARGS));
}
template<typename T>
bool operator==(const T &other) const
{
return _fun == other;
}
private:
BOOST_SIGNALS2_BOUND_EXTENDED_SLOT_FUNCTION_N(BOOST_SIGNALS2_NUM_ARGS)()
{}
ExtendedSlotFunction _fun;
boost::shared_ptr<connection> _connection;
};
template<BOOST_SIGNALS2_SIGNAL_TEMPLATE_DECL(BOOST_SIGNALS2_NUM_ARGS)>
class BOOST_SIGNALS2_SIGNAL_IMPL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS);
template<BOOST_SIGNALS2_SIGNAL_TEMPLATE_SPECIALIZATION_DECL(BOOST_SIGNALS2_NUM_ARGS)>
class BOOST_SIGNALS2_SIGNAL_IMPL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS) BOOST_SIGNALS2_SIGNAL_TEMPLATE_SPECIALIZATION
{
public:
typedef SlotFunction slot_function_type;
// typedef slotN<Signature, SlotFunction> slot_type;
typedef BOOST_SIGNALS2_SLOT_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)
<BOOST_SIGNALS2_SIGNATURE_TEMPLATE_INSTANTIATION(BOOST_SIGNALS2_NUM_ARGS),
slot_function_type> slot_type;
typedef ExtendedSlotFunction extended_slot_function_type;
// typedef slotN+1<R, const connection &, T1, T2, ..., TN, extended_slot_function_type> extended_slot_type;
typedef BOOST_SIGNALS2_EXTENDED_SLOT_TYPE(BOOST_SIGNALS2_NUM_ARGS) extended_slot_type;
typedef typename nonvoid<typename slot_function_type::result_type>::type nonvoid_slot_result_type;
private:
#ifdef BOOST_NO_VARIADIC_TEMPLATES
class slot_invoker;
#else // BOOST_NO_VARIADIC_TEMPLATES
typedef variadic_slot_invoker<nonvoid_slot_result_type, Args...> slot_invoker;
#endif // BOOST_NO_VARIADIC_TEMPLATES
typedef slot_call_iterator_cache<nonvoid_slot_result_type, slot_invoker> slot_call_iterator_cache_type;
typedef typename group_key<Group>::type group_key_type;
typedef shared_ptr<connection_body<group_key_type, slot_type, Mutex> > connection_body_type;
typedef grouped_list<Group, GroupCompare, connection_body_type> connection_list_type;
typedef BOOST_SIGNALS2_BOUND_EXTENDED_SLOT_FUNCTION_N(BOOST_SIGNALS2_NUM_ARGS)<extended_slot_function_type>
bound_extended_slot_function_type;
public:
typedef Combiner combiner_type;
typedef typename result_type_wrapper<typename combiner_type::result_type>::type result_type;
typedef Group group_type;
typedef GroupCompare group_compare_type;
typedef typename detail::slot_call_iterator_t<slot_invoker,
typename connection_list_type::iterator, connection_body<group_key_type, slot_type, Mutex> > slot_call_iterator;
BOOST_SIGNALS2_SIGNAL_IMPL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)(const combiner_type &combiner_arg,
const group_compare_type &group_compare):
_shared_state(new invocation_state(connection_list_type(group_compare), combiner_arg)),
_garbage_collector_it(_shared_state->connection_bodies().end())
{}
// connect slot
connection connect(const slot_type &slot, connect_position position = at_back)
{
unique_lock<mutex_type> lock(_mutex);
return nolock_connect(slot, position);
}
connection connect(const group_type &group,
const slot_type &slot, connect_position position = at_back)
{
unique_lock<Mutex> lock(_mutex);
return nolock_connect(group, slot, position);
}
// connect extended slot
connection connect_extended(const extended_slot_type &ext_slot, connect_position position = at_back)
{
unique_lock<mutex_type> lock(_mutex);
bound_extended_slot_function_type bound_slot(ext_slot.slot_function());
slot_type slot = replace_slot_function<slot_type>(ext_slot, bound_slot);
connection conn = nolock_connect(slot, position);
bound_slot.set_connection(conn);
return conn;
}
connection connect_extended(const group_type &group,
const extended_slot_type &ext_slot, connect_position position = at_back)
{
unique_lock<Mutex> lock(_mutex);
bound_extended_slot_function_type bound_slot(ext_slot.slot_function());
slot_type slot = replace_slot_function<slot_type>(ext_slot, bound_slot);
connection conn = nolock_connect(group, slot, position);
bound_slot.set_connection(conn);
return conn;
}
// disconnect slot(s)
void disconnect_all_slots()
{
shared_ptr<invocation_state> local_state =
get_readable_state();
typename connection_list_type::iterator it;
for(it = local_state->connection_bodies().begin();
it != local_state->connection_bodies().end(); ++it)
{
(*it)->disconnect();
}
}
void disconnect(const group_type &group)
{
shared_ptr<invocation_state> local_state =
get_readable_state();
group_key_type group_key(grouped_slots, group);
typename connection_list_type::iterator it;
typename connection_list_type::iterator end_it =
local_state->connection_bodies().upper_bound(group_key);
for(it = local_state->connection_bodies().lower_bound(group_key);
it != end_it; ++it)
{
(*it)->disconnect();
}
}
template <typename T>
void disconnect(const T &slot)
{
typedef mpl::bool_<(is_convertible<T, group_type>::value)> is_group;
do_disconnect(slot, is_group());
}
// emit signal
result_type operator ()(BOOST_SIGNALS2_SIGNATURE_FULL_ARGS(BOOST_SIGNALS2_NUM_ARGS))
{
shared_ptr<invocation_state> local_state;
typename connection_list_type::iterator it;
{
unique_lock<mutex_type> list_lock(_mutex);
// only clean up if it is safe to do so
if(_shared_state.unique())
nolock_cleanup_connections(false, 1);
/* Make a local copy of _shared_state while holding mutex, so we are
thread safe against the combiner or connection list getting modified
during invocation. */
local_state = _shared_state;
}
slot_invoker invoker = slot_invoker(BOOST_SIGNALS2_SIGNATURE_ARG_NAMES(BOOST_SIGNALS2_NUM_ARGS));
slot_call_iterator_cache_type cache(invoker);
invocation_janitor janitor(cache, *this, &local_state->connection_bodies());
return detail::combiner_invoker<typename combiner_type::result_type>()
(
local_state->combiner(),
slot_call_iterator(local_state->connection_bodies().begin(), local_state->connection_bodies().end(), cache),
slot_call_iterator(local_state->connection_bodies().end(), local_state->connection_bodies().end(), cache)
);
}
result_type operator ()(BOOST_SIGNALS2_SIGNATURE_FULL_ARGS(BOOST_SIGNALS2_NUM_ARGS)) const
{
shared_ptr<invocation_state> local_state;
typename connection_list_type::iterator it;
{
unique_lock<mutex_type> list_lock(_mutex);
// only clean up if it is safe to do so
if(_shared_state.unique())
nolock_cleanup_connections(false, 1);
/* Make a local copy of _shared_state while holding mutex, so we are
thread safe against the combiner or connection list getting modified
during invocation. */
local_state = _shared_state;
}
slot_invoker invoker = slot_invoker(BOOST_SIGNALS2_SIGNATURE_ARG_NAMES(BOOST_SIGNALS2_NUM_ARGS));
slot_call_iterator_cache_type cache(invoker);
invocation_janitor janitor(cache, *this, &local_state->connection_bodies());
return detail::combiner_invoker<typename combiner_type::result_type>()
(
local_state->combiner(),
slot_call_iterator(local_state->connection_bodies().begin(), local_state->connection_bodies().end(), cache),
slot_call_iterator(local_state->connection_bodies().end(), local_state->connection_bodies().end(), cache)
);
}
std::size_t num_slots() const
{
shared_ptr<invocation_state> local_state =
get_readable_state();
typename connection_list_type::iterator it;
std::size_t count = 0;
for(it = local_state->connection_bodies().begin();
it != local_state->connection_bodies().end(); ++it)
{
if((*it)->connected()) ++count;
}
return count;
}
bool empty() const
{
shared_ptr<invocation_state> local_state =
get_readable_state();
typename connection_list_type::iterator it;
for(it = local_state->connection_bodies().begin();
it != local_state->connection_bodies().end(); ++it)
{
if((*it)->connected()) return false;
}
return true;
}
combiner_type combiner() const
{
unique_lock<mutex_type> lock(_mutex);
return _shared_state->combiner();
}
void set_combiner(const combiner_type &combiner_arg)
{
unique_lock<mutex_type> lock(_mutex);
if(_shared_state.unique())
_shared_state->combiner() = combiner_arg;
else
_shared_state.reset(new invocation_state(*_shared_state, combiner_arg));
}
private:
typedef Mutex mutex_type;
// slot_invoker is passed to slot_call_iterator_t to run slots
#ifdef BOOST_NO_VARIADIC_TEMPLATES
class slot_invoker
{
public:
typedef nonvoid_slot_result_type result_type;
// typename add_reference<Tn>::type
#define BOOST_SIGNALS2_ADD_REF_TYPE(z, n, data) \
typename add_reference<BOOST_PP_CAT(T, BOOST_PP_INC(n))>::type
// typename add_reference<Tn>::type argn
#define BOOST_SIGNALS2_ADD_REF_ARG(z, n, data) \
BOOST_SIGNALS2_ADD_REF_TYPE(~, n, ~) \
BOOST_SIGNALS2_SIGNATURE_ARG_NAME(~, n, ~)
// typename add_reference<T1>::type arg1, typename add_reference<T2>::type arg2, ..., typename add_reference<Tn>::type argn
#define BOOST_SIGNALS2_ADD_REF_ARGS(arity) \
BOOST_PP_ENUM(arity, BOOST_SIGNALS2_ADD_REF_ARG, ~)
slot_invoker(BOOST_SIGNALS2_ADD_REF_ARGS(BOOST_SIGNALS2_NUM_ARGS)) BOOST_PP_IF(BOOST_SIGNALS2_NUM_ARGS, :, )
#undef BOOST_SIGNALS2_ADD_REF_ARGS
// m_argn
#define BOOST_SIGNALS2_M_ARG_NAME(z, n, data) BOOST_PP_CAT(m_arg, BOOST_PP_INC(n))
// m_argn ( argn )
#define BOOST_SIGNALS2_MISC_STATEMENT(z, n, data) \
BOOST_SIGNALS2_M_ARG_NAME(~, n, ~) ( BOOST_SIGNALS2_SIGNATURE_ARG_NAME(~, n, ~) )
// m_arg1(arg1), m_arg2(arg2), ..., m_argn(argn)
BOOST_PP_ENUM(BOOST_SIGNALS2_NUM_ARGS, BOOST_SIGNALS2_MISC_STATEMENT, ~)
#undef BOOST_SIGNALS2_MISC_STATEMENT
{}
result_type operator ()(const connection_body_type &connectionBody) const
{
result_type *resolver = 0;
return m_invoke(connectionBody,
resolver);
}
private:
#define BOOST_SIGNALS2_ADD_REF_M_ARG_STATEMENT(z, n, data) \
BOOST_SIGNALS2_ADD_REF_TYPE(~, n, ~) BOOST_SIGNALS2_M_ARG_NAME(~, n, ~) ;
BOOST_PP_REPEAT(BOOST_SIGNALS2_NUM_ARGS, BOOST_SIGNALS2_ADD_REF_M_ARG_STATEMENT, ~)
#undef BOOST_SIGNALS2_ADD_REF_M_ARG_STATEMENT
#undef BOOST_SIGNALS2_ADD_REF_ARG
#undef BOOST_SIGNALS2_ADD_REF_TYPE
// m_arg1, m_arg2, ..., m_argn
#define BOOST_SIGNALS2_M_ARG_NAMES(arity) BOOST_PP_ENUM(arity, BOOST_SIGNALS2_M_ARG_NAME, ~)
result_type m_invoke(const connection_body_type &connectionBody,
const void_type *) const
{
connectionBody->slot.slot_function()(BOOST_SIGNALS2_M_ARG_NAMES(BOOST_SIGNALS2_NUM_ARGS));
return void_type();
}
result_type m_invoke(const connection_body_type &connectionBody, ...) const
{
return connectionBody->slot.slot_function()(BOOST_SIGNALS2_M_ARG_NAMES(BOOST_SIGNALS2_NUM_ARGS));
}
};
#undef BOOST_SIGNALS2_M_ARG_NAMES
#undef BOOST_SIGNALS2_M_ARG_NAME
#endif // BOOST_NO_VARIADIC_TEMPLATES
// a struct used to optimize (minimize) the number of shared_ptrs that need to be created
// inside operator()
class invocation_state
{
public:
invocation_state(const connection_list_type &connections_in,
const combiner_type &combiner_in): _connection_bodies(new connection_list_type(connections_in)),
_combiner(new combiner_type(combiner_in))
{}
invocation_state(const invocation_state &other, const connection_list_type &connections_in):
_connection_bodies(new connection_list_type(connections_in)),
_combiner(other._combiner)
{}
invocation_state(const invocation_state &other, const combiner_type &combiner_in):
_connection_bodies(other._connection_bodies),
_combiner(new combiner_type(combiner_in))
{}
connection_list_type & connection_bodies() { return *_connection_bodies; }
const connection_list_type & connection_bodies() const { return *_connection_bodies; }
combiner_type & combiner() { return *_combiner; }
const combiner_type & combiner() const { return *_combiner; }
private:
invocation_state(const invocation_state &);
shared_ptr<connection_list_type> _connection_bodies;
shared_ptr<combiner_type> _combiner;
};
// Destructor of invocation_janitor does some cleanup when a signal invocation completes.
// Code can't be put directly in signal's operator() due to complications from void return types.
class invocation_janitor
{
public:
typedef BOOST_SIGNALS2_SIGNAL_IMPL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS) signal_type;
invocation_janitor
(
const slot_call_iterator_cache_type &cache,
const signal_type &sig,
const connection_list_type *connection_bodies
):_cache(cache), _sig(sig), _connection_bodies(connection_bodies)
{}
~invocation_janitor()
{
// force a full cleanup of disconnected slots if there are too many
if(_cache.disconnected_slot_count > _cache.connected_slot_count)
{
_sig.force_cleanup_connections(_connection_bodies);
}
}
private:
const slot_call_iterator_cache_type &_cache;
const signal_type &_sig;
const connection_list_type *_connection_bodies;
};
// clean up disconnected connections
void nolock_cleanup_connections_from(bool grab_tracked,
const typename connection_list_type::iterator &begin, unsigned count = 0) const
{
BOOST_ASSERT(_shared_state.unique());
typename connection_list_type::iterator it;
unsigned i;
for(it = begin, i = 0;
it != _shared_state->connection_bodies().end() && (count == 0 || i < count);
++i)
{
bool connected;
{
unique_lock<connection_body_base> lock(**it);
if(grab_tracked)
(*it)->nolock_slot_expired();
connected = (*it)->nolock_nograb_connected();
}// scoped lock destructs here, safe to erase now
if(connected == false)
{
it = _shared_state->connection_bodies().erase((*it)->group_key(), it);
}else
{
++it;
}
}
_garbage_collector_it = it;
}
// clean up a few connections in constant time
void nolock_cleanup_connections(bool grab_tracked, unsigned count) const
{
BOOST_ASSERT(_shared_state.unique());
typename connection_list_type::iterator begin;
if(_garbage_collector_it == _shared_state->connection_bodies().end())
{
begin = _shared_state->connection_bodies().begin();
}else
{
begin = _garbage_collector_it;
}
nolock_cleanup_connections_from(grab_tracked, begin, count);
}
/* Make a new copy of the slot list if it is currently being read somewhere else
*/
void nolock_force_unique_connection_list()
{
if(_shared_state.unique() == false)
{
_shared_state.reset(new invocation_state(*_shared_state, _shared_state->connection_bodies()));
nolock_cleanup_connections_from(true, _shared_state->connection_bodies().begin());
}else
{
/* We need to try and check more than just 1 connection here to avoid corner
cases where certain repeated connect/disconnect patterns cause the slot
list to grow without limit. */
nolock_cleanup_connections(true, 2);
}
}
// force a full cleanup of the connection list
void force_cleanup_connections(const connection_list_type *connection_bodies) const
{
unique_lock<mutex_type> list_lock(_mutex);
// if the connection list passed in as a parameter is no longer in use,
// we don't need to do any cleanup.
if(&_shared_state->connection_bodies() != connection_bodies)
{
return;
}
if(_shared_state.unique() == false)
{
_shared_state.reset(new invocation_state(*_shared_state, _shared_state->connection_bodies()));
}
nolock_cleanup_connections_from(false, _shared_state->connection_bodies().begin());
}
shared_ptr<invocation_state> get_readable_state() const
{
unique_lock<mutex_type> list_lock(_mutex);
return _shared_state;
}
connection_body_type create_new_connection(const slot_type &slot)
{
nolock_force_unique_connection_list();
return connection_body_type(new connection_body<group_key_type, slot_type, Mutex>(slot));
}
void do_disconnect(const group_type &group, mpl::bool_<true> /* is_group */)
{
disconnect(group);
}
template<typename T>
void do_disconnect(const T &slot, mpl::bool_<false> /* is_group */)
{
shared_ptr<invocation_state> local_state =
get_readable_state();
typename connection_list_type::iterator it;
for(it = local_state->connection_bodies().begin();
it != local_state->connection_bodies().end(); ++it)
{
unique_lock<connection_body_base> lock(**it);
if((*it)->slot.slot_function() == slot)
{
(*it)->nolock_disconnect();
}else
{
// check for wrapped extended slot
bound_extended_slot_function_type *fp;
fp = (*it)->slot.slot_function().template target<bound_extended_slot_function_type>();
if(fp && *fp == slot)
{
(*it)->nolock_disconnect();
}
}
}
}
// connect slot
connection nolock_connect(const slot_type &slot, connect_position position)
{
connection_body_type newConnectionBody =
create_new_connection(slot);
group_key_type group_key;
if(position == at_back)
{
group_key.first = back_ungrouped_slots;
_shared_state->connection_bodies().push_back(group_key, newConnectionBody);
}else
{
group_key.first = front_ungrouped_slots;
_shared_state->connection_bodies().push_front(group_key, newConnectionBody);
}
newConnectionBody->set_group_key(group_key);
return connection(newConnectionBody);
}
connection nolock_connect(const group_type &group,
const slot_type &slot, connect_position position)
{
connection_body_type newConnectionBody =
create_new_connection(slot);
// update map to first connection body in group if needed
group_key_type group_key(grouped_slots, group);
newConnectionBody->set_group_key(group_key);
if(position == at_back)
{
_shared_state->connection_bodies().push_back(group_key, newConnectionBody);
}else // at_front
{
_shared_state->connection_bodies().push_front(group_key, newConnectionBody);
}
return connection(newConnectionBody);
}
// _shared_state is mutable so we can do force_cleanup_connections during a const invocation
mutable shared_ptr<invocation_state> _shared_state;
mutable typename connection_list_type::iterator _garbage_collector_it;
// connection list mutex must never be locked when attempting a blocking lock on a slot,
// or you could deadlock.
mutable mutex_type _mutex;
};
template<BOOST_SIGNALS2_SIGNAL_TEMPLATE_DECL(BOOST_SIGNALS2_NUM_ARGS)>
class BOOST_SIGNALS2_WEAK_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS);
}
template<BOOST_SIGNALS2_SIGNAL_TEMPLATE_DEFAULTED_DECL(BOOST_SIGNALS2_NUM_ARGS)>
class BOOST_SIGNALS2_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS);
template<BOOST_SIGNALS2_SIGNAL_TEMPLATE_SPECIALIZATION_DECL(BOOST_SIGNALS2_NUM_ARGS)>
class BOOST_SIGNALS2_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)
BOOST_SIGNALS2_SIGNAL_TEMPLATE_SPECIALIZATION: public signal_base,
public detail::BOOST_SIGNALS2_STD_FUNCTIONAL_BASE
(typename detail::result_type_wrapper<typename Combiner::result_type>::type)
{
typedef detail::BOOST_SIGNALS2_SIGNAL_IMPL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)
<BOOST_SIGNALS2_SIGNAL_TEMPLATE_INSTANTIATION> impl_class;
public:
typedef detail::BOOST_SIGNALS2_WEAK_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)
<BOOST_SIGNALS2_SIGNAL_TEMPLATE_INSTANTIATION> weak_signal_type;
friend class detail::BOOST_SIGNALS2_WEAK_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)
<BOOST_SIGNALS2_SIGNAL_TEMPLATE_INSTANTIATION>;
typedef SlotFunction slot_function_type;
// typedef slotN<Signature, SlotFunction> slot_type;
typedef typename impl_class::slot_type slot_type;
typedef typename impl_class::extended_slot_function_type extended_slot_function_type;
typedef typename impl_class::extended_slot_type extended_slot_type;
typedef typename slot_function_type::result_type slot_result_type;
typedef Combiner combiner_type;
typedef typename impl_class::result_type result_type;
typedef Group group_type;
typedef GroupCompare group_compare_type;
typedef typename impl_class::slot_call_iterator
slot_call_iterator;
typedef typename mpl::identity<BOOST_SIGNALS2_SIGNATURE_FUNCTION_TYPE(BOOST_SIGNALS2_NUM_ARGS)>::type signature_type;
#ifdef BOOST_NO_VARIADIC_TEMPLATES
// typedef Tn argn_type;
#define BOOST_SIGNALS2_MISC_STATEMENT(z, n, data) \
typedef BOOST_PP_CAT(T, BOOST_PP_INC(n)) BOOST_PP_CAT(BOOST_PP_CAT(arg, BOOST_PP_INC(n)), _type);
BOOST_PP_REPEAT(BOOST_SIGNALS2_NUM_ARGS, BOOST_SIGNALS2_MISC_STATEMENT, ~)
#undef BOOST_SIGNALS2_MISC_STATEMENT
#if BOOST_SIGNALS2_NUM_ARGS == 1
typedef arg1_type argument_type;
#elif BOOST_SIGNALS2_NUM_ARGS == 2
typedef arg1_type first_argument_type;
typedef arg2_type second_argument_type;
#endif
template<unsigned n> class arg : public
detail::BOOST_SIGNALS2_PREPROCESSED_ARG_N_TYPE_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)
<n BOOST_SIGNALS2_PP_COMMA_IF(BOOST_SIGNALS2_NUM_ARGS)
BOOST_SIGNALS2_ARGS_TEMPLATE_INSTANTIATION(BOOST_SIGNALS2_NUM_ARGS)>
{};
BOOST_STATIC_CONSTANT(int, arity = BOOST_SIGNALS2_NUM_ARGS);
#else // BOOST_NO_VARIADIC_TEMPLATES
template<unsigned n> class arg
{
public:
typedef typename detail::variadic_arg_type<n, Args...>::type type;
};
BOOST_STATIC_CONSTANT(int, arity = sizeof...(Args));
#endif // BOOST_NO_VARIADIC_TEMPLATES
BOOST_SIGNALS2_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)(const combiner_type &combiner_arg = combiner_type(),
const group_compare_type &group_compare = group_compare_type()):
_pimpl(new impl_class(combiner_arg, group_compare))
{};
virtual ~BOOST_SIGNALS2_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)()
{
disconnect_all_slots();
}
connection connect(const slot_type &slot, connect_position position = at_back)
{
return (*_pimpl).connect(slot, position);
}
connection connect(const group_type &group,
const slot_type &slot, connect_position position = at_back)
{
return (*_pimpl).connect(group, slot, position);
}
connection connect_extended(const extended_slot_type &slot, connect_position position = at_back)
{
return (*_pimpl).connect_extended(slot, position);
}
connection connect_extended(const group_type &group,
const extended_slot_type &slot, connect_position position = at_back)
{
return (*_pimpl).connect_extended(group, slot, position);
}
void disconnect_all_slots()
{
(*_pimpl).disconnect_all_slots();
}
void disconnect(const group_type &group)
{
(*_pimpl).disconnect(group);
}
template <typename T>
void disconnect(const T &slot)
{
(*_pimpl).disconnect(slot);
}
result_type operator ()(BOOST_SIGNALS2_SIGNATURE_FULL_ARGS(BOOST_SIGNALS2_NUM_ARGS))
{
return (*_pimpl)(BOOST_SIGNALS2_SIGNATURE_ARG_NAMES(BOOST_SIGNALS2_NUM_ARGS));
}
result_type operator ()(BOOST_SIGNALS2_SIGNATURE_FULL_ARGS(BOOST_SIGNALS2_NUM_ARGS)) const
{
return (*_pimpl)(BOOST_SIGNALS2_SIGNATURE_ARG_NAMES(BOOST_SIGNALS2_NUM_ARGS));
}
std::size_t num_slots() const
{
return (*_pimpl).num_slots();
}
bool empty() const
{
return (*_pimpl).empty();
}
combiner_type combiner() const
{
return (*_pimpl).combiner();
}
void set_combiner(const combiner_type &combiner_arg)
{
return (*_pimpl).set_combiner(combiner_arg);
}
protected:
virtual shared_ptr<void> lock_pimpl() const
{
return _pimpl;
}
private:
shared_ptr<impl_class>
_pimpl;
};
namespace detail
{
// wrapper class for storing other signals as slots with automatic lifetime tracking
template<BOOST_SIGNALS2_SIGNAL_TEMPLATE_DECL(BOOST_SIGNALS2_NUM_ARGS)>
class BOOST_SIGNALS2_WEAK_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS);
template<BOOST_SIGNALS2_SIGNAL_TEMPLATE_SPECIALIZATION_DECL(BOOST_SIGNALS2_NUM_ARGS)>
class BOOST_SIGNALS2_WEAK_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)
BOOST_SIGNALS2_SIGNAL_TEMPLATE_SPECIALIZATION
{
public:
typedef typename BOOST_SIGNALS2_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)
<BOOST_SIGNALS2_SIGNAL_TEMPLATE_INSTANTIATION>::result_type
result_type;
BOOST_SIGNALS2_WEAK_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)
(const BOOST_SIGNALS2_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)
<BOOST_SIGNALS2_SIGNAL_TEMPLATE_INSTANTIATION>
&signal):
_weak_pimpl(signal._pimpl)
{}
result_type operator ()(BOOST_SIGNALS2_SIGNATURE_FULL_ARGS(BOOST_SIGNALS2_NUM_ARGS))
{
shared_ptr<detail::BOOST_SIGNALS2_SIGNAL_IMPL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)
<BOOST_SIGNALS2_SIGNAL_TEMPLATE_INSTANTIATION> >
shared_pimpl(_weak_pimpl.lock());
if(shared_pimpl == 0) boost::throw_exception(expired_slot());
return (*shared_pimpl)(BOOST_SIGNALS2_SIGNATURE_ARG_NAMES(BOOST_SIGNALS2_NUM_ARGS));
}
result_type operator ()(BOOST_SIGNALS2_SIGNATURE_FULL_ARGS(BOOST_SIGNALS2_NUM_ARGS)) const
{
shared_ptr<detail::BOOST_SIGNALS2_SIGNAL_IMPL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)
<BOOST_SIGNALS2_SIGNAL_TEMPLATE_INSTANTIATION> >
shared_pimpl(_weak_pimpl.lock());
if(shared_pimpl == 0) boost::throw_exception(expired_slot());
return (*shared_pimpl)(BOOST_SIGNALS2_SIGNATURE_ARG_NAMES(BOOST_SIGNALS2_NUM_ARGS));
}
private:
boost::weak_ptr<detail::BOOST_SIGNALS2_SIGNAL_IMPL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)
<BOOST_SIGNALS2_SIGNAL_TEMPLATE_INSTANTIATION> > _weak_pimpl;
};
#ifndef BOOST_NO_VARIADIC_TEMPLATES
template<int arity, typename Signature>
class extended_signature: public variadic_extended_signature<Signature>
{};
#else // BOOST_NO_VARIADIC_TEMPLATES
template<int arity, typename Signature>
class extended_signature;
// partial template specialization
template<typename Signature>
class extended_signature<BOOST_SIGNALS2_NUM_ARGS, Signature>
{
public:
// typename function_traits<Signature>::result_type (
// const boost::signals2::connection &,
// typename function_traits<Signature>::arg1_type,
// typename function_traits<Signature>::arg2_type,
// ...,
// typename function_traits<Signature>::argn_type)
#define BOOST_SIGNALS2_EXT_SIGNATURE(arity, Signature) \
typename function_traits<Signature>::result_type ( \
const boost::signals2::connection & BOOST_SIGNALS2_PP_COMMA_IF(BOOST_SIGNALS2_NUM_ARGS) \
BOOST_PP_ENUM(arity, BOOST_SIGNALS2_SIGNATURE_TO_ARGN_TYPE, Signature) )
typedef function<BOOST_SIGNALS2_EXT_SIGNATURE(BOOST_SIGNALS2_NUM_ARGS, Signature)> function_type;
#undef BOOST_SIGNALS2_EXT_SIGNATURE
};
template<unsigned arity, typename Signature, typename Combiner,
typename Group, typename GroupCompare, typename SlotFunction,
typename ExtendedSlotFunction, typename Mutex>
class signalN;
// partial template specialization
template<typename Signature, typename Combiner, typename Group,
typename GroupCompare, typename SlotFunction,
typename ExtendedSlotFunction, typename Mutex>
class signalN<BOOST_SIGNALS2_NUM_ARGS, Signature, Combiner, Group,
GroupCompare, SlotFunction, ExtendedSlotFunction, Mutex>
{
public:
typedef BOOST_SIGNALS2_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)<
BOOST_SIGNALS2_PORTABLE_SIGNATURE(BOOST_SIGNALS2_NUM_ARGS, Signature),
Combiner, Group,
GroupCompare, SlotFunction, ExtendedSlotFunction, Mutex> type;
};
#endif // BOOST_NO_VARIADIC_TEMPLATES
} // namespace detail
} // namespace signals2
} // namespace boost
#undef BOOST_SIGNALS2_NUM_ARGS
#undef BOOST_SIGNALS2_SIGNAL_TEMPLATE_INSTANTIATION