bind.hpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. // Copyright (C) 2009-2012 Lorenzo Caminiti
  2. // Distributed under the Boost Software License, Version 1.0
  3. // (see accompanying file LICENSE_1_0.txt or a copy at
  4. // http://www.boost.org/LICENSE_1_0.txt)
  5. // Home at http://www.boost.org/libs/local_function
  6. #ifndef BOOST_LOCAL_FUNCTION_AUX_CODE_BIND_HPP_
  7. #define BOOST_LOCAL_FUNCTION_AUX_CODE_BIND_HPP_
  8. #include <boost/local_function/aux_/symbol.hpp>
  9. #include <boost/local_function/aux_/macro/decl.hpp>
  10. #include <boost/local_function/aux_/preprocessor/traits/bind.hpp>
  11. #include <boost/local_function/aux_/preprocessor/traits/decl_binds.hpp>
  12. #include <boost/local_function/aux_/preprocessor/traits/decl_const_binds.hpp>
  13. #include <boost/utility/identity_type.hpp>
  14. #include <boost/scope_exit.hpp>
  15. #include <boost/type_traits/remove_reference.hpp>
  16. #include <boost/type_traits/function_traits.hpp>
  17. #include <boost/preprocessor/control/expr_iif.hpp>
  18. #include <boost/preprocessor/control/iif.hpp>
  19. #include <boost/preprocessor/facilities/empty.hpp>
  20. #include <boost/preprocessor/facilities/is_empty.hpp>
  21. #include <boost/preprocessor/facilities/identity.hpp>
  22. #include <boost/preprocessor/logical/bitand.hpp>
  23. #include <boost/preprocessor/punctuation/comma_if.hpp>
  24. #include <boost/preprocessor/tuple/elem.hpp>
  25. #include <boost/preprocessor/tuple/eat.hpp>
  26. #include <boost/preprocessor/list/adt.hpp>
  27. #include <boost/preprocessor/list/for_each_i.hpp>
  28. #include <boost/preprocessor/list/append.hpp>
  29. // PRIVATE //
  30. #define BOOST_LOCAL_FUNCTION_AUX_CODE_BIND_PARAMS_VAR_(id) \
  31. BOOST_LOCAL_FUNCTION_AUX_SYMBOL( (params)(id) )
  32. #define BOOST_LOCAL_FUNCTION_AUX_CODE_BIND_TAG_DECL_(r, id, i, bind_traits) \
  33. BOOST_SCOPE_EXIT_DETAIL_TAG_DECL(r, id, i, \
  34. BOOST_LOCAL_FUNCTION_AUX_PP_BIND_TRAITS_VAR_WITHOUT_TYPE( \
  35. bind_traits))
  36. #define BOOST_LOCAL_FUNCTION_AUX_CODE_BIND_CAPTURE_DECL_TYPED_( \
  37. r, id, typename01, i, bind_traits) \
  38. typedef BOOST_PP_EXPR_IIF(typename01, typename) \
  39. /* remove ref because typed var can have & prefix */ \
  40. ::boost::remove_reference< BOOST_PP_EXPR_IIF(typename01, typename) \
  41. ::boost::function_traits< \
  42. /* instead of using Boost.Typeof, get bind type as 1st */ \
  43. /* argument type of func type `void (type_ [&] var_)` */ \
  44. void ( BOOST_LOCAL_FUNCTION_AUX_PP_BIND_TRAITS_VAR_WITH_TYPE( \
  45. bind_traits) ) \
  46. >::arg1_type \
  47. >::type \
  48. BOOST_SCOPE_EXIT_DETAIL_CAPTURE_T(id, i, \
  49. BOOST_LOCAL_FUNCTION_AUX_PP_BIND_TRAITS_VAR_WITHOUT_TYPE( \
  50. bind_traits)) \
  51. ; /* close typedef */
  52. #define BOOST_LOCAL_FUNCTION_AUX_CODE_BIND_CAPTURE_DECL_DEDUCED_( \
  53. r, id, typename01, i, bind_traits) \
  54. BOOST_SCOPE_EXIT_DETAIL_CAPTURE_DECL(r, \
  55. ( \
  56. id \
  57. , \
  58. /* ScopeExit expects typename or EMPTY() here */ \
  59. BOOST_PP_EXPR_IIF(typename01, typename) \
  60. ), \
  61. i, BOOST_LOCAL_FUNCTION_AUX_PP_BIND_TRAITS_VAR_WITHOUT_TYPE( \
  62. bind_traits))
  63. #define BOOST_LOCAL_FUNCTION_AUX_CODE_BIND_CAPTURE_DECL_( \
  64. r, id_typename, i, bind_traits) \
  65. BOOST_PP_IIF(BOOST_PP_IS_EMPTY( \
  66. BOOST_LOCAL_FUNCTION_AUX_PP_BIND_TRAITS_VAR_WITH_TYPE(bind_traits)), \
  67. BOOST_LOCAL_FUNCTION_AUX_CODE_BIND_CAPTURE_DECL_DEDUCED_ \
  68. , \
  69. BOOST_LOCAL_FUNCTION_AUX_CODE_BIND_CAPTURE_DECL_TYPED_ \
  70. )(r, BOOST_PP_TUPLE_ELEM(2, 0, id_typename), \
  71. BOOST_PP_TUPLE_ELEM(2, 1, id_typename), i, bind_traits)
  72. #define BOOST_LOCAL_FUNCTION_AUX_CODE_BIND_PARAM_DECL_( \
  73. r, id_typename, i, bind_traits) \
  74. BOOST_SCOPE_EXIT_DETAIL_PARAM_DECL(r, \
  75. ( \
  76. BOOST_PP_TUPLE_ELEM(2, 0, id_typename) \
  77. , \
  78. /* ScopeExit expects typename or EMPTY() here */ \
  79. BOOST_PP_EXPR_IIF(BOOST_PP_TUPLE_ELEM(2, 1, id_typename), \
  80. typename \
  81. ) \
  82. ), \
  83. i, BOOST_LOCAL_FUNCTION_AUX_PP_BIND_TRAITS_VAR_WITHOUT_TYPE( \
  84. bind_traits))
  85. #define BOOST_LOCAL_FUNCTION_AUX_CODE_BIND_MEMBER_DECL_VAR_( \
  86. r, id, typename01, i, var) \
  87. BOOST_PP_EXPR_IIF(typename01, typename) \
  88. BOOST_IDENTITY_TYPE(( /* must use IDENTITY because of tparam comma */ \
  89. ::boost::scope_exit::detail::member< \
  90. BOOST_SCOPE_EXIT_DETAIL_PARAM_T(id, i, var) \
  91. , BOOST_SCOPE_EXIT_DETAIL_TAG(id, i) \
  92. > \
  93. )) \
  94. BOOST_SCOPE_EXIT_DETAIL_PARAM(id, i, var);
  95. #define BOOST_LOCAL_FUNCTION_AUX_CODE_BIND_MEMBER_DECL_( \
  96. r, id_typename, i, bind_traits) \
  97. BOOST_LOCAL_FUNCTION_AUX_CODE_BIND_MEMBER_DECL_VAR_(r, \
  98. BOOST_PP_TUPLE_ELEM(2, 0, id_typename), \
  99. BOOST_PP_TUPLE_ELEM(2, 1, id_typename), \
  100. i, BOOST_LOCAL_FUNCTION_AUX_PP_BIND_TRAITS_VAR_WITHOUT_TYPE( \
  101. bind_traits))
  102. #define BOOST_LOCAL_FUNCTION_AUX_CODE_BIND_PARAM_INIT_(r, id, i, bind_traits) \
  103. BOOST_SCOPE_EXIT_DETAIL_PARAM_INIT(r, id, i, \
  104. BOOST_LOCAL_FUNCTION_AUX_PP_BIND_TRAITS_VAR_WITHOUT_TYPE( \
  105. bind_traits))
  106. #define BOOST_LOCAL_FUNCTION_AUX_CODE_BIND_THIS_CAPTURE_TYPE_(id) \
  107. BOOST_LOCAL_FUNCTION_AUX_SYMBOL( (this_capture_type)(id) )
  108. #define BOOST_LOCAL_FUNCTION_AUX_CODE_BIND_THIS_TYPE_(id) \
  109. BOOST_LOCAL_FUNCTION_AUX_SYMBOL( (this_type)(id) )
  110. #define BOOST_LOCAL_FUNCTION_AUX_CODE_BIND_THIS_TYPEDEF_DEDUCED_( \
  111. id, typename01, all_bind_this_types) \
  112. BOOST_SCOPE_EXIT_DETAIL_TYPEDEF_TYPEOF_THIS(id, \
  113. BOOST_PP_EXPR_IIF(typename01, typename), /* otherwise EMPTY() */ \
  114. BOOST_LOCAL_FUNCTION_AUX_CODE_BIND_THIS_CAPTURE_TYPE_(id))
  115. #define BOOST_LOCAL_FUNCTION_AUX_CODE_BIND_THIS_TYPEDEF_TYPED_( \
  116. id, typename01, all_bind_this_types) \
  117. typedef \
  118. BOOST_LOCAL_FUNCTION_AUX_PP_BIND_TRAITS_THIS_TYPE(BOOST_PP_LIST_FIRST( \
  119. all_bind_this_types)) \
  120. BOOST_LOCAL_FUNCTION_AUX_CODE_BIND_THIS_CAPTURE_TYPE_(id) \
  121. ;
  122. #define BOOST_LOCAL_FUNCTION_AUX_CODE_BIND_THIS_TYPEDEF_( \
  123. id, typename01, all_bind_this_types) \
  124. /* typedef type_ */ \
  125. BOOST_PP_IIF(BOOST_PP_IS_EMPTY( \
  126. /* all_bind_this_type is list with 1 elem (possibly PP_EMPTY), */ \
  127. /* otherwise got a pp-parsing error before getting here */ \
  128. BOOST_LOCAL_FUNCTION_AUX_PP_BIND_TRAITS_THIS_TYPE( \
  129. BOOST_PP_LIST_FIRST(all_bind_this_types))), \
  130. BOOST_LOCAL_FUNCTION_AUX_CODE_BIND_THIS_TYPEDEF_DEDUCED_ \
  131. , \
  132. BOOST_LOCAL_FUNCTION_AUX_CODE_BIND_THIS_TYPEDEF_TYPED_ \
  133. )(id, typename01, all_bind_this_types)
  134. #define BOOST_LOCAL_FUNCTION_AUX_CODE_BIND_ALL_( \
  135. all_binds, all_bind_this_types, id, typename01) \
  136. /* binding tags */ \
  137. BOOST_PP_IIF(BOOST_PP_LIST_IS_CONS(all_bind_this_types), \
  138. BOOST_LOCAL_FUNCTION_AUX_CODE_BIND_THIS_TYPEDEF_ \
  139. , \
  140. BOOST_PP_TUPLE_EAT(3) \
  141. )(id, typename01, all_bind_this_types) \
  142. BOOST_PP_LIST_FOR_EACH_I(BOOST_LOCAL_FUNCTION_AUX_CODE_BIND_TAG_DECL_, id, \
  143. all_binds) \
  144. BOOST_PP_LIST_FOR_EACH_I(BOOST_LOCAL_FUNCTION_AUX_CODE_BIND_CAPTURE_DECL_, \
  145. (id, typename01), all_binds) \
  146. /* binding class */ \
  147. struct BOOST_SCOPE_EXIT_DETAIL_PARAMS_T(id) { \
  148. /* interim capture types to workaround internal error on old GCC */ \
  149. BOOST_PP_EXPR_IIF(BOOST_PP_LIST_IS_CONS(all_bind_this_types), \
  150. typedef BOOST_LOCAL_FUNCTION_AUX_CODE_BIND_THIS_CAPTURE_TYPE_(id) \
  151. BOOST_LOCAL_FUNCTION_AUX_CODE_BIND_THIS_TYPE_(id) ; \
  152. ) \
  153. BOOST_PP_EXPR_IIF(BOOST_PP_LIST_IS_CONS(all_bind_this_types), \
  154. BOOST_LOCAL_FUNCTION_AUX_CODE_BIND_THIS_TYPE_(id) \
  155. BOOST_LOCAL_FUNCTION_AUX_CODE_BIND_THIS_VAR; \
  156. ) \
  157. BOOST_PP_LIST_FOR_EACH_I( \
  158. BOOST_LOCAL_FUNCTION_AUX_CODE_BIND_PARAM_DECL_, \
  159. (id, typename01), all_binds) \
  160. BOOST_PP_LIST_FOR_EACH_I( \
  161. BOOST_LOCAL_FUNCTION_AUX_CODE_BIND_MEMBER_DECL_, \
  162. (id, typename01), all_binds) \
  163. } BOOST_LOCAL_FUNCTION_AUX_CODE_BIND_PARAMS_VAR_(id) = \
  164. /* NOTE: there is no way to wrap member initializer commas within */ \
  165. /* parenthesis so you must handle these commas manually if expanding */ \
  166. /* this macro within another macro */ \
  167. { \
  168. /* initialize the struct with param values to bind */ \
  169. BOOST_PP_EXPR_IIF(BOOST_PP_LIST_IS_CONS(all_bind_this_types), \
  170. this) /* here name `this` access object at enclosing scope */ \
  171. BOOST_PP_COMMA_IF(BOOST_PP_BITAND( \
  172. BOOST_PP_LIST_IS_CONS(all_bind_this_types) \
  173. , BOOST_PP_LIST_IS_CONS(all_binds) \
  174. )) \
  175. BOOST_PP_LIST_FOR_EACH_I( \
  176. BOOST_LOCAL_FUNCTION_AUX_CODE_BIND_PARAM_INIT_, id, all_binds) \
  177. };
  178. #define BOOST_LOCAL_FUNCTION_AUX_CODE_BIND_(id, typename01, decl_traits) \
  179. /* IMPORTANT: the order of these appends is important, it must follow */ \
  180. /* the indexing order used by the functor code which starts */ \
  181. /* enumerating const binds and then non-const binds */ \
  182. BOOST_LOCAL_FUNCTION_AUX_CODE_BIND_ALL_( \
  183. BOOST_PP_LIST_APPEND( \
  184. BOOST_LOCAL_FUNCTION_AUX_PP_DECL_TRAITS_CONST_BINDS( \
  185. decl_traits),\
  186. BOOST_LOCAL_FUNCTION_AUX_PP_DECL_TRAITS_BINDS( \
  187. decl_traits)), \
  188. BOOST_PP_LIST_APPEND( \
  189. BOOST_LOCAL_FUNCTION_AUX_PP_DECL_TRAITS_CONST_BIND_THIS_TYPES(decl_traits), \
  190. BOOST_LOCAL_FUNCTION_AUX_PP_DECL_TRAITS_BIND_THIS_TYPES( \
  191. decl_traits)), \
  192. id, typename01)
  193. // PUBLIC //
  194. #define BOOST_LOCAL_FUNCTION_AUX_CODE_BIND_THIS_TYPE(id, typename01) \
  195. BOOST_PP_EXPR_IIF(typename01, typename) \
  196. BOOST_SCOPE_EXIT_DETAIL_PARAMS_T(id):: \
  197. BOOST_LOCAL_FUNCTION_AUX_CODE_BIND_THIS_TYPE_(id)
  198. #define BOOST_LOCAL_FUNCTION_AUX_CODE_BIND_THIS_VAR \
  199. BOOST_LOCAL_FUNCTION_AUX_SYMBOL( (this_var) )
  200. #define BOOST_LOCAL_FUNCTION_AUX_CODE_BIND(id, typename01, decl_traits) \
  201. /* the binding data structures must be declared and initialized (to */ \
  202. /* empty structs, so hopefully the compiler will optimize away the */ \
  203. /* no-op code) even when there is no bound param because these structs */ \
  204. /* are used to init `...args.value` which is always used by the `END` */ \
  205. /* macro later because this macro does not know if there are bound */ \
  206. /* params or not */ \
  207. BOOST_LOCAL_FUNCTION_AUX_CODE_BIND_(id, typename01, decl_traits) \
  208. /* this code takes advantage of the template argument list/comparison */ \
  209. /* operator ambiguity to declare a variable iff it hasn't already been */ \
  210. /* declared in that scope; the second occurrence is parsed as: */ \
  211. /* (declared<(resolve<sizeof(boost_local_auxXargs)>::cmp1<0)>::cmp2> */ \
  212. /* ...Xargs); */ \
  213. /* which is a no-op */ \
  214. ::boost::scope_exit::detail::declared< boost::scope_exit::detail::resolve< \
  215. /* cannot prefix with `::` as in `sizeof(:: ...` because the name */ \
  216. /* must refer to the local variable name to allow multiple local */ \
  217. /* functions (and exits) within the same scope (however this */ \
  218. /* does not allow for nesting because local variables cannot be */ \
  219. /* used in nested code blocks) */ \
  220. sizeof(BOOST_LOCAL_FUNCTION_AUX_DECL_ARGS_VAR) \
  221. >::cmp1<0>::cmp2 > BOOST_LOCAL_FUNCTION_AUX_DECL_ARGS_VAR; \
  222. /* stores bound types/values into `...args` variable (args variable */ \
  223. /* can be accessed by `NAME` macro because doesn't use __LINE__ id) */ \
  224. BOOST_LOCAL_FUNCTION_AUX_DECL_ARGS_VAR.value = \
  225. &BOOST_LOCAL_FUNCTION_AUX_CODE_BIND_PARAMS_VAR_(id);
  226. #endif // #include guard