function.hpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330
  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. #if !BOOST_PP_IS_ITERATING
  7. # ifndef BOOST_LOCAL_FUNCTION_AUX_FUNCTION_HPP_
  8. # define BOOST_LOCAL_FUNCTION_AUX_FUNCTION_HPP_
  9. # include <boost/local_function/config.hpp>
  10. # include <boost/local_function/aux_/member.hpp>
  11. # include <boost/call_traits.hpp>
  12. # include <boost/typeof/typeof.hpp>
  13. # include <boost/config.hpp>
  14. # include <boost/preprocessor/iteration/iterate.hpp>
  15. # include <boost/preprocessor/repetition/repeat.hpp>
  16. # include <boost/preprocessor/repetition/enum.hpp>
  17. # include <boost/preprocessor/punctuation/comma_if.hpp>
  18. # include <boost/preprocessor/arithmetic/add.hpp>
  19. # include <boost/preprocessor/arithmetic/sub.hpp>
  20. # include <boost/preprocessor/arithmetic/inc.hpp>
  21. # include <boost/preprocessor/control/iif.hpp>
  22. # include <boost/preprocessor/cat.hpp>
  23. // PRIVATE //
  24. #define BOOST_LOCAL_FUNCTION_AUX_FUNCTION_THIS_FILE_ \
  25. "boost/local_function/aux_/function.hpp"
  26. // PUBLIC //
  27. #define BOOST_LOCAL_FUNCTION_AUX_FUNCTION_INIT_CALL_FUNC \
  28. BOOST_LOCAL_FUNCTION_AUX_SYMBOL( (init_call) )
  29. #define BOOST_LOCAL_FUNCTION_AUX_typename_seq(z, n, unused) \
  30. (typename)
  31. #define BOOST_LOCAL_FUNCTION_AUX_arg_type(z, arg_n, unused) \
  32. BOOST_PP_CAT(Arg, arg_n)
  33. #define BOOST_LOCAL_FUNCTION_AUX_arg_typedef(z, arg_n, unused) \
  34. typedef \
  35. BOOST_LOCAL_FUNCTION_AUX_arg_type(z, arg_n, ~) \
  36. /* name must follow Boost.FunctionTraits arg1_type, arg2_type, ... */ \
  37. BOOST_PP_CAT(BOOST_PP_CAT(arg, BOOST_PP_INC(arg_n)), _type) \
  38. ;
  39. #define BOOST_LOCAL_FUNCTION_AUX_comma_arg_tparam(z, arg_n, unused) \
  40. , typename BOOST_LOCAL_FUNCTION_AUX_arg_type(z, arg_n, ~)
  41. #define BOOST_LOCAL_FUNCTION_AUX_arg_param_type(z, arg_n, comma01) \
  42. BOOST_PP_COMMA_IF(comma01) \
  43. typename ::boost::call_traits< \
  44. BOOST_LOCAL_FUNCTION_AUX_arg_type(z, arg_n, ~) \
  45. >::param_type
  46. #define BOOST_LOCAL_FUNCTION_AUX_arg_name(z, arg_n, comma01) \
  47. BOOST_PP_COMMA_IF(comma01) \
  48. BOOST_PP_CAT(arg, arg_n)
  49. #define BOOST_LOCAL_FUNCTION_AUX_arg_param_decl(z, arg_n, unused) \
  50. BOOST_LOCAL_FUNCTION_AUX_arg_param_type(z, arg_n, 0 /* no leading comma */)\
  51. BOOST_LOCAL_FUNCTION_AUX_arg_name(z, arg_n, 0 /* no leading comma */)
  52. #define BOOST_LOCAL_FUNCTION_AUX_bind_type(z, bind_n, unused) \
  53. BOOST_PP_CAT(Bind, bind_n)
  54. #define BOOST_LOCAL_FUNCTION_AUX_comma_bind_type(z, bind_n, unused) \
  55. , BOOST_LOCAL_FUNCTION_AUX_bind_type(z, bind_n, ~)
  56. #define BOOST_LOCAL_FUNCTION_AUX_comma_bind_ref(z, bind_n, unused) \
  57. , BOOST_LOCAL_FUNCTION_AUX_bind_type(z, bind_n, ~) &
  58. #define BOOST_LOCAL_FUNCTION_AUX_comma_bind_tparam(z, bind_n, unused) \
  59. , typename BOOST_LOCAL_FUNCTION_AUX_bind_type(z, bind_n, ~)
  60. #define BOOST_LOCAL_FUNCTION_AUX_bind_name(z, bind_n, unused) \
  61. BOOST_PP_CAT(bing, bind_n)
  62. #define BOOST_LOCAL_FUNCTION_AUX_comma_bind_param_decl(z, bind_n, unused) \
  63. , \
  64. BOOST_LOCAL_FUNCTION_AUX_bind_type(z, bind_n, ~) & \
  65. BOOST_LOCAL_FUNCTION_AUX_bind_name(z, bind_n, ~)
  66. #define BOOST_LOCAL_FUNCTION_AUX_bind_member(z, bind_n, unsued) \
  67. BOOST_PP_CAT(BOOST_LOCAL_FUNCTION_AUX_bind_name(z, bind_n, ~), _)
  68. #define BOOST_LOCAL_FUNCTION_AUX_comma_bind_member_deref(z, bind_n, unsued) \
  69. , member_deref< BOOST_LOCAL_FUNCTION_AUX_bind_type(z, bind_n, ~) >( \
  70. BOOST_LOCAL_FUNCTION_AUX_bind_member(z, bind_n, ~))
  71. #define BOOST_LOCAL_FUNCTION_AUX_bind_member_init(z, bind_n, unused) \
  72. BOOST_LOCAL_FUNCTION_AUX_bind_member(z, bind_n, ~) = member_addr( \
  73. BOOST_LOCAL_FUNCTION_AUX_bind_name(z, bind_n, ~));
  74. #define BOOST_LOCAL_FUNCTION_AUX_bind_member_decl(z, bind_n, unused) \
  75. /* must be ptr (not ref) so can use default constr */ \
  76. typename member_type< \
  77. BOOST_LOCAL_FUNCTION_AUX_bind_type(z, bind_n, ~) \
  78. >::pointer BOOST_LOCAL_FUNCTION_AUX_bind_member(z, bind_n, ~) ;
  79. #define BOOST_LOCAL_FUNCTION_AUX_call_ptr(z, n, unused) \
  80. BOOST_PP_CAT(call_ptr, n)
  81. #define BOOST_LOCAL_FUNCTION_AUX_call_name(z, n, unused) \
  82. BOOST_PP_CAT(call, n)
  83. #define BOOST_LOCAL_FUNCTION_AUX_call_member(z, n, unused) \
  84. BOOST_PP_CAT(BOOST_LOCAL_FUNCTION_AUX_call_name(z, n, unused), _)
  85. #define BOOST_LOCAL_FUNCTION_AUX_call_typedef(z, n, arity) \
  86. typedef R (*BOOST_LOCAL_FUNCTION_AUX_call_ptr(z, n, ~))( \
  87. object_ptr \
  88. BOOST_PP_IIF(BOOST_LOCAL_FUNCTION_CONFIG_LOCALS_AS_TPARAMS, \
  89. BOOST_PP_TUPLE_EAT(3) \
  90. , \
  91. BOOST_PP_REPEAT_ ## z \
  92. )(BOOST_LOCAL_FUNCTION_CONFIG_BIND_MAX, \
  93. BOOST_LOCAL_FUNCTION_AUX_comma_bind_ref, ~) \
  94. BOOST_PP_REPEAT_ ## z(BOOST_PP_SUB(arity, n), \
  95. BOOST_LOCAL_FUNCTION_AUX_arg_param_type, 1 /* leading comma */)\
  96. );
  97. #define BOOST_LOCAL_FUNCTION_AUX_comma_call_param_decl(z, n, unused) \
  98. , \
  99. BOOST_LOCAL_FUNCTION_AUX_call_ptr(z, n, ~) \
  100. BOOST_LOCAL_FUNCTION_AUX_call_name(z, n, ~)
  101. #define BOOST_LOCAL_FUNCTION_AUX_call_decl(z, n, unused) \
  102. BOOST_LOCAL_FUNCTION_AUX_call_ptr(z, n, ~) \
  103. BOOST_LOCAL_FUNCTION_AUX_call_member(z, n, ~);
  104. #define BOOST_LOCAL_FUNCTION_AUX_call_init(z, n, unused) \
  105. BOOST_LOCAL_FUNCTION_AUX_call_member(z, n, ~) = \
  106. BOOST_LOCAL_FUNCTION_AUX_call_name(z, n, ~);
  107. #define BOOST_LOCAL_FUNCTION_AUX_operator_call(z, defaults_n, arity) \
  108. /* precondition: object_ && call_function_ */ \
  109. inline R operator()( \
  110. BOOST_PP_ENUM_ ## z(BOOST_PP_SUB(arity, defaults_n), \
  111. BOOST_LOCAL_FUNCTION_AUX_arg_param_decl, ~) \
  112. ) /* cannot be const because of binds (same as for local ftor) */ { \
  113. /* run-time: do not assert preconditions here for efficiency */ \
  114. /* run-time: this function call is done via a function pointer */ \
  115. /* so unfortunately does not allow for compiler inlining */ \
  116. /* optimizations (an alternative using virtual function was also */ \
  117. /* investigated but also virtual functions cannot be optimized */ \
  118. /* plus they require virtual table lookups to the alternative */ \
  119. /* performed worst) */ \
  120. return BOOST_LOCAL_FUNCTION_AUX_call_member(z, defaults_n, ~)( \
  121. object_ \
  122. BOOST_PP_IIF( \
  123. BOOST_LOCAL_FUNCTION_CONFIG_LOCALS_AS_TPARAMS,\
  124. BOOST_PP_TUPLE_EAT(3) \
  125. , \
  126. BOOST_PP_REPEAT_ ## z \
  127. )(BOOST_LOCAL_FUNCTION_CONFIG_BIND_MAX, \
  128. BOOST_LOCAL_FUNCTION_AUX_comma_bind_member_deref, ~) \
  129. BOOST_PP_REPEAT_ ## z(BOOST_PP_SUB(arity, defaults_n), \
  130. BOOST_LOCAL_FUNCTION_AUX_arg_name, 1 /* leading comma */) \
  131. ); \
  132. }
  133. namespace boost { namespace local_function { namespace aux {
  134. template<
  135. typename F
  136. , size_t defaults
  137. #if !BOOST_LOCAL_FUNCTION_CONFIG_LOCALS_AS_TPARAMS
  138. BOOST_PP_REPEAT(BOOST_LOCAL_FUNCTION_CONFIG_BIND_MAX,
  139. BOOST_LOCAL_FUNCTION_AUX_comma_bind_tparam, ~)
  140. #endif
  141. >
  142. class function {}; // Empty template, only use its specializations.
  143. // Iterate within namespace.
  144. # define BOOST_PP_ITERATION_PARAMS_1 \
  145. (3, (0, BOOST_LOCAL_FUNCTION_CONFIG_FUNCTION_ARITY_MAX, \
  146. BOOST_LOCAL_FUNCTION_AUX_FUNCTION_THIS_FILE_))
  147. # include BOOST_PP_ITERATE() // Iterate over function arity.
  148. } } } // namespace
  149. // Register type for type-of emu (NAME use TYPEOF to deduce this fctor type).
  150. #include BOOST_TYPEOF_INCREMENT_REGISTRATION_GROUP()
  151. BOOST_TYPEOF_REGISTER_TEMPLATE(boost::local_function::aux::function,
  152. (typename) // For `F` tparam.
  153. (size_t) // For `defaults` tparam.
  154. // MSVC error if using #if instead of PP_IIF here.
  155. BOOST_PP_IIF(BOOST_LOCAL_FUNCTION_CONFIG_LOCALS_AS_TPARAMS,
  156. BOOST_PP_TUPLE_EAT(3) // Nothing.
  157. ,
  158. BOOST_PP_REPEAT // For bind tparams.
  159. )(BOOST_LOCAL_FUNCTION_CONFIG_BIND_MAX,
  160. BOOST_LOCAL_FUNCTION_AUX_typename_seq, ~)
  161. )
  162. #undef BOOST_LOCAL_FUNCTION_AUX_typename_seq
  163. #undef BOOST_LOCAL_FUNCTION_AUX_arg_type
  164. #undef BOOST_LOCAL_FUNCTION_AUX_arg_typedef
  165. #undef BOOST_LOCAL_FUNCTION_AUX_comma_arg_tparam
  166. #undef BOOST_LOCAL_FUNCTION_AUX_arg_param_type
  167. #undef BOOST_LOCAL_FUNCTION_AUX_arg_name
  168. #undef BOOST_LOCAL_FUNCTION_AUX_arg_param_decl
  169. #undef BOOST_LOCAL_FUNCTION_AUX_bind_type
  170. #undef BOOST_LOCAL_FUNCTION_AUX_comma_bind_type
  171. #undef BOOST_LOCAL_FUNCTION_AUX_comma_bind_ref
  172. #undef BOOST_LOCAL_FUNCTION_AUX_comma_bind_tparam
  173. #undef BOOST_LOCAL_FUNCTION_AUX_bind_name
  174. #undef BOOST_LOCAL_FUNCTION_AUX_comma_bind_param_decl
  175. #undef BOOST_LOCAL_FUNCTION_AUX_bind_member
  176. #undef BOOST_LOCAL_FUNCTION_AUX_comma_bind_member_deref
  177. #undef BOOST_LOCAL_FUNCTION_AUX_bind_member_init
  178. #undef BOOST_LOCAL_FUNCTION_AUX_bind_member_decl
  179. #undef BOOST_LOCAL_FUNCTION_AUX_call_ptr
  180. #undef BOOST_LOCAL_FUNCTION_AUX_call_name
  181. #undef BOOST_LOCAL_FUNCTION_AUX_call_member
  182. #undef BOOST_LOCAL_FUNCTION_AUX_call_typedef
  183. #undef BOOST_LOCAL_FUNCTION_AUX_comma_call_param_decl
  184. #undef BOOST_LOCAL_FUNCTION_AUX_call_decl
  185. #undef BOOST_LOCAL_FUNCTION_AUX_call_init
  186. #undef BOOST_LOCAL_FUNCTION_AUX_operator_call
  187. # endif // #include guard
  188. #elif BOOST_PP_ITERATION_DEPTH() == 1
  189. # define BOOST_LOCAL_FUNCTION_AUX_arity BOOST_PP_FRAME_ITERATION(1)
  190. # define BOOST_PP_ITERATION_PARAMS_2 \
  191. (3, (0, BOOST_LOCAL_FUNCTION_AUX_arity, \
  192. BOOST_LOCAL_FUNCTION_AUX_FUNCTION_THIS_FILE_))
  193. # include BOOST_PP_ITERATE() // Iterate over default params count.
  194. # undef BOOST_LOCAL_FUNCTION_AUX_arity
  195. #elif BOOST_PP_ITERATION_DEPTH() == 2
  196. # define BOOST_LOCAL_FUNCTION_AUX_defaults BOOST_PP_FRAME_ITERATION(2)
  197. template<
  198. typename R
  199. BOOST_PP_REPEAT(BOOST_LOCAL_FUNCTION_AUX_arity,
  200. BOOST_LOCAL_FUNCTION_AUX_comma_arg_tparam, ~)
  201. #if !BOOST_LOCAL_FUNCTION_CONFIG_LOCALS_AS_TPARAMS
  202. BOOST_PP_REPEAT(BOOST_LOCAL_FUNCTION_CONFIG_BIND_MAX,
  203. BOOST_LOCAL_FUNCTION_AUX_comma_bind_tparam, ~)
  204. #endif
  205. >
  206. class function<
  207. R (
  208. BOOST_PP_ENUM(BOOST_LOCAL_FUNCTION_AUX_arity,
  209. BOOST_LOCAL_FUNCTION_AUX_arg_type, ~)
  210. )
  211. , BOOST_LOCAL_FUNCTION_AUX_defaults
  212. #if !BOOST_LOCAL_FUNCTION_CONFIG_LOCALS_AS_TPARAMS
  213. BOOST_PP_REPEAT(BOOST_LOCAL_FUNCTION_CONFIG_BIND_MAX,
  214. BOOST_LOCAL_FUNCTION_AUX_comma_bind_type, ~)
  215. #endif
  216. > {
  217. // The object type will actually be a local class which cannot be passed as
  218. // a template parameter so a generic `void*` pointer is used to hold the
  219. // object (this pointer will then be cased by the call-function implemented
  220. // by the local class itself). This is the trick used to pass a local
  221. // function as a template parameter. This trick uses function pointers for
  222. // the call-functions and function pointers cannot always be optimized by
  223. // the compiler (they cannot be inlined) thus this trick increased run-time
  224. // (another trick using virtual functions for the local class was also
  225. // investigated but also virtual functions cannot be inlined plus they
  226. // require virtual tables lookups so the virtual functions trick measured
  227. // worst run-time performance than the function pointer trick).
  228. typedef void* object_ptr;
  229. BOOST_PP_REPEAT(BOOST_PP_INC(BOOST_LOCAL_FUNCTION_AUX_defaults),
  230. BOOST_LOCAL_FUNCTION_AUX_call_typedef, // INC for no defaults.
  231. BOOST_LOCAL_FUNCTION_AUX_arity)
  232. public:
  233. // Provide public type interface following Boost.Function names
  234. // (traits must be defined in both this and the local functor).
  235. BOOST_STATIC_CONSTANT(size_t, arity = BOOST_LOCAL_FUNCTION_AUX_arity);
  236. typedef R result_type;
  237. BOOST_PP_REPEAT(BOOST_LOCAL_FUNCTION_AUX_arity,
  238. BOOST_LOCAL_FUNCTION_AUX_arg_typedef, ~)
  239. // NOTE: Must have default constructor for init without function name in
  240. // function macro expansion.
  241. // Cannot be private but it should never be used by programmers directly
  242. // so used internal symbol.
  243. inline void BOOST_LOCAL_FUNCTION_AUX_FUNCTION_INIT_CALL_FUNC(
  244. object_ptr object
  245. #if !BOOST_LOCAL_FUNCTION_CONFIG_LOCALS_AS_TPARAMS
  246. BOOST_PP_REPEAT(BOOST_LOCAL_FUNCTION_CONFIG_BIND_MAX,
  247. BOOST_LOCAL_FUNCTION_AUX_comma_bind_param_decl, ~)
  248. #endif
  249. BOOST_PP_REPEAT(BOOST_PP_INC(BOOST_LOCAL_FUNCTION_AUX_defaults),
  250. BOOST_LOCAL_FUNCTION_AUX_comma_call_param_decl, ~)
  251. ) {
  252. object_ = object;
  253. #if !BOOST_LOCAL_FUNCTION_CONFIG_LOCALS_AS_TPARAMS
  254. BOOST_PP_REPEAT(BOOST_LOCAL_FUNCTION_CONFIG_BIND_MAX,
  255. BOOST_LOCAL_FUNCTION_AUX_bind_member_init, ~)
  256. #endif
  257. BOOST_PP_REPEAT(BOOST_PP_INC(BOOST_LOCAL_FUNCTION_AUX_defaults),
  258. BOOST_LOCAL_FUNCTION_AUX_call_init, ~) // INC for no defaults.
  259. unused_ = 0; // To avoid a GCC uninitialized warning.
  260. }
  261. // Result operator(Arg1, ..., ArgN-1, ArgN) -- iff defaults >= 0
  262. // Result operator(Arg1, ..., ArgN-1) -- iff defaults >= 1
  263. // ... -- etc
  264. BOOST_PP_REPEAT(BOOST_PP_INC(BOOST_LOCAL_FUNCTION_AUX_defaults),
  265. BOOST_LOCAL_FUNCTION_AUX_operator_call, // INC for no defaults.
  266. BOOST_LOCAL_FUNCTION_AUX_arity)
  267. private:
  268. object_ptr object_;
  269. #if !BOOST_LOCAL_FUNCTION_CONFIG_LOCALS_AS_TPARAMS
  270. BOOST_PP_REPEAT(BOOST_LOCAL_FUNCTION_CONFIG_BIND_MAX,
  271. BOOST_LOCAL_FUNCTION_AUX_bind_member_decl, ~)
  272. #endif
  273. BOOST_PP_REPEAT(BOOST_PP_INC(BOOST_LOCAL_FUNCTION_AUX_defaults),
  274. BOOST_LOCAL_FUNCTION_AUX_call_decl, ~) // INC for no defaults.
  275. // run-time: this unused void* member variable allows for compiler
  276. // optimizations (at least on MSVC it reduces invocation time of about 50%)
  277. void* unused_;
  278. };
  279. # undef BOOST_LOCAL_FUNCTION_AUX_defaults
  280. #endif // iteration