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