signal_template.hpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410
  1. // Boost.Signals library
  2. // Copyright Douglas Gregor 2001-2004. Use, modification and
  3. // distribution is subject to the Boost Software License, Version
  4. // 1.0. (See accompanying file LICENSE_1_0.txt or copy at
  5. // http://www.boost.org/LICENSE_1_0.txt)
  6. // For more information, see http://www.boost.org
  7. // This file intentionally does not have include guards, because it is meant
  8. // to be included multiple times (one for each signalN class). The
  9. // BOOST_SIGNALS_SIGNAL_TEMPLATE_HEADER_INCLUDED macro merely serves to
  10. // suppress reinclusion of the files that this header depends on.
  11. #ifndef BOOST_SIGNALS_SIGNAL_TEMPLATE_HEADER_INCLUDED
  12. #define BOOST_SIGNALS_SIGNAL_TEMPLATE_HEADER_INCLUDED
  13. # include <boost/config.hpp>
  14. # include <boost/signals/connection.hpp>
  15. # include <boost/utility.hpp>
  16. # include <boost/ref.hpp>
  17. # include <boost/signals/slot.hpp>
  18. # include <boost/last_value.hpp>
  19. # include <boost/signals/detail/signal_base.hpp>
  20. # include <boost/signals/detail/slot_call_iterator.hpp>
  21. # include <boost/mpl/bool.hpp>
  22. # include <boost/type_traits/is_convertible.hpp>
  23. # include <cassert>
  24. # include <functional>
  25. # include <memory>
  26. #endif // !BOOST_SIGNALS_SIGNAL_TEMPLATE_HEADER_INCLUDED
  27. #ifdef BOOST_HAS_ABI_HEADERS
  28. # include BOOST_ABI_PREFIX
  29. #endif
  30. // Include the appropriate functionN header
  31. #define BOOST_SIGNAL_FUNCTION_N_HEADER BOOST_JOIN(<boost/function/function,BOOST_SIGNALS_NUM_ARGS.hpp>)
  32. #include BOOST_SIGNAL_FUNCTION_N_HEADER
  33. // Determine if a comma should follow a listing of the arguments/parameters
  34. #if BOOST_SIGNALS_NUM_ARGS == 0
  35. # define BOOST_SIGNALS_COMMA_IF_NONZERO_ARGS
  36. #else
  37. # define BOOST_SIGNALS_COMMA_IF_NONZERO_ARGS ,
  38. #endif // BOOST_SIGNALS_NUM_ARGS > 0
  39. // Define class names used
  40. #define BOOST_SIGNALS_SIGNAL BOOST_JOIN(signal,BOOST_SIGNALS_NUM_ARGS)
  41. #define BOOST_SIGNALS_FUNCTION BOOST_JOIN(function,BOOST_SIGNALS_NUM_ARGS)
  42. #define BOOST_SIGNALS_ARGS_STRUCT BOOST_JOIN(args,BOOST_SIGNALS_NUM_ARGS)
  43. #define BOOST_SIGNALS_CALL_BOUND BOOST_JOIN(call_bound,BOOST_SIGNALS_NUM_ARGS)
  44. // Define commonly-used instantiations
  45. #define BOOST_SIGNALS_ARGS_STRUCT_INST \
  46. BOOST_SIGNALS_NAMESPACE::detail::BOOST_SIGNALS_ARGS_STRUCT<BOOST_SIGNALS_TEMPLATE_ARGS>
  47. namespace boost {
  48. namespace BOOST_SIGNALS_NAMESPACE {
  49. namespace detail {
  50. // Holds the arguments for a bound slot call in a single place
  51. template<BOOST_SIGNALS_TEMPLATE_PARMS
  52. BOOST_SIGNALS_COMMA_IF_NONZERO_ARGS
  53. typename Dummy = int>
  54. struct BOOST_SIGNALS_ARGS_STRUCT {
  55. BOOST_SIGNALS_ARGS_STRUCT(BOOST_SIGNALS_COPY_PARMS)
  56. BOOST_SIGNALS_INIT_ARGS
  57. {
  58. }
  59. BOOST_SIGNALS_ARGS_AS_MEMBERS
  60. };
  61. // Function object that calls the function object given to it, passing
  62. // the bound arguments along to that underlying function object
  63. template<typename R>
  64. struct BOOST_SIGNALS_CALL_BOUND {
  65. template<BOOST_SIGNALS_TEMPLATE_PARMS
  66. BOOST_SIGNALS_COMMA_IF_NONZERO_ARGS
  67. typename F>
  68. struct caller {
  69. typedef BOOST_SIGNALS_ARGS_STRUCT<BOOST_SIGNALS_TEMPLATE_ARGS>*
  70. args_type;
  71. args_type args;
  72. typedef R result_type;
  73. caller() {}
  74. caller(args_type a) : args(a) {}
  75. template<typename Pair>
  76. R operator()(const Pair& slot) const
  77. {
  78. F* target = const_cast<F*>(unsafe_any_cast<F>(&slot.second));
  79. return (*target)(BOOST_SIGNALS_BOUND_ARGS);
  80. }
  81. };
  82. };
  83. template<>
  84. struct BOOST_SIGNALS_CALL_BOUND<void> {
  85. template<BOOST_SIGNALS_TEMPLATE_PARMS
  86. BOOST_SIGNALS_COMMA_IF_NONZERO_ARGS
  87. typename F>
  88. struct caller {
  89. typedef BOOST_SIGNALS_ARGS_STRUCT<BOOST_SIGNALS_TEMPLATE_ARGS>*
  90. args_type;
  91. args_type args;
  92. typedef unusable result_type;
  93. caller(args_type a) : args(a) {}
  94. template<typename Pair>
  95. unusable operator()(const Pair& slot) const
  96. {
  97. F* target = const_cast<F*>(unsafe_any_cast<F>(&slot.second));
  98. (*target)(BOOST_SIGNALS_BOUND_ARGS);
  99. return unusable();
  100. }
  101. };
  102. };
  103. } // namespace detail
  104. } // namespace BOOST_SIGNALS_NAMESPACE
  105. // The actual signalN class
  106. template<
  107. typename R,
  108. BOOST_SIGNALS_TEMPLATE_PARMS
  109. BOOST_SIGNALS_COMMA_IF_NONZERO_ARGS
  110. typename Combiner = last_value<R>,
  111. typename Group = int,
  112. typename GroupCompare = std::less<Group>,
  113. typename SlotFunction = BOOST_SIGNALS_FUNCTION<
  114. R BOOST_SIGNALS_COMMA_IF_NONZERO_ARGS
  115. BOOST_SIGNALS_TEMPLATE_ARGS>
  116. >
  117. class BOOST_SIGNALS_SIGNAL :
  118. public BOOST_SIGNALS_NAMESPACE::detail::signal_base, // management of slot list
  119. public BOOST_SIGNALS_NAMESPACE::trackable // signals are trackable
  120. {
  121. public:
  122. // The slot function type
  123. typedef SlotFunction slot_function_type;
  124. // Result type of a slot
  125. typedef typename BOOST_SIGNALS_NAMESPACE::detail::slot_result_type<R>::type
  126. slot_result_type;
  127. // Argument types
  128. BOOST_SIGNALS_ARG_TYPES
  129. #if BOOST_SIGNALS_NUM_ARGS == 1
  130. typedef T1 argument_type;
  131. #elif BOOST_SIGNALS_NUM_ARGS == 2
  132. typedef T1 first_argument_type;
  133. typedef T2 second_argument_type;
  134. #endif
  135. private:
  136. // The real slot name comparison object type
  137. typedef BOOST_SIGNALS_NAMESPACE::detail::group_bridge_compare<GroupCompare, Group>
  138. real_group_compare_type;
  139. // The function object passed to the slot call iterator that will call
  140. // the underlying slot function with its arguments bound
  141. typedef BOOST_SIGNALS_NAMESPACE::detail::BOOST_SIGNALS_CALL_BOUND<R>
  142. outer_bound_slot_caller;
  143. typedef typename outer_bound_slot_caller::template
  144. caller<BOOST_SIGNALS_TEMPLATE_ARGS
  145. BOOST_SIGNALS_COMMA_IF_NONZERO_ARGS
  146. slot_function_type>
  147. call_bound_slot;
  148. public:
  149. // Combiner's result type
  150. typedef typename Combiner::result_type result_type;
  151. // Combiner type
  152. typedef Combiner combiner_type;
  153. // Slot type
  154. typedef slot<slot_function_type> slot_type;
  155. // Slot name type and comparison
  156. typedef Group group_type;
  157. typedef GroupCompare group_compare_type;
  158. typedef BOOST_SIGNALS_NAMESPACE::detail::slot_call_iterator<
  159. call_bound_slot, iterator> slot_call_iterator;
  160. explicit
  161. BOOST_SIGNALS_SIGNAL(const Combiner& c = Combiner(),
  162. const GroupCompare& comp = GroupCompare()) :
  163. BOOST_SIGNALS_NAMESPACE::detail::signal_base(real_group_compare_type(comp),
  164. c)
  165. {
  166. }
  167. // Connect a slot to this signal
  168. BOOST_SIGNALS_NAMESPACE::connection
  169. connect(const slot_type&,
  170. BOOST_SIGNALS_NAMESPACE::connect_position at
  171. = BOOST_SIGNALS_NAMESPACE::at_back);
  172. BOOST_SIGNALS_NAMESPACE::connection
  173. connect(const group_type&, const slot_type&,
  174. BOOST_SIGNALS_NAMESPACE::connect_position at
  175. = BOOST_SIGNALS_NAMESPACE::at_back);
  176. #if BOOST_WORKAROUND(BOOST_MSVC, <= 1300)
  177. // MSVC 6.0 and 7.0 don't handle the is_convertible test well
  178. void disconnect(const group_type& group)
  179. {
  180. impl->disconnect(group);
  181. }
  182. #else
  183. template<typename T>
  184. void disconnect(const T& t)
  185. {
  186. typedef mpl::bool_<(is_convertible<T, group_type>::value)> is_group;
  187. this->do_disconnect(t, is_group());
  188. }
  189. private:
  190. // Disconnect a named slot
  191. void do_disconnect(const group_type& group, mpl::bool_<true>)
  192. {
  193. impl->disconnect(group);
  194. }
  195. template<typename Function>
  196. void do_disconnect(const Function& f, mpl::bool_<false>)
  197. {
  198. // Notify the slot handling code that we are iterating through the slots
  199. BOOST_SIGNALS_NAMESPACE::detail::call_notification notification(this->impl);
  200. for (iterator i = impl->slots_.begin(); i != impl->slots_.end(); ++i) {
  201. slot_function_type& s = *unsafe_any_cast<slot_function_type>(&i->second);
  202. if (s == f) i->first.disconnect();
  203. }
  204. }
  205. #endif
  206. public:
  207. // Emit the signal
  208. result_type operator()(BOOST_SIGNALS_PARMS);
  209. result_type operator()(BOOST_SIGNALS_PARMS) const;
  210. Combiner& combiner()
  211. { return *unsafe_any_cast<Combiner>(&impl->combiner_); }
  212. const Combiner& combiner() const
  213. { return *unsafe_any_cast<const Combiner>(&impl->combiner_); }
  214. };
  215. template<
  216. typename R,
  217. BOOST_SIGNALS_TEMPLATE_PARMS
  218. BOOST_SIGNALS_COMMA_IF_NONZERO_ARGS
  219. typename Combiner,
  220. typename Group,
  221. typename GroupCompare,
  222. typename SlotFunction
  223. >
  224. BOOST_SIGNALS_NAMESPACE::connection
  225. BOOST_SIGNALS_SIGNAL<
  226. R, BOOST_SIGNALS_TEMPLATE_ARGS
  227. BOOST_SIGNALS_COMMA_IF_NONZERO_ARGS
  228. Combiner, Group, GroupCompare, SlotFunction
  229. >::connect(const slot_type& in_slot,
  230. BOOST_SIGNALS_NAMESPACE::connect_position at)
  231. {
  232. using boost::BOOST_SIGNALS_NAMESPACE::detail::stored_group;
  233. // If the slot has been disconnected, just return a disconnected
  234. // connection
  235. if (!in_slot.is_active()) {
  236. return BOOST_SIGNALS_NAMESPACE::connection();
  237. }
  238. return impl->connect_slot(in_slot.get_slot_function(), stored_group(),
  239. in_slot.get_data(), at);
  240. }
  241. template<
  242. typename R,
  243. BOOST_SIGNALS_TEMPLATE_PARMS
  244. BOOST_SIGNALS_COMMA_IF_NONZERO_ARGS
  245. typename Combiner,
  246. typename Group,
  247. typename GroupCompare,
  248. typename SlotFunction
  249. >
  250. BOOST_SIGNALS_NAMESPACE::connection
  251. BOOST_SIGNALS_SIGNAL<
  252. R, BOOST_SIGNALS_TEMPLATE_ARGS
  253. BOOST_SIGNALS_COMMA_IF_NONZERO_ARGS
  254. Combiner, Group, GroupCompare, SlotFunction
  255. >::connect(const group_type& group,
  256. const slot_type& in_slot,
  257. BOOST_SIGNALS_NAMESPACE::connect_position at)
  258. {
  259. // If the slot has been disconnected, just return a disconnected
  260. // connection
  261. if (!in_slot.is_active()) {
  262. return BOOST_SIGNALS_NAMESPACE::connection();
  263. }
  264. return impl->connect_slot(in_slot.get_slot_function(), group,
  265. in_slot.get_data(), at);
  266. }
  267. template<
  268. typename R,
  269. BOOST_SIGNALS_TEMPLATE_PARMS
  270. BOOST_SIGNALS_COMMA_IF_NONZERO_ARGS
  271. typename Combiner,
  272. typename Group,
  273. typename GroupCompare,
  274. typename SlotFunction
  275. >
  276. typename BOOST_SIGNALS_SIGNAL<
  277. R, BOOST_SIGNALS_TEMPLATE_ARGS
  278. BOOST_SIGNALS_COMMA_IF_NONZERO_ARGS
  279. Combiner, Group, GroupCompare, SlotFunction>::result_type
  280. BOOST_SIGNALS_SIGNAL<
  281. R, BOOST_SIGNALS_TEMPLATE_ARGS
  282. BOOST_SIGNALS_COMMA_IF_NONZERO_ARGS
  283. Combiner, Group, GroupCompare, SlotFunction
  284. >::operator()(BOOST_SIGNALS_PARMS)
  285. {
  286. // Notify the slot handling code that we are making a call
  287. BOOST_SIGNALS_NAMESPACE::detail::call_notification notification(this->impl);
  288. // Construct a function object that will call the underlying slots
  289. // with the given arguments.
  290. #if BOOST_SIGNALS_NUM_ARGS == 0
  291. BOOST_SIGNALS_ARGS_STRUCT_INST args;
  292. #else
  293. BOOST_SIGNALS_ARGS_STRUCT_INST args(BOOST_SIGNALS_ARGS);
  294. #endif // BOOST_SIGNALS_NUM_ARGS > 0
  295. call_bound_slot f(&args);
  296. typedef typename call_bound_slot::result_type call_result_type;
  297. optional<call_result_type> cache;
  298. // Let the combiner call the slots via a pair of input iterators
  299. return combiner()(slot_call_iterator(notification.impl->slots_.begin(),
  300. impl->slots_.end(), f, cache),
  301. slot_call_iterator(notification.impl->slots_.end(),
  302. impl->slots_.end(), f, cache));
  303. }
  304. template<
  305. typename R,
  306. BOOST_SIGNALS_TEMPLATE_PARMS
  307. BOOST_SIGNALS_COMMA_IF_NONZERO_ARGS
  308. typename Combiner,
  309. typename Group,
  310. typename GroupCompare,
  311. typename SlotFunction
  312. >
  313. typename BOOST_SIGNALS_SIGNAL<
  314. R, BOOST_SIGNALS_TEMPLATE_ARGS
  315. BOOST_SIGNALS_COMMA_IF_NONZERO_ARGS
  316. Combiner, Group, GroupCompare, SlotFunction>::result_type
  317. BOOST_SIGNALS_SIGNAL<
  318. R, BOOST_SIGNALS_TEMPLATE_ARGS
  319. BOOST_SIGNALS_COMMA_IF_NONZERO_ARGS
  320. Combiner, Group, GroupCompare, SlotFunction
  321. >::operator()(BOOST_SIGNALS_PARMS) const
  322. {
  323. // Notify the slot handling code that we are making a call
  324. BOOST_SIGNALS_NAMESPACE::detail::call_notification notification(this->impl);
  325. // Construct a function object that will call the underlying slots
  326. // with the given arguments.
  327. #if BOOST_SIGNALS_NUM_ARGS == 0
  328. BOOST_SIGNALS_ARGS_STRUCT_INST args;
  329. #else
  330. BOOST_SIGNALS_ARGS_STRUCT_INST args(BOOST_SIGNALS_ARGS);
  331. #endif // BOOST_SIGNALS_NUM_ARGS > 0
  332. call_bound_slot f(&args);
  333. typedef typename call_bound_slot::result_type call_result_type;
  334. optional<call_result_type> cache;
  335. // Let the combiner call the slots via a pair of input iterators
  336. return combiner()(slot_call_iterator(notification.impl->slots_.begin(),
  337. impl->slots_.end(), f, cache),
  338. slot_call_iterator(notification.impl->slots_.end(),
  339. impl->slots_.end(), f, cache));
  340. }
  341. } // namespace boost
  342. #undef BOOST_SIGNAL_FUNCTION_N_HEADER
  343. #undef BOOST_SIGNALS_ARGS_STRUCT_INST
  344. #undef BOOST_SIGNALS_CALL_BOUND
  345. #undef BOOST_SIGNALS_ARGS_STRUCT
  346. #undef BOOST_SIGNALS_FUNCTION
  347. #undef BOOST_SIGNALS_SIGNAL
  348. #undef BOOST_SIGNALS_COMMA_IF_NONZERO_ARGS
  349. #ifdef BOOST_HAS_ABI_HEADERS
  350. # include BOOST_ABI_SUFFIX
  351. #endif