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