signal_template.hpp 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836
  1. /*
  2. Template for Signa1, Signal2, ... classes that support signals
  3. with 1, 2, ... parameters
  4. Begin: 2007-01-23
  5. */
  6. // Copyright Frank Mori Hess 2007-2008
  7. //
  8. // Use, modification and
  9. // distribution is subject to the Boost Software License, Version
  10. // 1.0. (See accompanying file LICENSE_1_0.txt or copy at
  11. // http://www.boost.org/LICENSE_1_0.txt)
  12. // This file is included iteratively, and should not be protected from multiple inclusion
  13. #ifdef BOOST_NO_CXX11_VARIADIC_TEMPLATES
  14. #define BOOST_SIGNALS2_NUM_ARGS BOOST_PP_ITERATION()
  15. #else
  16. #define BOOST_SIGNALS2_NUM_ARGS 1
  17. #endif
  18. // R, T1, T2, ..., TN, Combiner, Group, GroupCompare, SlotFunction, ExtendedSlotFunction, Mutex
  19. #define BOOST_SIGNALS2_SIGNAL_TEMPLATE_INSTANTIATION \
  20. BOOST_SIGNALS2_SIGNATURE_TEMPLATE_INSTANTIATION(BOOST_SIGNALS2_NUM_ARGS), \
  21. Combiner, Group, GroupCompare, SlotFunction, ExtendedSlotFunction, Mutex
  22. namespace boost
  23. {
  24. namespace signals2
  25. {
  26. namespace detail
  27. {
  28. // helper for bound_extended_slot_function that handles specialization for void return
  29. template<typename R>
  30. class BOOST_SIGNALS2_BOUND_EXTENDED_SLOT_FUNCTION_INVOKER_N(BOOST_SIGNALS2_NUM_ARGS)
  31. {
  32. public:
  33. typedef R result_type;
  34. template<typename ExtendedSlotFunction BOOST_SIGNALS2_PP_COMMA_IF(BOOST_SIGNALS2_NUM_ARGS)
  35. BOOST_SIGNALS2_ARGS_TEMPLATE_DECL(BOOST_SIGNALS2_NUM_ARGS)>
  36. result_type operator()(ExtendedSlotFunction &func, const connection &conn
  37. BOOST_SIGNALS2_PP_COMMA_IF(BOOST_SIGNALS2_NUM_ARGS)
  38. BOOST_SIGNALS2_FULL_REF_ARGS(BOOST_SIGNALS2_NUM_ARGS)) const
  39. {
  40. return func(conn BOOST_SIGNALS2_PP_COMMA_IF(BOOST_SIGNALS2_NUM_ARGS)
  41. BOOST_SIGNALS2_SIGNATURE_ARG_NAMES(BOOST_SIGNALS2_NUM_ARGS));
  42. }
  43. };
  44. #ifdef BOOST_NO_VOID_RETURNS
  45. template<>
  46. class BOOST_SIGNALS2_BOUND_EXTENDED_SLOT_FUNCTION_INVOKER_N(BOOST_SIGNALS2_NUM_ARGS)<void>
  47. {
  48. public:
  49. typedef result_type_wrapper<void>::type result_type;
  50. template<typename ExtendedSlotFunction BOOST_SIGNALS2_PP_COMMA_IF(BOOST_SIGNALS2_NUM_ARGS)
  51. BOOST_SIGNALS2_ARGS_TEMPLATE_DECL(BOOST_SIGNALS2_NUM_ARGS)>
  52. result_type operator()(ExtendedSlotFunction &func, const connection &conn
  53. BOOST_SIGNALS2_PP_COMMA_IF(BOOST_SIGNALS2_NUM_ARGS)
  54. BOOST_SIGNALS2_FULL_REF_ARGS(BOOST_SIGNALS2_NUM_ARGS)) const
  55. {
  56. func(conn BOOST_SIGNALS2_PP_COMMA_IF(BOOST_SIGNALS2_NUM_ARGS)
  57. BOOST_SIGNALS2_SIGNATURE_ARG_NAMES(BOOST_SIGNALS2_NUM_ARGS));
  58. return result_type();
  59. }
  60. };
  61. #endif
  62. // wrapper around an signalN::extended_slot_function which binds the
  63. // connection argument so it looks like a normal
  64. // signalN::slot_function
  65. template<typename ExtendedSlotFunction>
  66. class BOOST_SIGNALS2_BOUND_EXTENDED_SLOT_FUNCTION_N(BOOST_SIGNALS2_NUM_ARGS)
  67. {
  68. public:
  69. typedef typename result_type_wrapper<typename ExtendedSlotFunction::result_type>::type result_type;
  70. BOOST_SIGNALS2_BOUND_EXTENDED_SLOT_FUNCTION_N(BOOST_SIGNALS2_NUM_ARGS)(const ExtendedSlotFunction &fun):
  71. _fun(fun), _connection(new connection)
  72. {}
  73. void set_connection(const connection &conn)
  74. {
  75. *_connection = conn;
  76. }
  77. #if BOOST_SIGNALS2_NUM_ARGS > 0
  78. template<BOOST_SIGNALS2_ARGS_TEMPLATE_DECL(BOOST_SIGNALS2_NUM_ARGS)>
  79. #endif // BOOST_SIGNALS2_NUM_ARGS > 0
  80. result_type operator()(BOOST_SIGNALS2_FULL_REF_ARGS(BOOST_SIGNALS2_NUM_ARGS))
  81. {
  82. return BOOST_SIGNALS2_BOUND_EXTENDED_SLOT_FUNCTION_INVOKER_N(BOOST_SIGNALS2_NUM_ARGS)
  83. <typename ExtendedSlotFunction::result_type>()
  84. (_fun, *_connection BOOST_SIGNALS2_PP_COMMA_IF(BOOST_SIGNALS2_NUM_ARGS)
  85. BOOST_SIGNALS2_SIGNATURE_ARG_NAMES(BOOST_SIGNALS2_NUM_ARGS));
  86. }
  87. // const overload
  88. #if BOOST_SIGNALS2_NUM_ARGS > 0
  89. template<BOOST_SIGNALS2_ARGS_TEMPLATE_DECL(BOOST_SIGNALS2_NUM_ARGS)>
  90. #endif // BOOST_SIGNALS2_NUM_ARGS > 0
  91. result_type operator()(BOOST_SIGNALS2_FULL_REF_ARGS(BOOST_SIGNALS2_NUM_ARGS)) const
  92. {
  93. return BOOST_SIGNALS2_BOUND_EXTENDED_SLOT_FUNCTION_INVOKER_N(BOOST_SIGNALS2_NUM_ARGS)
  94. <typename ExtendedSlotFunction::result_type>()
  95. (_fun, *_connection BOOST_SIGNALS2_PP_COMMA_IF(BOOST_SIGNALS2_NUM_ARGS)
  96. BOOST_SIGNALS2_SIGNATURE_ARG_NAMES(BOOST_SIGNALS2_NUM_ARGS));
  97. }
  98. template<typename T>
  99. bool operator==(const T &other) const
  100. {
  101. return _fun == other;
  102. }
  103. private:
  104. BOOST_SIGNALS2_BOUND_EXTENDED_SLOT_FUNCTION_N(BOOST_SIGNALS2_NUM_ARGS)()
  105. {}
  106. ExtendedSlotFunction _fun;
  107. boost::shared_ptr<connection> _connection;
  108. };
  109. template<BOOST_SIGNALS2_SIGNAL_TEMPLATE_DECL(BOOST_SIGNALS2_NUM_ARGS)>
  110. class BOOST_SIGNALS2_SIGNAL_IMPL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS);
  111. template<BOOST_SIGNALS2_SIGNAL_TEMPLATE_SPECIALIZATION_DECL(BOOST_SIGNALS2_NUM_ARGS)>
  112. class BOOST_SIGNALS2_SIGNAL_IMPL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS) BOOST_SIGNALS2_SIGNAL_TEMPLATE_SPECIALIZATION
  113. {
  114. public:
  115. typedef SlotFunction slot_function_type;
  116. // typedef slotN<Signature, SlotFunction> slot_type;
  117. typedef BOOST_SIGNALS2_SLOT_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)
  118. <BOOST_SIGNALS2_SIGNATURE_TEMPLATE_INSTANTIATION(BOOST_SIGNALS2_NUM_ARGS),
  119. slot_function_type> slot_type;
  120. typedef ExtendedSlotFunction extended_slot_function_type;
  121. // typedef slotN+1<R, const connection &, T1, T2, ..., TN, extended_slot_function_type> extended_slot_type;
  122. typedef BOOST_SIGNALS2_EXTENDED_SLOT_TYPE(BOOST_SIGNALS2_NUM_ARGS) extended_slot_type;
  123. typedef typename nonvoid<typename slot_function_type::result_type>::type nonvoid_slot_result_type;
  124. private:
  125. #ifdef BOOST_NO_CXX11_VARIADIC_TEMPLATES
  126. class slot_invoker;
  127. #else // BOOST_NO_CXX11_VARIADIC_TEMPLATES
  128. typedef variadic_slot_invoker<nonvoid_slot_result_type, Args...> slot_invoker;
  129. #endif // BOOST_NO_CXX11_VARIADIC_TEMPLATES
  130. typedef slot_call_iterator_cache<nonvoid_slot_result_type, slot_invoker> slot_call_iterator_cache_type;
  131. typedef typename group_key<Group>::type group_key_type;
  132. typedef shared_ptr<connection_body<group_key_type, slot_type, Mutex> > connection_body_type;
  133. typedef grouped_list<Group, GroupCompare, connection_body_type> connection_list_type;
  134. typedef BOOST_SIGNALS2_BOUND_EXTENDED_SLOT_FUNCTION_N(BOOST_SIGNALS2_NUM_ARGS)<extended_slot_function_type>
  135. bound_extended_slot_function_type;
  136. public:
  137. typedef Combiner combiner_type;
  138. typedef typename result_type_wrapper<typename combiner_type::result_type>::type result_type;
  139. typedef Group group_type;
  140. typedef GroupCompare group_compare_type;
  141. typedef typename detail::slot_call_iterator_t<slot_invoker,
  142. typename connection_list_type::iterator, connection_body<group_key_type, slot_type, Mutex> > slot_call_iterator;
  143. BOOST_SIGNALS2_SIGNAL_IMPL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)(const combiner_type &combiner_arg,
  144. const group_compare_type &group_compare):
  145. _shared_state(new invocation_state(connection_list_type(group_compare), combiner_arg)),
  146. _garbage_collector_it(_shared_state->connection_bodies().end())
  147. {}
  148. // connect slot
  149. connection connect(const slot_type &slot, connect_position position = at_back)
  150. {
  151. unique_lock<mutex_type> lock(_mutex);
  152. return nolock_connect(slot, position);
  153. }
  154. connection connect(const group_type &group,
  155. const slot_type &slot, connect_position position = at_back)
  156. {
  157. unique_lock<Mutex> lock(_mutex);
  158. return nolock_connect(group, slot, position);
  159. }
  160. // connect extended slot
  161. connection connect_extended(const extended_slot_type &ext_slot, connect_position position = at_back)
  162. {
  163. unique_lock<mutex_type> lock(_mutex);
  164. bound_extended_slot_function_type bound_slot(ext_slot.slot_function());
  165. slot_type slot = replace_slot_function<slot_type>(ext_slot, bound_slot);
  166. connection conn = nolock_connect(slot, position);
  167. bound_slot.set_connection(conn);
  168. return conn;
  169. }
  170. connection connect_extended(const group_type &group,
  171. const extended_slot_type &ext_slot, connect_position position = at_back)
  172. {
  173. unique_lock<Mutex> lock(_mutex);
  174. bound_extended_slot_function_type bound_slot(ext_slot.slot_function());
  175. slot_type slot = replace_slot_function<slot_type>(ext_slot, bound_slot);
  176. connection conn = nolock_connect(group, slot, position);
  177. bound_slot.set_connection(conn);
  178. return conn;
  179. }
  180. // disconnect slot(s)
  181. void disconnect_all_slots()
  182. {
  183. shared_ptr<invocation_state> local_state =
  184. get_readable_state();
  185. typename connection_list_type::iterator it;
  186. for(it = local_state->connection_bodies().begin();
  187. it != local_state->connection_bodies().end(); ++it)
  188. {
  189. (*it)->disconnect();
  190. }
  191. }
  192. void disconnect(const group_type &group)
  193. {
  194. shared_ptr<invocation_state> local_state =
  195. get_readable_state();
  196. group_key_type group_key(grouped_slots, group);
  197. typename connection_list_type::iterator it;
  198. typename connection_list_type::iterator end_it =
  199. local_state->connection_bodies().upper_bound(group_key);
  200. for(it = local_state->connection_bodies().lower_bound(group_key);
  201. it != end_it; ++it)
  202. {
  203. (*it)->disconnect();
  204. }
  205. }
  206. template <typename T>
  207. void disconnect(const T &slot)
  208. {
  209. typedef mpl::bool_<(is_convertible<T, group_type>::value)> is_group;
  210. do_disconnect(slot, is_group());
  211. }
  212. // emit signal
  213. result_type operator ()(BOOST_SIGNALS2_SIGNATURE_FULL_ARGS(BOOST_SIGNALS2_NUM_ARGS))
  214. {
  215. shared_ptr<invocation_state> local_state;
  216. typename connection_list_type::iterator it;
  217. {
  218. unique_lock<mutex_type> list_lock(_mutex);
  219. // only clean up if it is safe to do so
  220. if(_shared_state.unique())
  221. nolock_cleanup_connections(false, 1);
  222. /* Make a local copy of _shared_state while holding mutex, so we are
  223. thread safe against the combiner or connection list getting modified
  224. during invocation. */
  225. local_state = _shared_state;
  226. }
  227. slot_invoker invoker = slot_invoker(BOOST_SIGNALS2_SIGNATURE_ARG_NAMES(BOOST_SIGNALS2_NUM_ARGS));
  228. slot_call_iterator_cache_type cache(invoker);
  229. invocation_janitor janitor(cache, *this, &local_state->connection_bodies());
  230. return detail::combiner_invoker<typename combiner_type::result_type>()
  231. (
  232. local_state->combiner(),
  233. slot_call_iterator(local_state->connection_bodies().begin(), local_state->connection_bodies().end(), cache),
  234. slot_call_iterator(local_state->connection_bodies().end(), local_state->connection_bodies().end(), cache)
  235. );
  236. }
  237. result_type operator ()(BOOST_SIGNALS2_SIGNATURE_FULL_ARGS(BOOST_SIGNALS2_NUM_ARGS)) const
  238. {
  239. shared_ptr<invocation_state> local_state;
  240. typename connection_list_type::iterator it;
  241. {
  242. unique_lock<mutex_type> list_lock(_mutex);
  243. // only clean up if it is safe to do so
  244. if(_shared_state.unique())
  245. nolock_cleanup_connections(false, 1);
  246. /* Make a local copy of _shared_state while holding mutex, so we are
  247. thread safe against the combiner or connection list getting modified
  248. during invocation. */
  249. local_state = _shared_state;
  250. }
  251. slot_invoker invoker = slot_invoker(BOOST_SIGNALS2_SIGNATURE_ARG_NAMES(BOOST_SIGNALS2_NUM_ARGS));
  252. slot_call_iterator_cache_type cache(invoker);
  253. invocation_janitor janitor(cache, *this, &local_state->connection_bodies());
  254. return detail::combiner_invoker<typename combiner_type::result_type>()
  255. (
  256. local_state->combiner(),
  257. slot_call_iterator(local_state->connection_bodies().begin(), local_state->connection_bodies().end(), cache),
  258. slot_call_iterator(local_state->connection_bodies().end(), local_state->connection_bodies().end(), cache)
  259. );
  260. }
  261. std::size_t num_slots() const
  262. {
  263. shared_ptr<invocation_state> local_state =
  264. get_readable_state();
  265. typename connection_list_type::iterator it;
  266. std::size_t count = 0;
  267. for(it = local_state->connection_bodies().begin();
  268. it != local_state->connection_bodies().end(); ++it)
  269. {
  270. if((*it)->connected()) ++count;
  271. }
  272. return count;
  273. }
  274. bool empty() const
  275. {
  276. shared_ptr<invocation_state> local_state =
  277. get_readable_state();
  278. typename connection_list_type::iterator it;
  279. for(it = local_state->connection_bodies().begin();
  280. it != local_state->connection_bodies().end(); ++it)
  281. {
  282. if((*it)->connected()) return false;
  283. }
  284. return true;
  285. }
  286. combiner_type combiner() const
  287. {
  288. unique_lock<mutex_type> lock(_mutex);
  289. return _shared_state->combiner();
  290. }
  291. void set_combiner(const combiner_type &combiner_arg)
  292. {
  293. unique_lock<mutex_type> lock(_mutex);
  294. if(_shared_state.unique())
  295. _shared_state->combiner() = combiner_arg;
  296. else
  297. _shared_state.reset(new invocation_state(*_shared_state, combiner_arg));
  298. }
  299. private:
  300. typedef Mutex mutex_type;
  301. // slot_invoker is passed to slot_call_iterator_t to run slots
  302. #ifdef BOOST_NO_CXX11_VARIADIC_TEMPLATES
  303. class slot_invoker
  304. {
  305. public:
  306. typedef nonvoid_slot_result_type result_type;
  307. // typename add_reference<Tn>::type
  308. #define BOOST_SIGNALS2_ADD_REF_TYPE(z, n, data) \
  309. typename add_reference<BOOST_PP_CAT(T, BOOST_PP_INC(n))>::type
  310. // typename add_reference<Tn>::type argn
  311. #define BOOST_SIGNALS2_ADD_REF_ARG(z, n, data) \
  312. BOOST_SIGNALS2_ADD_REF_TYPE(~, n, ~) \
  313. BOOST_SIGNALS2_SIGNATURE_ARG_NAME(~, n, ~)
  314. // typename add_reference<T1>::type arg1, typename add_reference<T2>::type arg2, ..., typename add_reference<Tn>::type argn
  315. #define BOOST_SIGNALS2_ADD_REF_ARGS(arity) \
  316. BOOST_PP_ENUM(arity, BOOST_SIGNALS2_ADD_REF_ARG, ~)
  317. slot_invoker(BOOST_SIGNALS2_ADD_REF_ARGS(BOOST_SIGNALS2_NUM_ARGS)) BOOST_PP_EXPR_IF(BOOST_SIGNALS2_NUM_ARGS, :)
  318. #undef BOOST_SIGNALS2_ADD_REF_ARGS
  319. // m_argn
  320. #define BOOST_SIGNALS2_M_ARG_NAME(z, n, data) BOOST_PP_CAT(m_arg, BOOST_PP_INC(n))
  321. // m_argn ( argn )
  322. #define BOOST_SIGNALS2_MISC_STATEMENT(z, n, data) \
  323. BOOST_SIGNALS2_M_ARG_NAME(~, n, ~) ( BOOST_SIGNALS2_SIGNATURE_ARG_NAME(~, n, ~) )
  324. // m_arg1(arg1), m_arg2(arg2), ..., m_argn(argn)
  325. BOOST_PP_ENUM(BOOST_SIGNALS2_NUM_ARGS, BOOST_SIGNALS2_MISC_STATEMENT, ~)
  326. #undef BOOST_SIGNALS2_MISC_STATEMENT
  327. {}
  328. result_type operator ()(const connection_body_type &connectionBody) const
  329. {
  330. result_type *resolver = 0;
  331. return m_invoke(connectionBody,
  332. resolver);
  333. }
  334. private:
  335. // declare assignment operator private since this class might have reference or const members
  336. slot_invoker & operator=(const slot_invoker &);
  337. #define BOOST_SIGNALS2_ADD_REF_M_ARG_STATEMENT(z, n, data) \
  338. BOOST_SIGNALS2_ADD_REF_TYPE(~, n, ~) BOOST_SIGNALS2_M_ARG_NAME(~, n, ~) ;
  339. BOOST_PP_REPEAT(BOOST_SIGNALS2_NUM_ARGS, BOOST_SIGNALS2_ADD_REF_M_ARG_STATEMENT, ~)
  340. #undef BOOST_SIGNALS2_ADD_REF_M_ARG_STATEMENT
  341. #undef BOOST_SIGNALS2_ADD_REF_ARG
  342. #undef BOOST_SIGNALS2_ADD_REF_TYPE
  343. // m_arg1, m_arg2, ..., m_argn
  344. #define BOOST_SIGNALS2_M_ARG_NAMES(arity) BOOST_PP_ENUM(arity, BOOST_SIGNALS2_M_ARG_NAME, ~)
  345. result_type m_invoke(const connection_body_type &connectionBody,
  346. const void_type *) const
  347. {
  348. connectionBody->slot.slot_function()(BOOST_SIGNALS2_M_ARG_NAMES(BOOST_SIGNALS2_NUM_ARGS));
  349. return void_type();
  350. }
  351. result_type m_invoke(const connection_body_type &connectionBody, ...) const
  352. {
  353. return connectionBody->slot.slot_function()(BOOST_SIGNALS2_M_ARG_NAMES(BOOST_SIGNALS2_NUM_ARGS));
  354. }
  355. };
  356. #undef BOOST_SIGNALS2_M_ARG_NAMES
  357. #undef BOOST_SIGNALS2_M_ARG_NAME
  358. #endif // BOOST_NO_CXX11_VARIADIC_TEMPLATES
  359. // a struct used to optimize (minimize) the number of shared_ptrs that need to be created
  360. // inside operator()
  361. class invocation_state
  362. {
  363. public:
  364. invocation_state(const connection_list_type &connections_in,
  365. const combiner_type &combiner_in): _connection_bodies(new connection_list_type(connections_in)),
  366. _combiner(new combiner_type(combiner_in))
  367. {}
  368. invocation_state(const invocation_state &other, const connection_list_type &connections_in):
  369. _connection_bodies(new connection_list_type(connections_in)),
  370. _combiner(other._combiner)
  371. {}
  372. invocation_state(const invocation_state &other, const combiner_type &combiner_in):
  373. _connection_bodies(other._connection_bodies),
  374. _combiner(new combiner_type(combiner_in))
  375. {}
  376. connection_list_type & connection_bodies() { return *_connection_bodies; }
  377. const connection_list_type & connection_bodies() const { return *_connection_bodies; }
  378. combiner_type & combiner() { return *_combiner; }
  379. const combiner_type & combiner() const { return *_combiner; }
  380. private:
  381. invocation_state(const invocation_state &);
  382. shared_ptr<connection_list_type> _connection_bodies;
  383. shared_ptr<combiner_type> _combiner;
  384. };
  385. // Destructor of invocation_janitor does some cleanup when a signal invocation completes.
  386. // Code can't be put directly in signal's operator() due to complications from void return types.
  387. class invocation_janitor
  388. {
  389. public:
  390. typedef BOOST_SIGNALS2_SIGNAL_IMPL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS) signal_type;
  391. invocation_janitor
  392. (
  393. const slot_call_iterator_cache_type &cache,
  394. const signal_type &sig,
  395. const connection_list_type *connection_bodies
  396. ):_cache(cache), _sig(sig), _connection_bodies(connection_bodies)
  397. {}
  398. ~invocation_janitor()
  399. {
  400. // force a full cleanup of disconnected slots if there are too many
  401. if(_cache.disconnected_slot_count > _cache.connected_slot_count)
  402. {
  403. _sig.force_cleanup_connections(_connection_bodies);
  404. }
  405. }
  406. private:
  407. const slot_call_iterator_cache_type &_cache;
  408. const signal_type &_sig;
  409. const connection_list_type *_connection_bodies;
  410. };
  411. // clean up disconnected connections
  412. void nolock_cleanup_connections_from(bool grab_tracked,
  413. const typename connection_list_type::iterator &begin, unsigned count = 0) const
  414. {
  415. BOOST_ASSERT(_shared_state.unique());
  416. typename connection_list_type::iterator it;
  417. unsigned i;
  418. for(it = begin, i = 0;
  419. it != _shared_state->connection_bodies().end() && (count == 0 || i < count);
  420. ++i)
  421. {
  422. bool connected;
  423. {
  424. unique_lock<connection_body_base> lock(**it);
  425. if(grab_tracked)
  426. (*it)->nolock_slot_expired();
  427. connected = (*it)->nolock_nograb_connected();
  428. }// scoped lock destructs here, safe to erase now
  429. if(connected == false)
  430. {
  431. it = _shared_state->connection_bodies().erase((*it)->group_key(), it);
  432. }else
  433. {
  434. ++it;
  435. }
  436. }
  437. _garbage_collector_it = it;
  438. }
  439. // clean up a few connections in constant time
  440. void nolock_cleanup_connections(bool grab_tracked, unsigned count) const
  441. {
  442. BOOST_ASSERT(_shared_state.unique());
  443. typename connection_list_type::iterator begin;
  444. if(_garbage_collector_it == _shared_state->connection_bodies().end())
  445. {
  446. begin = _shared_state->connection_bodies().begin();
  447. }else
  448. {
  449. begin = _garbage_collector_it;
  450. }
  451. nolock_cleanup_connections_from(grab_tracked, begin, count);
  452. }
  453. /* Make a new copy of the slot list if it is currently being read somewhere else
  454. */
  455. void nolock_force_unique_connection_list()
  456. {
  457. if(_shared_state.unique() == false)
  458. {
  459. _shared_state.reset(new invocation_state(*_shared_state, _shared_state->connection_bodies()));
  460. nolock_cleanup_connections_from(true, _shared_state->connection_bodies().begin());
  461. }else
  462. {
  463. /* We need to try and check more than just 1 connection here to avoid corner
  464. cases where certain repeated connect/disconnect patterns cause the slot
  465. list to grow without limit. */
  466. nolock_cleanup_connections(true, 2);
  467. }
  468. }
  469. // force a full cleanup of the connection list
  470. void force_cleanup_connections(const connection_list_type *connection_bodies) const
  471. {
  472. unique_lock<mutex_type> list_lock(_mutex);
  473. // if the connection list passed in as a parameter is no longer in use,
  474. // we don't need to do any cleanup.
  475. if(&_shared_state->connection_bodies() != connection_bodies)
  476. {
  477. return;
  478. }
  479. if(_shared_state.unique() == false)
  480. {
  481. _shared_state.reset(new invocation_state(*_shared_state, _shared_state->connection_bodies()));
  482. }
  483. nolock_cleanup_connections_from(false, _shared_state->connection_bodies().begin());
  484. }
  485. shared_ptr<invocation_state> get_readable_state() const
  486. {
  487. unique_lock<mutex_type> list_lock(_mutex);
  488. return _shared_state;
  489. }
  490. connection_body_type create_new_connection(const slot_type &slot)
  491. {
  492. nolock_force_unique_connection_list();
  493. return connection_body_type(new connection_body<group_key_type, slot_type, Mutex>(slot));
  494. }
  495. void do_disconnect(const group_type &group, mpl::bool_<true> /* is_group */)
  496. {
  497. disconnect(group);
  498. }
  499. template<typename T>
  500. void do_disconnect(const T &slot, mpl::bool_<false> /* is_group */)
  501. {
  502. shared_ptr<invocation_state> local_state =
  503. get_readable_state();
  504. typename connection_list_type::iterator it;
  505. for(it = local_state->connection_bodies().begin();
  506. it != local_state->connection_bodies().end(); ++it)
  507. {
  508. unique_lock<connection_body_base> lock(**it);
  509. if((*it)->slot.slot_function() == slot)
  510. {
  511. (*it)->nolock_disconnect();
  512. }else
  513. {
  514. // check for wrapped extended slot
  515. bound_extended_slot_function_type *fp;
  516. fp = (*it)->slot.slot_function().template target<bound_extended_slot_function_type>();
  517. if(fp && *fp == slot)
  518. {
  519. (*it)->nolock_disconnect();
  520. }
  521. }
  522. }
  523. }
  524. // connect slot
  525. connection nolock_connect(const slot_type &slot, connect_position position)
  526. {
  527. connection_body_type newConnectionBody =
  528. create_new_connection(slot);
  529. group_key_type group_key;
  530. if(position == at_back)
  531. {
  532. group_key.first = back_ungrouped_slots;
  533. _shared_state->connection_bodies().push_back(group_key, newConnectionBody);
  534. }else
  535. {
  536. group_key.first = front_ungrouped_slots;
  537. _shared_state->connection_bodies().push_front(group_key, newConnectionBody);
  538. }
  539. newConnectionBody->set_group_key(group_key);
  540. return connection(newConnectionBody);
  541. }
  542. connection nolock_connect(const group_type &group,
  543. const slot_type &slot, connect_position position)
  544. {
  545. connection_body_type newConnectionBody =
  546. create_new_connection(slot);
  547. // update map to first connection body in group if needed
  548. group_key_type group_key(grouped_slots, group);
  549. newConnectionBody->set_group_key(group_key);
  550. if(position == at_back)
  551. {
  552. _shared_state->connection_bodies().push_back(group_key, newConnectionBody);
  553. }else // at_front
  554. {
  555. _shared_state->connection_bodies().push_front(group_key, newConnectionBody);
  556. }
  557. return connection(newConnectionBody);
  558. }
  559. // _shared_state is mutable so we can do force_cleanup_connections during a const invocation
  560. mutable shared_ptr<invocation_state> _shared_state;
  561. mutable typename connection_list_type::iterator _garbage_collector_it;
  562. // connection list mutex must never be locked when attempting a blocking lock on a slot,
  563. // or you could deadlock.
  564. mutable mutex_type _mutex;
  565. };
  566. template<BOOST_SIGNALS2_SIGNAL_TEMPLATE_DECL(BOOST_SIGNALS2_NUM_ARGS)>
  567. class BOOST_SIGNALS2_WEAK_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS);
  568. }
  569. template<BOOST_SIGNALS2_SIGNAL_TEMPLATE_DEFAULTED_DECL(BOOST_SIGNALS2_NUM_ARGS)>
  570. class BOOST_SIGNALS2_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS);
  571. template<BOOST_SIGNALS2_SIGNAL_TEMPLATE_SPECIALIZATION_DECL(BOOST_SIGNALS2_NUM_ARGS)>
  572. class BOOST_SIGNALS2_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)
  573. BOOST_SIGNALS2_SIGNAL_TEMPLATE_SPECIALIZATION: public signal_base,
  574. public detail::BOOST_SIGNALS2_STD_FUNCTIONAL_BASE
  575. (typename detail::result_type_wrapper<typename Combiner::result_type>::type)
  576. {
  577. typedef detail::BOOST_SIGNALS2_SIGNAL_IMPL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)
  578. <BOOST_SIGNALS2_SIGNAL_TEMPLATE_INSTANTIATION> impl_class;
  579. public:
  580. typedef detail::BOOST_SIGNALS2_WEAK_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)
  581. <BOOST_SIGNALS2_SIGNAL_TEMPLATE_INSTANTIATION> weak_signal_type;
  582. friend class detail::BOOST_SIGNALS2_WEAK_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)
  583. <BOOST_SIGNALS2_SIGNAL_TEMPLATE_INSTANTIATION>;
  584. typedef SlotFunction slot_function_type;
  585. // typedef slotN<Signature, SlotFunction> slot_type;
  586. typedef typename impl_class::slot_type slot_type;
  587. typedef typename impl_class::extended_slot_function_type extended_slot_function_type;
  588. typedef typename impl_class::extended_slot_type extended_slot_type;
  589. typedef typename slot_function_type::result_type slot_result_type;
  590. typedef Combiner combiner_type;
  591. typedef typename impl_class::result_type result_type;
  592. typedef Group group_type;
  593. typedef GroupCompare group_compare_type;
  594. typedef typename impl_class::slot_call_iterator
  595. slot_call_iterator;
  596. typedef typename mpl::identity<BOOST_SIGNALS2_SIGNATURE_FUNCTION_TYPE(BOOST_SIGNALS2_NUM_ARGS)>::type signature_type;
  597. #ifdef BOOST_NO_CXX11_VARIADIC_TEMPLATES
  598. // typedef Tn argn_type;
  599. #define BOOST_SIGNALS2_MISC_STATEMENT(z, n, data) \
  600. typedef BOOST_PP_CAT(T, BOOST_PP_INC(n)) BOOST_PP_CAT(BOOST_PP_CAT(arg, BOOST_PP_INC(n)), _type);
  601. BOOST_PP_REPEAT(BOOST_SIGNALS2_NUM_ARGS, BOOST_SIGNALS2_MISC_STATEMENT, ~)
  602. #undef BOOST_SIGNALS2_MISC_STATEMENT
  603. #if BOOST_SIGNALS2_NUM_ARGS == 1
  604. typedef arg1_type argument_type;
  605. #elif BOOST_SIGNALS2_NUM_ARGS == 2
  606. typedef arg1_type first_argument_type;
  607. typedef arg2_type second_argument_type;
  608. #endif
  609. template<unsigned n> class arg : public
  610. detail::BOOST_SIGNALS2_PREPROCESSED_ARG_N_TYPE_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)
  611. <n BOOST_SIGNALS2_PP_COMMA_IF(BOOST_SIGNALS2_NUM_ARGS)
  612. BOOST_SIGNALS2_ARGS_TEMPLATE_INSTANTIATION(BOOST_SIGNALS2_NUM_ARGS)>
  613. {};
  614. BOOST_STATIC_CONSTANT(int, arity = BOOST_SIGNALS2_NUM_ARGS);
  615. #else // BOOST_NO_CXX11_VARIADIC_TEMPLATES
  616. template<unsigned n> class arg
  617. {
  618. public:
  619. typedef typename detail::variadic_arg_type<n, Args...>::type type;
  620. };
  621. BOOST_STATIC_CONSTANT(int, arity = sizeof...(Args));
  622. #endif // BOOST_NO_CXX11_VARIADIC_TEMPLATES
  623. BOOST_SIGNALS2_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)(const combiner_type &combiner_arg = combiner_type(),
  624. const group_compare_type &group_compare = group_compare_type()):
  625. _pimpl(new impl_class(combiner_arg, group_compare))
  626. {};
  627. virtual ~BOOST_SIGNALS2_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)()
  628. {
  629. disconnect_all_slots();
  630. }
  631. connection connect(const slot_type &slot, connect_position position = at_back)
  632. {
  633. return (*_pimpl).connect(slot, position);
  634. }
  635. connection connect(const group_type &group,
  636. const slot_type &slot, connect_position position = at_back)
  637. {
  638. return (*_pimpl).connect(group, slot, position);
  639. }
  640. connection connect_extended(const extended_slot_type &slot, connect_position position = at_back)
  641. {
  642. return (*_pimpl).connect_extended(slot, position);
  643. }
  644. connection connect_extended(const group_type &group,
  645. const extended_slot_type &slot, connect_position position = at_back)
  646. {
  647. return (*_pimpl).connect_extended(group, slot, position);
  648. }
  649. void disconnect_all_slots()
  650. {
  651. (*_pimpl).disconnect_all_slots();
  652. }
  653. void disconnect(const group_type &group)
  654. {
  655. (*_pimpl).disconnect(group);
  656. }
  657. template <typename T>
  658. void disconnect(const T &slot)
  659. {
  660. (*_pimpl).disconnect(slot);
  661. }
  662. result_type operator ()(BOOST_SIGNALS2_SIGNATURE_FULL_ARGS(BOOST_SIGNALS2_NUM_ARGS))
  663. {
  664. return (*_pimpl)(BOOST_SIGNALS2_SIGNATURE_ARG_NAMES(BOOST_SIGNALS2_NUM_ARGS));
  665. }
  666. result_type operator ()(BOOST_SIGNALS2_SIGNATURE_FULL_ARGS(BOOST_SIGNALS2_NUM_ARGS)) const
  667. {
  668. return (*_pimpl)(BOOST_SIGNALS2_SIGNATURE_ARG_NAMES(BOOST_SIGNALS2_NUM_ARGS));
  669. }
  670. std::size_t num_slots() const
  671. {
  672. return (*_pimpl).num_slots();
  673. }
  674. bool empty() const
  675. {
  676. return (*_pimpl).empty();
  677. }
  678. combiner_type combiner() const
  679. {
  680. return (*_pimpl).combiner();
  681. }
  682. void set_combiner(const combiner_type &combiner_arg)
  683. {
  684. return (*_pimpl).set_combiner(combiner_arg);
  685. }
  686. void swap(BOOST_SIGNALS2_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS) & other)
  687. {
  688. using std::swap;
  689. swap(_pimpl, other._pimpl);
  690. }
  691. protected:
  692. virtual shared_ptr<void> lock_pimpl() const
  693. {
  694. return _pimpl;
  695. }
  696. private:
  697. shared_ptr<impl_class>
  698. _pimpl;
  699. };
  700. #ifdef BOOST_NO_CXX11_VARIADIC_TEMPLATES
  701. // free swap function for signalN classes, findable by ADL
  702. template<BOOST_SIGNALS2_SIGNAL_TEMPLATE_DECL(BOOST_SIGNALS2_NUM_ARGS)>
  703. void swap(
  704. BOOST_SIGNALS2_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS) <BOOST_SIGNALS2_SIGNAL_TEMPLATE_INSTANTIATION> &sig1,
  705. BOOST_SIGNALS2_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS) <BOOST_SIGNALS2_SIGNAL_TEMPLATE_INSTANTIATION> &sig2 )
  706. {
  707. sig1.swap(sig2);
  708. }
  709. #endif
  710. namespace detail
  711. {
  712. // wrapper class for storing other signals as slots with automatic lifetime tracking
  713. template<BOOST_SIGNALS2_SIGNAL_TEMPLATE_DECL(BOOST_SIGNALS2_NUM_ARGS)>
  714. class BOOST_SIGNALS2_WEAK_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS);
  715. template<BOOST_SIGNALS2_SIGNAL_TEMPLATE_SPECIALIZATION_DECL(BOOST_SIGNALS2_NUM_ARGS)>
  716. class BOOST_SIGNALS2_WEAK_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)
  717. BOOST_SIGNALS2_SIGNAL_TEMPLATE_SPECIALIZATION
  718. {
  719. public:
  720. typedef typename BOOST_SIGNALS2_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)
  721. <BOOST_SIGNALS2_SIGNAL_TEMPLATE_INSTANTIATION>::result_type
  722. result_type;
  723. BOOST_SIGNALS2_WEAK_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)
  724. (const BOOST_SIGNALS2_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)
  725. <BOOST_SIGNALS2_SIGNAL_TEMPLATE_INSTANTIATION>
  726. &signal):
  727. _weak_pimpl(signal._pimpl)
  728. {}
  729. result_type operator ()(BOOST_SIGNALS2_SIGNATURE_FULL_ARGS(BOOST_SIGNALS2_NUM_ARGS))
  730. {
  731. shared_ptr<detail::BOOST_SIGNALS2_SIGNAL_IMPL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)
  732. <BOOST_SIGNALS2_SIGNAL_TEMPLATE_INSTANTIATION> >
  733. shared_pimpl(_weak_pimpl.lock());
  734. if(shared_pimpl == 0) boost::throw_exception(expired_slot());
  735. return (*shared_pimpl)(BOOST_SIGNALS2_SIGNATURE_ARG_NAMES(BOOST_SIGNALS2_NUM_ARGS));
  736. }
  737. result_type operator ()(BOOST_SIGNALS2_SIGNATURE_FULL_ARGS(BOOST_SIGNALS2_NUM_ARGS)) const
  738. {
  739. shared_ptr<detail::BOOST_SIGNALS2_SIGNAL_IMPL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)
  740. <BOOST_SIGNALS2_SIGNAL_TEMPLATE_INSTANTIATION> >
  741. shared_pimpl(_weak_pimpl.lock());
  742. if(shared_pimpl == 0) boost::throw_exception(expired_slot());
  743. return (*shared_pimpl)(BOOST_SIGNALS2_SIGNATURE_ARG_NAMES(BOOST_SIGNALS2_NUM_ARGS));
  744. }
  745. private:
  746. boost::weak_ptr<detail::BOOST_SIGNALS2_SIGNAL_IMPL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)
  747. <BOOST_SIGNALS2_SIGNAL_TEMPLATE_INSTANTIATION> > _weak_pimpl;
  748. };
  749. #ifndef BOOST_NO_CXX11_VARIADIC_TEMPLATES
  750. template<int arity, typename Signature>
  751. class extended_signature: public variadic_extended_signature<Signature>
  752. {};
  753. #else // BOOST_NO_CXX11_VARIADIC_TEMPLATES
  754. template<int arity, typename Signature>
  755. class extended_signature;
  756. // partial template specialization
  757. template<typename Signature>
  758. class extended_signature<BOOST_SIGNALS2_NUM_ARGS, Signature>
  759. {
  760. public:
  761. // typename function_traits<Signature>::result_type (
  762. // const boost::signals2::connection &,
  763. // typename function_traits<Signature>::arg1_type,
  764. // typename function_traits<Signature>::arg2_type,
  765. // ...,
  766. // typename function_traits<Signature>::argn_type)
  767. #define BOOST_SIGNALS2_EXT_SIGNATURE(arity, Signature) \
  768. typename function_traits<Signature>::result_type ( \
  769. const boost::signals2::connection & BOOST_SIGNALS2_PP_COMMA_IF(BOOST_SIGNALS2_NUM_ARGS) \
  770. BOOST_PP_ENUM(arity, BOOST_SIGNALS2_SIGNATURE_TO_ARGN_TYPE, Signature) )
  771. typedef function<BOOST_SIGNALS2_EXT_SIGNATURE(BOOST_SIGNALS2_NUM_ARGS, Signature)> function_type;
  772. #undef BOOST_SIGNALS2_EXT_SIGNATURE
  773. };
  774. template<unsigned arity, typename Signature, typename Combiner,
  775. typename Group, typename GroupCompare, typename SlotFunction,
  776. typename ExtendedSlotFunction, typename Mutex>
  777. class signalN;
  778. // partial template specialization
  779. template<typename Signature, typename Combiner, typename Group,
  780. typename GroupCompare, typename SlotFunction,
  781. typename ExtendedSlotFunction, typename Mutex>
  782. class signalN<BOOST_SIGNALS2_NUM_ARGS, Signature, Combiner, Group,
  783. GroupCompare, SlotFunction, ExtendedSlotFunction, Mutex>
  784. {
  785. public:
  786. typedef BOOST_SIGNALS2_SIGNAL_CLASS_NAME(BOOST_SIGNALS2_NUM_ARGS)<
  787. BOOST_SIGNALS2_PORTABLE_SIGNATURE(BOOST_SIGNALS2_NUM_ARGS, Signature),
  788. Combiner, Group,
  789. GroupCompare, SlotFunction, ExtendedSlotFunction, Mutex> type;
  790. };
  791. #endif // BOOST_NO_CXX11_VARIADIC_TEMPLATES
  792. } // namespace detail
  793. } // namespace signals2
  794. } // namespace boost
  795. #undef BOOST_SIGNALS2_NUM_ARGS
  796. #undef BOOST_SIGNALS2_SIGNAL_TEMPLATE_INSTANTIATION