| // 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 result_type; |
| optional<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 result_type; |
| optional<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 |