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