You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and dots ('.'), can be up to 35 characters long. Letters must be lowercase.
410 lines
13 KiB
410 lines
13 KiB
// Boost.Signals library |
|
|
|
// Copyright Douglas Gregor 2001-2004. 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) |
|
|
|
// For more information, see http://www.boost.org |
|
|
|
// This file intentionally does not have include guards, because it is meant |
|
// to be included multiple times (one for each signalN class). The |
|
// BOOST_SIGNALS_SIGNAL_TEMPLATE_HEADER_INCLUDED macro merely serves to |
|
// suppress reinclusion of the files that this header depends on. |
|
|
|
#ifndef BOOST_SIGNALS_SIGNAL_TEMPLATE_HEADER_INCLUDED |
|
#define BOOST_SIGNALS_SIGNAL_TEMPLATE_HEADER_INCLUDED |
|
# include <boost/config.hpp> |
|
# include <boost/signals/connection.hpp> |
|
# include <boost/utility.hpp> |
|
# include <boost/ref.hpp> |
|
# include <boost/signals/slot.hpp> |
|
# include <boost/last_value.hpp> |
|
# include <boost/signals/detail/signal_base.hpp> |
|
# include <boost/signals/detail/slot_call_iterator.hpp> |
|
# include <boost/mpl/bool.hpp> |
|
# include <boost/type_traits/is_convertible.hpp> |
|
# include <cassert> |
|
# include <functional> |
|
# include <memory> |
|
#endif // !BOOST_SIGNALS_SIGNAL_TEMPLATE_HEADER_INCLUDED |
|
|
|
#ifdef BOOST_HAS_ABI_HEADERS |
|
# include BOOST_ABI_PREFIX |
|
#endif |
|
|
|
// Include the appropriate functionN header |
|
#define BOOST_SIGNAL_FUNCTION_N_HEADER BOOST_JOIN(<boost/function/function,BOOST_SIGNALS_NUM_ARGS.hpp>) |
|
#include BOOST_SIGNAL_FUNCTION_N_HEADER |
|
|
|
// Determine if a comma should follow a listing of the arguments/parameters |
|
#if BOOST_SIGNALS_NUM_ARGS == 0 |
|
# define BOOST_SIGNALS_COMMA_IF_NONZERO_ARGS |
|
#else |
|
# define BOOST_SIGNALS_COMMA_IF_NONZERO_ARGS , |
|
#endif // BOOST_SIGNALS_NUM_ARGS > 0 |
|
|
|
// Define class names used |
|
#define BOOST_SIGNALS_SIGNAL BOOST_JOIN(signal,BOOST_SIGNALS_NUM_ARGS) |
|
#define BOOST_SIGNALS_FUNCTION BOOST_JOIN(function,BOOST_SIGNALS_NUM_ARGS) |
|
#define BOOST_SIGNALS_ARGS_STRUCT BOOST_JOIN(args,BOOST_SIGNALS_NUM_ARGS) |
|
#define BOOST_SIGNALS_CALL_BOUND BOOST_JOIN(call_bound,BOOST_SIGNALS_NUM_ARGS) |
|
|
|
// Define commonly-used instantiations |
|
#define BOOST_SIGNALS_ARGS_STRUCT_INST \ |
|
BOOST_SIGNALS_NAMESPACE::detail::BOOST_SIGNALS_ARGS_STRUCT<BOOST_SIGNALS_TEMPLATE_ARGS> |
|
|
|
namespace boost { |
|
namespace BOOST_SIGNALS_NAMESPACE { |
|
namespace detail { |
|
// Holds the arguments for a bound slot call in a single place |
|
template<BOOST_SIGNALS_TEMPLATE_PARMS |
|
BOOST_SIGNALS_COMMA_IF_NONZERO_ARGS |
|
typename Dummy = int> |
|
struct BOOST_SIGNALS_ARGS_STRUCT { |
|
BOOST_SIGNALS_ARGS_STRUCT(BOOST_SIGNALS_COPY_PARMS) |
|
BOOST_SIGNALS_INIT_ARGS |
|
{ |
|
} |
|
|
|
BOOST_SIGNALS_ARGS_AS_MEMBERS |
|
}; |
|
|
|
// Function object that calls the function object given to it, passing |
|
// the bound arguments along to that underlying function object |
|
template<typename R> |
|
struct BOOST_SIGNALS_CALL_BOUND { |
|
template<BOOST_SIGNALS_TEMPLATE_PARMS |
|
BOOST_SIGNALS_COMMA_IF_NONZERO_ARGS |
|
typename F> |
|
struct caller { |
|
typedef BOOST_SIGNALS_ARGS_STRUCT<BOOST_SIGNALS_TEMPLATE_ARGS>* |
|
args_type; |
|
|
|
args_type args; |
|
|
|
typedef R result_type; |
|
|
|
caller() {} |
|
caller(args_type a) : args(a) {} |
|
|
|
template<typename Pair> |
|
R operator()(const Pair& slot) const |
|
{ |
|
F* target = const_cast<F*>(unsafe_any_cast<F>(&slot.second)); |
|
return (*target)(BOOST_SIGNALS_BOUND_ARGS); |
|
} |
|
}; |
|
}; |
|
|
|
template<> |
|
struct BOOST_SIGNALS_CALL_BOUND<void> { |
|
template<BOOST_SIGNALS_TEMPLATE_PARMS |
|
BOOST_SIGNALS_COMMA_IF_NONZERO_ARGS |
|
typename F> |
|
struct caller { |
|
typedef BOOST_SIGNALS_ARGS_STRUCT<BOOST_SIGNALS_TEMPLATE_ARGS>* |
|
args_type; |
|
|
|
args_type args; |
|
|
|
typedef unusable result_type; |
|
|
|
caller(args_type a) : args(a) {} |
|
|
|
template<typename Pair> |
|
unusable operator()(const Pair& slot) const |
|
{ |
|
F* target = const_cast<F*>(unsafe_any_cast<F>(&slot.second)); |
|
(*target)(BOOST_SIGNALS_BOUND_ARGS); |
|
return unusable(); |
|
} |
|
}; |
|
}; |
|
} // namespace detail |
|
} // namespace BOOST_SIGNALS_NAMESPACE |
|
|
|
// The actual signalN class |
|
template< |
|
typename R, |
|
BOOST_SIGNALS_TEMPLATE_PARMS |
|
BOOST_SIGNALS_COMMA_IF_NONZERO_ARGS |
|
typename Combiner = last_value<R>, |
|
typename Group = int, |
|
typename GroupCompare = std::less<Group>, |
|
typename SlotFunction = BOOST_SIGNALS_FUNCTION< |
|
R BOOST_SIGNALS_COMMA_IF_NONZERO_ARGS |
|
BOOST_SIGNALS_TEMPLATE_ARGS> |
|
> |
|
class BOOST_SIGNALS_SIGNAL : |
|
public BOOST_SIGNALS_NAMESPACE::detail::signal_base, // management of slot list |
|
public BOOST_SIGNALS_NAMESPACE::trackable // signals are trackable |
|
{ |
|
public: |
|
// The slot function type |
|
typedef SlotFunction slot_function_type; |
|
|
|
// Result type of a slot |
|
typedef typename BOOST_SIGNALS_NAMESPACE::detail::slot_result_type<R>::type |
|
slot_result_type; |
|
|
|
// Argument types |
|
BOOST_SIGNALS_ARG_TYPES |
|
|
|
#if BOOST_SIGNALS_NUM_ARGS == 1 |
|
typedef T1 argument_type; |
|
#elif BOOST_SIGNALS_NUM_ARGS == 2 |
|
typedef T1 first_argument_type; |
|
typedef T2 second_argument_type; |
|
#endif |
|
|
|
private: |
|
// The real slot name comparison object type |
|
typedef BOOST_SIGNALS_NAMESPACE::detail::group_bridge_compare<GroupCompare, Group> |
|
real_group_compare_type; |
|
|
|
// The function object passed to the slot call iterator that will call |
|
// the underlying slot function with its arguments bound |
|
typedef BOOST_SIGNALS_NAMESPACE::detail::BOOST_SIGNALS_CALL_BOUND<R> |
|
outer_bound_slot_caller; |
|
typedef typename outer_bound_slot_caller::template |
|
caller<BOOST_SIGNALS_TEMPLATE_ARGS |
|
BOOST_SIGNALS_COMMA_IF_NONZERO_ARGS |
|
slot_function_type> |
|
call_bound_slot; |
|
|
|
public: |
|
// Combiner's result type |
|
typedef typename Combiner::result_type result_type; |
|
|
|
// Combiner type |
|
typedef Combiner combiner_type; |
|
|
|
// Slot type |
|
typedef slot<slot_function_type> slot_type; |
|
|
|
// Slot name type and comparison |
|
typedef Group group_type; |
|
typedef GroupCompare group_compare_type; |
|
|
|
typedef BOOST_SIGNALS_NAMESPACE::detail::slot_call_iterator< |
|
call_bound_slot, iterator> slot_call_iterator; |
|
|
|
explicit |
|
BOOST_SIGNALS_SIGNAL(const Combiner& c = Combiner(), |
|
const GroupCompare& comp = GroupCompare()) : |
|
BOOST_SIGNALS_NAMESPACE::detail::signal_base(real_group_compare_type(comp), |
|
c) |
|
{ |
|
} |
|
|
|
// Connect a slot to this signal |
|
BOOST_SIGNALS_NAMESPACE::connection |
|
connect(const slot_type&, |
|
BOOST_SIGNALS_NAMESPACE::connect_position at |
|
= BOOST_SIGNALS_NAMESPACE::at_back); |
|
|
|
|
|
BOOST_SIGNALS_NAMESPACE::connection |
|
connect(const group_type&, const slot_type&, |
|
BOOST_SIGNALS_NAMESPACE::connect_position at |
|
= BOOST_SIGNALS_NAMESPACE::at_back); |
|
|
|
#if BOOST_WORKAROUND(BOOST_MSVC, <= 1300) |
|
// MSVC 6.0 and 7.0 don't handle the is_convertible test well |
|
void disconnect(const group_type& group) |
|
{ |
|
impl->disconnect(group); |
|
} |
|
#else |
|
template<typename T> |
|
void disconnect(const T& t) |
|
{ |
|
typedef mpl::bool_<(is_convertible<T, group_type>::value)> is_group; |
|
this->do_disconnect(t, is_group()); |
|
} |
|
|
|
private: |
|
// Disconnect a named slot |
|
void do_disconnect(const group_type& group, mpl::bool_<true>) |
|
{ |
|
impl->disconnect(group); |
|
} |
|
|
|
template<typename Function> |
|
void do_disconnect(const Function& f, mpl::bool_<false>) |
|
{ |
|
// Notify the slot handling code that we are iterating through the slots |
|
BOOST_SIGNALS_NAMESPACE::detail::call_notification notification(this->impl); |
|
|
|
for (iterator i = impl->slots_.begin(); i != impl->slots_.end(); ++i) { |
|
slot_function_type& s = *unsafe_any_cast<slot_function_type>(&i->second); |
|
if (s == f) i->first.disconnect(); |
|
} |
|
} |
|
#endif |
|
|
|
public: |
|
|
|
// Emit the signal |
|
result_type operator()(BOOST_SIGNALS_PARMS); |
|
result_type operator()(BOOST_SIGNALS_PARMS) const; |
|
|
|
Combiner& combiner() |
|
{ return *unsafe_any_cast<Combiner>(&impl->combiner_); } |
|
|
|
const Combiner& combiner() const |
|
{ return *unsafe_any_cast<const Combiner>(&impl->combiner_); } |
|
}; |
|
|
|
template< |
|
typename R, |
|
BOOST_SIGNALS_TEMPLATE_PARMS |
|
BOOST_SIGNALS_COMMA_IF_NONZERO_ARGS |
|
typename Combiner, |
|
typename Group, |
|
typename GroupCompare, |
|
typename SlotFunction |
|
> |
|
BOOST_SIGNALS_NAMESPACE::connection |
|
BOOST_SIGNALS_SIGNAL< |
|
R, BOOST_SIGNALS_TEMPLATE_ARGS |
|
BOOST_SIGNALS_COMMA_IF_NONZERO_ARGS |
|
Combiner, Group, GroupCompare, SlotFunction |
|
>::connect(const slot_type& in_slot, |
|
BOOST_SIGNALS_NAMESPACE::connect_position at) |
|
{ |
|
using boost::BOOST_SIGNALS_NAMESPACE::detail::stored_group; |
|
|
|
// If the slot has been disconnected, just return a disconnected |
|
// connection |
|
if (!in_slot.is_active()) { |
|
return BOOST_SIGNALS_NAMESPACE::connection(); |
|
} |
|
|
|
return impl->connect_slot(in_slot.get_slot_function(), stored_group(), |
|
in_slot.get_data(), at); |
|
} |
|
|
|
template< |
|
typename R, |
|
BOOST_SIGNALS_TEMPLATE_PARMS |
|
BOOST_SIGNALS_COMMA_IF_NONZERO_ARGS |
|
typename Combiner, |
|
typename Group, |
|
typename GroupCompare, |
|
typename SlotFunction |
|
> |
|
BOOST_SIGNALS_NAMESPACE::connection |
|
BOOST_SIGNALS_SIGNAL< |
|
R, BOOST_SIGNALS_TEMPLATE_ARGS |
|
BOOST_SIGNALS_COMMA_IF_NONZERO_ARGS |
|
Combiner, Group, GroupCompare, SlotFunction |
|
>::connect(const group_type& group, |
|
const slot_type& in_slot, |
|
BOOST_SIGNALS_NAMESPACE::connect_position at) |
|
{ |
|
// If the slot has been disconnected, just return a disconnected |
|
// connection |
|
if (!in_slot.is_active()) { |
|
return BOOST_SIGNALS_NAMESPACE::connection(); |
|
} |
|
|
|
return impl->connect_slot(in_slot.get_slot_function(), group, |
|
in_slot.get_data(), at); |
|
} |
|
|
|
template< |
|
typename R, |
|
BOOST_SIGNALS_TEMPLATE_PARMS |
|
BOOST_SIGNALS_COMMA_IF_NONZERO_ARGS |
|
typename Combiner, |
|
typename Group, |
|
typename GroupCompare, |
|
typename SlotFunction |
|
> |
|
typename BOOST_SIGNALS_SIGNAL< |
|
R, BOOST_SIGNALS_TEMPLATE_ARGS |
|
BOOST_SIGNALS_COMMA_IF_NONZERO_ARGS |
|
Combiner, Group, GroupCompare, SlotFunction>::result_type |
|
BOOST_SIGNALS_SIGNAL< |
|
R, BOOST_SIGNALS_TEMPLATE_ARGS |
|
BOOST_SIGNALS_COMMA_IF_NONZERO_ARGS |
|
Combiner, Group, GroupCompare, SlotFunction |
|
>::operator()(BOOST_SIGNALS_PARMS) |
|
{ |
|
// Notify the slot handling code that we are making a call |
|
BOOST_SIGNALS_NAMESPACE::detail::call_notification notification(this->impl); |
|
|
|
// Construct a function object that will call the underlying slots |
|
// with the given arguments. |
|
#if BOOST_SIGNALS_NUM_ARGS == 0 |
|
BOOST_SIGNALS_ARGS_STRUCT_INST args; |
|
#else |
|
BOOST_SIGNALS_ARGS_STRUCT_INST args(BOOST_SIGNALS_ARGS); |
|
#endif // BOOST_SIGNALS_NUM_ARGS > 0 |
|
call_bound_slot f(&args); |
|
|
|
typedef typename call_bound_slot::result_type call_result_type; |
|
optional<call_result_type> cache; |
|
// Let the combiner call the slots via a pair of input iterators |
|
return combiner()(slot_call_iterator(notification.impl->slots_.begin(), |
|
impl->slots_.end(), f, cache), |
|
slot_call_iterator(notification.impl->slots_.end(), |
|
impl->slots_.end(), f, cache)); |
|
} |
|
|
|
template< |
|
typename R, |
|
BOOST_SIGNALS_TEMPLATE_PARMS |
|
BOOST_SIGNALS_COMMA_IF_NONZERO_ARGS |
|
typename Combiner, |
|
typename Group, |
|
typename GroupCompare, |
|
typename SlotFunction |
|
> |
|
typename BOOST_SIGNALS_SIGNAL< |
|
R, BOOST_SIGNALS_TEMPLATE_ARGS |
|
BOOST_SIGNALS_COMMA_IF_NONZERO_ARGS |
|
Combiner, Group, GroupCompare, SlotFunction>::result_type |
|
BOOST_SIGNALS_SIGNAL< |
|
R, BOOST_SIGNALS_TEMPLATE_ARGS |
|
BOOST_SIGNALS_COMMA_IF_NONZERO_ARGS |
|
Combiner, Group, GroupCompare, SlotFunction |
|
>::operator()(BOOST_SIGNALS_PARMS) const |
|
{ |
|
// Notify the slot handling code that we are making a call |
|
BOOST_SIGNALS_NAMESPACE::detail::call_notification notification(this->impl); |
|
|
|
// Construct a function object that will call the underlying slots |
|
// with the given arguments. |
|
#if BOOST_SIGNALS_NUM_ARGS == 0 |
|
BOOST_SIGNALS_ARGS_STRUCT_INST args; |
|
#else |
|
BOOST_SIGNALS_ARGS_STRUCT_INST args(BOOST_SIGNALS_ARGS); |
|
#endif // BOOST_SIGNALS_NUM_ARGS > 0 |
|
|
|
call_bound_slot f(&args); |
|
|
|
typedef typename call_bound_slot::result_type call_result_type; |
|
optional<call_result_type> cache; |
|
|
|
// Let the combiner call the slots via a pair of input iterators |
|
return combiner()(slot_call_iterator(notification.impl->slots_.begin(), |
|
impl->slots_.end(), f, cache), |
|
slot_call_iterator(notification.impl->slots_.end(), |
|
impl->slots_.end(), f, cache)); |
|
} |
|
} // namespace boost |
|
|
|
#undef BOOST_SIGNAL_FUNCTION_N_HEADER |
|
#undef BOOST_SIGNALS_ARGS_STRUCT_INST |
|
#undef BOOST_SIGNALS_CALL_BOUND |
|
#undef BOOST_SIGNALS_ARGS_STRUCT |
|
#undef BOOST_SIGNALS_FUNCTION |
|
#undef BOOST_SIGNALS_SIGNAL |
|
#undef BOOST_SIGNALS_COMMA_IF_NONZERO_ARGS |
|
|
|
#ifdef BOOST_HAS_ABI_HEADERS |
|
# include BOOST_ABI_SUFFIX |
|
#endif
|
|
|