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