]>
Commit | Line | Data |
---|---|---|
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 |