085beb7edaeaba211aa103dd721b0c37c322b018
[platform/upstream/boost.git] / boost / fusion / functional / invocation / invoke.hpp
1 /*=============================================================================
2     Copyright (c) 2005-2006 Joao Abecasis
3     Copyright (c) 2006-2007 Tobias Schwinger
4
5     Use modification and distribution are subject to the Boost Software
6     License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
7     http://www.boost.org/LICENSE_1_0.txt).
8 ==============================================================================*/
9
10 #if !defined(BOOST_FUSION_FUNCTIONAL_INVOCATION_INVOKE_HPP_INCLUDED)
11 #if !defined(BOOST_PP_IS_ITERATING)
12
13 #include <boost/preprocessor/cat.hpp>
14 #include <boost/preprocessor/iteration/iterate.hpp>
15 #include <boost/preprocessor/arithmetic/dec.hpp>
16 #include <boost/preprocessor/repetition/repeat_from_to.hpp>
17 #include <boost/preprocessor/repetition/enum.hpp>
18 #include <boost/preprocessor/repetition/enum_shifted.hpp>
19 #include <boost/preprocessor/repetition/enum_params.hpp>
20 #include <boost/preprocessor/repetition/enum_shifted_params.hpp>
21
22 #include <boost/mpl/if.hpp>
23 #include <boost/mpl/eval_if.hpp>
24 #include <boost/mpl/or.hpp>
25 #include <boost/mpl/front.hpp>
26 #include <boost/mpl/identity.hpp>
27
28 #include <boost/type_traits/add_const.hpp>
29 #include <boost/type_traits/remove_cv.hpp>
30 #include <boost/type_traits/add_reference.hpp>
31 #include <boost/type_traits/remove_reference.hpp>
32 #include <boost/type_traits/is_convertible.hpp>
33
34 #include <boost/function_types/is_function.hpp>
35 #include <boost/function_types/is_callable_builtin.hpp>
36 #include <boost/function_types/is_member_pointer.hpp>
37 #include <boost/function_types/is_member_function_pointer.hpp>
38 #include <boost/function_types/result_type.hpp>
39 #include <boost/function_types/parameter_types.hpp>
40
41 #include <boost/utility/result_of.hpp>
42
43 #include <boost/fusion/support/category_of.hpp>
44 #include <boost/fusion/sequence/intrinsic/at.hpp>
45 #include <boost/fusion/sequence/intrinsic/size.hpp>
46 #include <boost/fusion/sequence/intrinsic/front.hpp>
47 #include <boost/fusion/sequence/intrinsic/begin.hpp>
48 #include <boost/fusion/iterator/next.hpp>
49 #include <boost/fusion/iterator/deref.hpp>
50 #include <boost/fusion/functional/invocation/limits.hpp>
51 #include <boost/fusion/functional/invocation/detail/that_ptr.hpp>
52
53 namespace boost { namespace fusion
54 {
55     namespace result_of
56     {
57         template <typename Function, class Sequence> struct invoke;
58     }
59
60     template <typename Function, class Sequence>
61     inline typename result_of::invoke<Function, Sequence>::type
62     invoke(Function, Sequence &);
63
64     template <typename Function, class Sequence>
65     inline typename result_of::invoke<Function, Sequence const>::type
66     invoke(Function, Sequence const &);
67
68     //----- ---- --- -- - -  -   -
69
70     namespace detail
71     {
72         namespace ft = function_types;
73
74         template<
75             typename Function, class Sequence,
76             int N = result_of::size<Sequence>::value,
77             bool CBI = ft::is_callable_builtin<Function>::value,
78             bool RandomAccess = traits::is_random_access<Sequence>::value
79             >
80         struct invoke_impl;
81
82         template <class Sequence, int N>
83         struct invoke_param_types;
84
85         template <typename T, class Sequence>
86         struct invoke_data_member;
87
88         template <typename Function, class Sequence, int N, bool RandomAccess>
89         struct invoke_mem_fn;
90
91         #define  BOOST_PP_FILENAME_1 <boost/fusion/functional/invocation/invoke.hpp>
92         #define  BOOST_PP_ITERATION_LIMITS (0, BOOST_FUSION_INVOKE_MAX_ARITY)
93         #include BOOST_PP_ITERATE()
94
95         template <typename F, class Sequence, int N, bool RandomAccess>
96         struct invoke_nonmember_builtin
97         // use same implementation as for function objects but...
98             : invoke_impl< // ...work around boost::result_of bugs
99                 typename mpl::eval_if< ft::is_function<F>,
100                     boost::add_reference<F>, boost::remove_cv<F> >::type,
101                 Sequence, N, false, RandomAccess >
102         { };
103
104         template <typename Function, class Sequence, int N, bool RandomAccess>
105         struct invoke_impl<Function,Sequence,N,true,RandomAccess>
106             : mpl::if_< ft::is_member_function_pointer<Function>,
107                 invoke_mem_fn<Function,Sequence,N,RandomAccess>,
108                 invoke_nonmember_builtin<Function,Sequence,N,RandomAccess>
109             >::type
110         { };
111
112         template <typename Function, class Sequence, bool RandomAccess>
113         struct invoke_impl<Function,Sequence,1,true,RandomAccess>
114             : mpl::eval_if< ft::is_member_pointer<Function>,
115                 mpl::if_< ft::is_member_function_pointer<Function>,
116                     invoke_mem_fn<Function,Sequence,1,RandomAccess>,
117                     invoke_data_member<Function, Sequence> >,
118                 mpl::identity< invoke_nonmember_builtin<
119                     Function,Sequence,1,RandomAccess> >
120             >::type
121         { };
122
123         template <typename T, class C, class Sequence>
124         struct invoke_data_member< T C::*, Sequence >
125         {
126         private:
127
128             typedef typename result_of::front<Sequence>::type that;
129
130             typedef mpl::or_< boost::is_convertible<that,C*>,
131                               boost::is_convertible<that,C&>,
132                               non_const_pointee<that> > non_const_cond;
133
134             typedef typename mpl::eval_if< non_const_cond,
135                 mpl::identity<C>, add_const<C> >::type qualified_class;
136
137             typedef typename mpl::eval_if< non_const_cond,
138                 mpl::identity<T>, add_const<T> >::type qualified_type;
139
140         public:
141
142             typedef typename boost::add_reference<qualified_type>::type
143                 result_type;
144
145             static inline result_type call(T C::* f, Sequence & s)
146             {
147                 typename result_of::front<Sequence>::type c = fusion::front(s);
148                 return that_ptr<qualified_class>::get(c)->*f;
149             }
150         };
151     }
152
153     namespace result_of
154     {
155         template <typename Function, class Sequence> struct invoke
156         {
157             typedef typename detail::invoke_impl<
158                 typename boost::remove_reference<Function>::type, Sequence
159               >::result_type type;
160         };
161     }
162
163     template <typename Function, class Sequence>
164     inline typename result_of::invoke<Function,Sequence>::type
165     invoke(Function f, Sequence & s)
166     {
167         return detail::invoke_impl<
168                 typename boost::remove_reference<Function>::type,Sequence
169             >::call(f,s);
170     }
171
172     template <typename Function, class Sequence>
173     inline typename result_of::invoke<Function,Sequence const>::type
174     invoke(Function f, Sequence const & s)
175     {
176         return detail::invoke_impl<
177                 typename boost::remove_reference<Function>::type,Sequence const
178             >::call(f,s);
179     }
180
181 }}
182
183 #define BOOST_FUSION_FUNCTIONAL_INVOCATION_INVOKE_HPP_INCLUDED
184 #else // defined(BOOST_PP_IS_ITERATING)
185 ///////////////////////////////////////////////////////////////////////////////
186 //
187 //  Preprocessor vertical repetition code
188 //
189 ///////////////////////////////////////////////////////////////////////////////
190 #define N BOOST_PP_ITERATION()
191
192         template <typename Function, class Sequence>
193         struct invoke_impl<Function,Sequence,N,false,true>
194         {
195         public:
196
197             typedef typename boost::result_of<
198 #define M(z,j,data) typename result_of::at_c<Sequence,j>::type
199                     Function(BOOST_PP_ENUM(N,M,~)) >::type result_type;
200 #undef M
201
202 #if N > 0
203
204             template <typename F>
205             static inline result_type
206             call(F & f, Sequence & s)
207             {
208 #define M(z,j,data) fusion::at_c<j>(s)
209                 return f( BOOST_PP_ENUM(N,M,~) );
210             }
211
212 #else
213             template <typename F>
214             static inline result_type
215             call(F & f, Sequence & /*s*/)
216             {
217                 return f();
218             }
219
220 #endif
221
222         };
223
224
225 #if N > 0
226         template <typename Function, class Sequence>
227         struct invoke_mem_fn<Function,Sequence,N,true>
228         {
229         public:
230
231             typedef typename ft::result_type<Function>::type result_type;
232
233             template <typename F>
234             static inline result_type
235             call(F & f, Sequence & s)
236             {
237                 return (that_ptr<typename mpl::front<
238                                 ft::parameter_types<Function> >::type
239                     >::get(fusion::at_c<0>(s))->*f)(BOOST_PP_ENUM_SHIFTED(N,M,~));
240             }
241         };
242 #endif
243
244 #undef M
245
246 #define M(z,j,data)                                                             \
247             typename seq::I##j i##j =                                          \
248                 fusion::next(BOOST_PP_CAT(i,BOOST_PP_DEC(j)));
249
250         template <typename Function, class Sequence>
251         struct invoke_impl<Function,Sequence,N,false,false>
252         {
253         private:
254             typedef invoke_param_types<Sequence,N> seq;
255         public:
256
257             typedef typename boost::result_of<
258                 Function(BOOST_PP_ENUM_PARAMS(N,typename seq::T))
259                 >::type result_type;
260
261 #if N > 0
262
263             template <typename F>
264             static inline result_type
265             call(F & f, Sequence & s)
266             {
267                 typename seq::I0 i0 = fusion::begin(s);
268                 BOOST_PP_REPEAT_FROM_TO(1,N,M,~)
269                 return f( BOOST_PP_ENUM_PARAMS(N,*i) );
270             }
271
272 #else
273
274             template <typename F>
275             static inline result_type
276             call(F & f, Sequence & /*s*/)
277             {
278                 return f();
279             }
280
281 #endif
282
283         };
284
285 #if N > 0
286         template <typename Function, class Sequence>
287         struct invoke_mem_fn<Function,Sequence,N,false>
288         {
289         private:
290             typedef invoke_param_types<Sequence,N> seq;
291         public:
292
293             typedef typename ft::result_type<Function>::type result_type;
294
295             template <typename F>
296             static inline result_type
297             call(F & f, Sequence & s)
298             {
299                 typename seq::I0 i0 = fusion::begin(s);
300                 BOOST_PP_REPEAT_FROM_TO(1,N,M,~)
301
302                 return (that_ptr< typename mpl::front<
303                                       ft::parameter_types<Function> >::type
304                     >::get(*i0)->*f)(BOOST_PP_ENUM_SHIFTED_PARAMS(N,*i));
305             }
306         };
307 #endif
308
309 #undef M
310
311         template <class Sequence> struct invoke_param_types<Sequence,N>
312         {
313 #if N > 0
314             typedef typename result_of::begin<Sequence>::type I0;
315             typedef typename result_of::deref<I0>::type T0;
316
317 #define M(z,i,data)                                                             \
318             typedef typename result_of::next<                                  \
319                 BOOST_PP_CAT(I,BOOST_PP_DEC(i))>::type I##i;                   \
320             typedef typename result_of::deref<I##i>::type T##i;
321
322             BOOST_PP_REPEAT_FROM_TO(1,N,M,~)
323 #undef M
324 #endif
325         };
326
327
328 #undef N
329 #endif // defined(BOOST_PP_IS_ITERATING)
330 #endif
331