// 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