summaryrefslogtreecommitdiff
path: root/boost/local_function/aux_/function.hpp
blob: e6de939743a7a92a85e939623a21f97b36770835 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330

// Copyright (C) 2009-2012 Lorenzo Caminiti
// Distributed under the Boost Software License, Version 1.0
// (see accompanying file LICENSE_1_0.txt or a copy at
// http://www.boost.org/LICENSE_1_0.txt)
// Home at http://www.boost.org/libs/local_function

#if !BOOST_PP_IS_ITERATING
#   ifndef BOOST_LOCAL_FUNCTION_AUX_FUNCTION_HPP_
#       define BOOST_LOCAL_FUNCTION_AUX_FUNCTION_HPP_

#       include <boost/local_function/config.hpp>
#       include <boost/local_function/aux_/member.hpp>
#       include <boost/call_traits.hpp>
#       include <boost/typeof/typeof.hpp>
#       include <boost/config.hpp>
#       include <boost/preprocessor/iteration/iterate.hpp>
#       include <boost/preprocessor/repetition/repeat.hpp>
#       include <boost/preprocessor/repetition/enum.hpp>
#       include <boost/preprocessor/punctuation/comma_if.hpp>
#       include <boost/preprocessor/arithmetic/add.hpp>
#       include <boost/preprocessor/arithmetic/sub.hpp>
#       include <boost/preprocessor/arithmetic/inc.hpp>
#       include <boost/preprocessor/control/iif.hpp>
#       include <boost/preprocessor/cat.hpp>

// PRIVATE //

#define BOOST_LOCAL_FUNCTION_AUX_FUNCTION_THIS_FILE_ \
    "boost/local_function/aux_/function.hpp"

// PUBLIC //

#define BOOST_LOCAL_FUNCTION_AUX_FUNCTION_INIT_CALL_FUNC \
    BOOST_LOCAL_FUNCTION_AUX_SYMBOL( (init_call) )

#define BOOST_LOCAL_FUNCTION_AUX_typename_seq(z, n, unused) \
    (typename)

#define BOOST_LOCAL_FUNCTION_AUX_arg_type(z, arg_n, unused) \
    BOOST_PP_CAT(Arg, arg_n)

#define BOOST_LOCAL_FUNCTION_AUX_arg_typedef(z, arg_n, unused) \
    typedef \
        BOOST_LOCAL_FUNCTION_AUX_arg_type(z, arg_n, ~) \
        /* name must follow Boost.FunctionTraits arg1_type, arg2_type, ... */ \
        BOOST_PP_CAT(BOOST_PP_CAT(arg, BOOST_PP_INC(arg_n)), _type) \
    ;

#define BOOST_LOCAL_FUNCTION_AUX_comma_arg_tparam(z, arg_n, unused) \
    , typename BOOST_LOCAL_FUNCTION_AUX_arg_type(z, arg_n, ~)

#define BOOST_LOCAL_FUNCTION_AUX_arg_param_type(z, arg_n, comma01) \
    BOOST_PP_COMMA_IF(comma01) \
    typename ::boost::call_traits< \
        BOOST_LOCAL_FUNCTION_AUX_arg_type(z, arg_n, ~) \
    >::param_type

#define BOOST_LOCAL_FUNCTION_AUX_arg_name(z, arg_n, comma01) \
    BOOST_PP_COMMA_IF(comma01) \
    BOOST_PP_CAT(arg, arg_n)

#define BOOST_LOCAL_FUNCTION_AUX_arg_param_decl(z, arg_n, unused) \
    BOOST_LOCAL_FUNCTION_AUX_arg_param_type(z, arg_n, 0 /* no leading comma */)\
    BOOST_LOCAL_FUNCTION_AUX_arg_name(z, arg_n, 0 /* no leading comma */)

#define BOOST_LOCAL_FUNCTION_AUX_bind_type(z, bind_n, unused) \
    BOOST_PP_CAT(Bind, bind_n)

#define BOOST_LOCAL_FUNCTION_AUX_comma_bind_type(z, bind_n, unused) \
    , BOOST_LOCAL_FUNCTION_AUX_bind_type(z, bind_n, ~)

#define BOOST_LOCAL_FUNCTION_AUX_comma_bind_ref(z, bind_n, unused) \
    , BOOST_LOCAL_FUNCTION_AUX_bind_type(z, bind_n, ~) &

#define BOOST_LOCAL_FUNCTION_AUX_comma_bind_tparam(z, bind_n, unused) \
    , typename BOOST_LOCAL_FUNCTION_AUX_bind_type(z, bind_n, ~)

#define BOOST_LOCAL_FUNCTION_AUX_bind_name(z, bind_n, unused) \
    BOOST_PP_CAT(bing, bind_n)

#define BOOST_LOCAL_FUNCTION_AUX_comma_bind_param_decl(z, bind_n, unused) \
    , \
    BOOST_LOCAL_FUNCTION_AUX_bind_type(z, bind_n, ~) & \
    BOOST_LOCAL_FUNCTION_AUX_bind_name(z, bind_n, ~)
    
#define BOOST_LOCAL_FUNCTION_AUX_bind_member(z, bind_n, unsued) \
    BOOST_PP_CAT(BOOST_LOCAL_FUNCTION_AUX_bind_name(z, bind_n, ~), _)

#define BOOST_LOCAL_FUNCTION_AUX_comma_bind_member_deref(z, bind_n, unsued) \
    , member_deref< BOOST_LOCAL_FUNCTION_AUX_bind_type(z, bind_n, ~) >( \
            BOOST_LOCAL_FUNCTION_AUX_bind_member(z, bind_n, ~))

#define BOOST_LOCAL_FUNCTION_AUX_bind_member_init(z, bind_n, unused) \
    BOOST_LOCAL_FUNCTION_AUX_bind_member(z, bind_n, ~) = member_addr( \
            BOOST_LOCAL_FUNCTION_AUX_bind_name(z, bind_n, ~));

#define BOOST_LOCAL_FUNCTION_AUX_bind_member_decl(z, bind_n, unused) \
    /* must be ptr (not ref) so can use default constr */ \
    typename member_type< \
        BOOST_LOCAL_FUNCTION_AUX_bind_type(z, bind_n, ~) \
    >::pointer BOOST_LOCAL_FUNCTION_AUX_bind_member(z, bind_n, ~) ;

#define BOOST_LOCAL_FUNCTION_AUX_call_ptr(z, n, unused) \
    BOOST_PP_CAT(call_ptr, n)

#define BOOST_LOCAL_FUNCTION_AUX_call_name(z, n, unused) \
    BOOST_PP_CAT(call, n)

#define BOOST_LOCAL_FUNCTION_AUX_call_member(z, n, unused) \
    BOOST_PP_CAT(BOOST_LOCAL_FUNCTION_AUX_call_name(z, n, unused), _)

#define BOOST_LOCAL_FUNCTION_AUX_call_typedef(z, n, arity) \
    typedef R (*BOOST_LOCAL_FUNCTION_AUX_call_ptr(z, n, ~))( \
        object_ptr \
        BOOST_PP_IIF(BOOST_LOCAL_FUNCTION_CONFIG_LOCALS_AS_TPARAMS, \
            BOOST_PP_TUPLE_EAT(3) \
        , \
            BOOST_PP_REPEAT_ ## z \
        )(BOOST_LOCAL_FUNCTION_CONFIG_BIND_MAX, \
                BOOST_LOCAL_FUNCTION_AUX_comma_bind_ref, ~) \
        BOOST_PP_REPEAT_ ## z(BOOST_PP_SUB(arity, n), \
                BOOST_LOCAL_FUNCTION_AUX_arg_param_type, 1 /* leading comma */)\
    );

#define BOOST_LOCAL_FUNCTION_AUX_comma_call_param_decl(z, n, unused) \
    , \
    BOOST_LOCAL_FUNCTION_AUX_call_ptr(z, n, ~) \
    BOOST_LOCAL_FUNCTION_AUX_call_name(z, n, ~)

#define BOOST_LOCAL_FUNCTION_AUX_call_decl(z, n, unused) \
    BOOST_LOCAL_FUNCTION_AUX_call_ptr(z, n, ~) \
    BOOST_LOCAL_FUNCTION_AUX_call_member(z, n, ~);

#define BOOST_LOCAL_FUNCTION_AUX_call_init(z, n, unused) \
    BOOST_LOCAL_FUNCTION_AUX_call_member(z, n, ~) = \
            BOOST_LOCAL_FUNCTION_AUX_call_name(z, n, ~);
                
#define BOOST_LOCAL_FUNCTION_AUX_operator_call(z, defaults_n, arity) \
    /* precondition: object_ && call_function_ */ \
    inline R operator()( \
        BOOST_PP_ENUM_ ## z(BOOST_PP_SUB(arity, defaults_n), \
                BOOST_LOCAL_FUNCTION_AUX_arg_param_decl, ~) \
    ) /* cannot be const because of binds (same as for local ftor) */ { \
        /* run-time: do not assert preconditions here for efficiency */ \
        /* run-time: this function call is done via a function pointer */ \
        /* so unfortunately does not allow for compiler inlining */ \
        /* optimizations (an alternative using virtual function was also */ \
        /* investigated but also virtual functions cannot be optimized */ \
        /* plus they require virtual table lookups to the alternative */ \
        /* performed worst) */ \
        return BOOST_LOCAL_FUNCTION_AUX_call_member(z, defaults_n, ~)( \
            object_ \
            BOOST_PP_IIF( \
                    BOOST_LOCAL_FUNCTION_CONFIG_LOCALS_AS_TPARAMS,\
                BOOST_PP_TUPLE_EAT(3) \
            , \
                BOOST_PP_REPEAT_ ## z \
            )(BOOST_LOCAL_FUNCTION_CONFIG_BIND_MAX, \
                    BOOST_LOCAL_FUNCTION_AUX_comma_bind_member_deref, ~) \
            BOOST_PP_REPEAT_ ## z(BOOST_PP_SUB(arity, defaults_n), \
                    BOOST_LOCAL_FUNCTION_AUX_arg_name, 1 /* leading comma */) \
        ); \
    }

namespace boost { namespace local_function { namespace aux {

template<
      typename F
    , size_t defaults
#if !BOOST_LOCAL_FUNCTION_CONFIG_LOCALS_AS_TPARAMS
    BOOST_PP_REPEAT(BOOST_LOCAL_FUNCTION_CONFIG_BIND_MAX,
            BOOST_LOCAL_FUNCTION_AUX_comma_bind_tparam, ~)
#endif
>
class function {}; // Empty template, only use its specializations.

// Iterate within namespace.
#       define BOOST_PP_ITERATION_PARAMS_1 \
                (3, (0, BOOST_LOCAL_FUNCTION_CONFIG_FUNCTION_ARITY_MAX, \
                BOOST_LOCAL_FUNCTION_AUX_FUNCTION_THIS_FILE_))
#       include BOOST_PP_ITERATE() // Iterate over function arity.

} } } // namespace

// Register type for type-of emu (NAME use TYPEOF to deduce this fctor type).
#include BOOST_TYPEOF_INCREMENT_REGISTRATION_GROUP()
BOOST_TYPEOF_REGISTER_TEMPLATE(boost::local_function::aux::function,
    (typename) // For `F` tparam.
    (size_t) // For `defaults` tparam.
    // MSVC error if using #if instead of PP_IIF here.
    BOOST_PP_IIF(BOOST_LOCAL_FUNCTION_CONFIG_LOCALS_AS_TPARAMS,
        BOOST_PP_TUPLE_EAT(3) // Nothing.
    ,
        BOOST_PP_REPEAT // For bind tparams.
    )(BOOST_LOCAL_FUNCTION_CONFIG_BIND_MAX,
            BOOST_LOCAL_FUNCTION_AUX_typename_seq, ~)
)

#undef BOOST_LOCAL_FUNCTION_AUX_typename_seq
#undef BOOST_LOCAL_FUNCTION_AUX_arg_type
#undef BOOST_LOCAL_FUNCTION_AUX_arg_typedef
#undef BOOST_LOCAL_FUNCTION_AUX_comma_arg_tparam
#undef BOOST_LOCAL_FUNCTION_AUX_arg_param_type
#undef BOOST_LOCAL_FUNCTION_AUX_arg_name
#undef BOOST_LOCAL_FUNCTION_AUX_arg_param_decl
#undef BOOST_LOCAL_FUNCTION_AUX_bind_type
#undef BOOST_LOCAL_FUNCTION_AUX_comma_bind_type
#undef BOOST_LOCAL_FUNCTION_AUX_comma_bind_ref
#undef BOOST_LOCAL_FUNCTION_AUX_comma_bind_tparam
#undef BOOST_LOCAL_FUNCTION_AUX_bind_name
#undef BOOST_LOCAL_FUNCTION_AUX_comma_bind_param_decl
#undef BOOST_LOCAL_FUNCTION_AUX_bind_member
#undef BOOST_LOCAL_FUNCTION_AUX_comma_bind_member_deref
#undef BOOST_LOCAL_FUNCTION_AUX_bind_member_init
#undef BOOST_LOCAL_FUNCTION_AUX_bind_member_decl
#undef BOOST_LOCAL_FUNCTION_AUX_call_ptr
#undef BOOST_LOCAL_FUNCTION_AUX_call_name
#undef BOOST_LOCAL_FUNCTION_AUX_call_member
#undef BOOST_LOCAL_FUNCTION_AUX_call_typedef
#undef BOOST_LOCAL_FUNCTION_AUX_comma_call_param_decl
#undef BOOST_LOCAL_FUNCTION_AUX_call_decl
#undef BOOST_LOCAL_FUNCTION_AUX_call_init
#undef BOOST_LOCAL_FUNCTION_AUX_operator_call

#   endif // #include guard

#elif BOOST_PP_ITERATION_DEPTH() == 1
#   define BOOST_LOCAL_FUNCTION_AUX_arity BOOST_PP_FRAME_ITERATION(1)
#   define BOOST_PP_ITERATION_PARAMS_2 \
            (3, (0, BOOST_LOCAL_FUNCTION_AUX_arity, \
            BOOST_LOCAL_FUNCTION_AUX_FUNCTION_THIS_FILE_))
#   include BOOST_PP_ITERATE() // Iterate over default params count.
#   undef BOOST_LOCAL_FUNCTION_AUX_arity

#elif BOOST_PP_ITERATION_DEPTH() == 2
#   define BOOST_LOCAL_FUNCTION_AUX_defaults BOOST_PP_FRAME_ITERATION(2)

template<
    typename R
    BOOST_PP_REPEAT(BOOST_LOCAL_FUNCTION_AUX_arity,
            BOOST_LOCAL_FUNCTION_AUX_comma_arg_tparam, ~)
#if !BOOST_LOCAL_FUNCTION_CONFIG_LOCALS_AS_TPARAMS
    BOOST_PP_REPEAT(BOOST_LOCAL_FUNCTION_CONFIG_BIND_MAX,
            BOOST_LOCAL_FUNCTION_AUX_comma_bind_tparam, ~)
#endif
>
class function<
      R (
        BOOST_PP_ENUM(BOOST_LOCAL_FUNCTION_AUX_arity,
                BOOST_LOCAL_FUNCTION_AUX_arg_type, ~)
      )
    , BOOST_LOCAL_FUNCTION_AUX_defaults
#if !BOOST_LOCAL_FUNCTION_CONFIG_LOCALS_AS_TPARAMS
    BOOST_PP_REPEAT(BOOST_LOCAL_FUNCTION_CONFIG_BIND_MAX,
            BOOST_LOCAL_FUNCTION_AUX_comma_bind_type, ~)
#endif
> {
    // The object type will actually be a local class which cannot be passed as
    // a template parameter so a generic `void*` pointer is used to hold the
    // object (this pointer will then be cased by the call-function implemented
    // by the local class itself). This is the trick used to pass a local
    // function as a template parameter. This trick uses function pointers for
    // the call-functions and function pointers cannot always be optimized by
    // the compiler (they cannot be inlined) thus this trick increased run-time
    // (another trick using virtual functions for the local class was also
    // investigated but also virtual functions cannot be inlined plus they
    // require virtual tables lookups so the virtual functions trick measured
    // worst run-time performance than the function pointer trick).
    typedef void* object_ptr;
    BOOST_PP_REPEAT(BOOST_PP_INC(BOOST_LOCAL_FUNCTION_AUX_defaults),
            BOOST_LOCAL_FUNCTION_AUX_call_typedef, // INC for no defaults.
            BOOST_LOCAL_FUNCTION_AUX_arity)

public:
    // Provide public type interface following Boost.Function names
    // (traits must be defined in both this and the local functor).
    BOOST_STATIC_CONSTANT(size_t, arity = BOOST_LOCAL_FUNCTION_AUX_arity);
    typedef R result_type;
    BOOST_PP_REPEAT(BOOST_LOCAL_FUNCTION_AUX_arity,
            BOOST_LOCAL_FUNCTION_AUX_arg_typedef, ~)

    // NOTE: Must have default constructor for init without function name in
    // function macro expansion.

    // Cannot be private but it should never be used by programmers directly
    // so used internal symbol.
    inline void BOOST_LOCAL_FUNCTION_AUX_FUNCTION_INIT_CALL_FUNC(
        object_ptr object
#if !BOOST_LOCAL_FUNCTION_CONFIG_LOCALS_AS_TPARAMS
        BOOST_PP_REPEAT(BOOST_LOCAL_FUNCTION_CONFIG_BIND_MAX,
                BOOST_LOCAL_FUNCTION_AUX_comma_bind_param_decl, ~)
#endif
        BOOST_PP_REPEAT(BOOST_PP_INC(BOOST_LOCAL_FUNCTION_AUX_defaults),
                BOOST_LOCAL_FUNCTION_AUX_comma_call_param_decl, ~)
    ) {
        object_ = object;
#if !BOOST_LOCAL_FUNCTION_CONFIG_LOCALS_AS_TPARAMS
        BOOST_PP_REPEAT(BOOST_LOCAL_FUNCTION_CONFIG_BIND_MAX,
                BOOST_LOCAL_FUNCTION_AUX_bind_member_init, ~)
#endif
        BOOST_PP_REPEAT(BOOST_PP_INC(BOOST_LOCAL_FUNCTION_AUX_defaults),
                BOOST_LOCAL_FUNCTION_AUX_call_init, ~) // INC for no defaults.
        unused_ = 0; // To avoid a GCC uninitialized warning.
    }
    
    // Result operator(Arg1, ..., ArgN-1, ArgN) -- iff defaults >= 0
    // Result operator(Arg1, ..., ArgN-1)       -- iff defaults >= 1
    // ...                                      -- etc
    BOOST_PP_REPEAT(BOOST_PP_INC(BOOST_LOCAL_FUNCTION_AUX_defaults),
            BOOST_LOCAL_FUNCTION_AUX_operator_call, // INC for no defaults.
            BOOST_LOCAL_FUNCTION_AUX_arity)

private:
    object_ptr object_;
#if !BOOST_LOCAL_FUNCTION_CONFIG_LOCALS_AS_TPARAMS
    BOOST_PP_REPEAT(BOOST_LOCAL_FUNCTION_CONFIG_BIND_MAX,
            BOOST_LOCAL_FUNCTION_AUX_bind_member_decl, ~)
#endif
    BOOST_PP_REPEAT(BOOST_PP_INC(BOOST_LOCAL_FUNCTION_AUX_defaults),
            BOOST_LOCAL_FUNCTION_AUX_call_decl, ~) // INC for no defaults.

    // run-time: this unused void* member variable allows for compiler
    // optimizations (at least on MSVC it reduces invocation time of about 50%)
    void* unused_;
};

#   undef BOOST_LOCAL_FUNCTION_AUX_defaults
#endif // iteration