1 /*=============================================================================
2     Copyright (c) 2001-2011 Joel de Guzman
3     Copyright (c) 2001-2011 Hartmut Kaiser
4     http://spirit.sourceforge.net/
5 
6     Distributed under the Boost Software License, Version 1.0. (See accompanying
7     file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
8 =============================================================================*/
9 #if !defined(BOOST_SPIRIT_ACTION_DISPATCH_APRIL_18_2008_0720AM)
10 #define BOOST_SPIRIT_ACTION_DISPATCH_APRIL_18_2008_0720AM
11 
12 #if defined(_MSC_VER)
13 #pragma once
14 #endif
15 
16 #include<boost/config.hpp>
17 
18 #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && !defined(BOOST_NO_CXX11_LAMBDAS) && \
19     !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && !defined(BOOST_NO_CXX11_DECLTYPE)
20 #include <utility>
21 #include <type_traits>
22 #endif
23 
24 
25 #include <boost/spirit/home/support/attributes.hpp>
26 
27 namespace boost { namespace phoenix
28 {
29     template <typename Expr>
30     struct actor;
31 }}
32 
33 namespace boost { namespace spirit { namespace traits
34 {
35     template <typename Component>
36     struct action_dispatch
37     {
38 #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && !defined(BOOST_NO_CXX11_LAMBDAS) && \
39     !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && !defined(BOOST_NO_CXX11_DECLTYPE)
40         // omit function parameters without specializing for each possible
41         // type of callable entity
42         // many thanks to Eelis/##iso-c++ for this contribution
43 
44     private:
45         // this will be used to pass around POD types which are safe
46         // to go through the ellipsis operator (if ever used)
47         template <typename>
48         struct fwd_tag {};
49 
50         // the first parameter is a placeholder to obtain SFINAE when
51         // doing overload resolution, the second one is the actual
52         // forwarder, where we can apply our implementation
53         template <typename, typename T>
54         struct fwd_storage { typedef T type; };
55 
56         // gcc should accept fake<T>() but it prints a sorry, needs
57         // a check once the bug is sorted out, use a FAKE_CALL macro for now
58         template <typename T>
59         T fake_call();
60 
61 #define BOOST_SPIRIT_FAKE_CALL(T) (*(T*)0)
62 
63         // the forwarders, here we could tweak the implementation of
64         // how parameters are passed to the functions, if needed
65         struct fwd_none
66         {
67             template<typename F, typename... Rest>
operator ()boost::spirit::traits::action_dispatch::fwd_none68             auto operator()(F && f, Rest&&...) -> decltype(f())
69             {
70                 return f();
71             }
72         };
73 
74         struct fwd_attrib
75         {
76             template<typename F, typename A, typename... Rest>
operator ()boost::spirit::traits::action_dispatch::fwd_attrib77             auto operator()(F && f, A && a, Rest&&...) -> decltype(f(a))
78             {
79                  return f(a);
80             }
81         };
82 
83         struct fwd_attrib_context
84         {
85              template<typename F, typename A, typename B, typename... Rest>
operator ()boost::spirit::traits::action_dispatch::fwd_attrib_context86              auto operator()(F && f, A && a, B && b, Rest&&...)
87                 -> decltype(f(a, b))
88              {
89                  return f(a, b);
90              }
91         };
92 
93         struct fwd_attrib_context_pass
94         {
95             template<typename F, typename A, typename B, typename C
96               , typename... Rest>
operator ()boost::spirit::traits::action_dispatch::fwd_attrib_context_pass97             auto operator()(F && f, A && a, B && b, C && c, Rest&&...)
98                -> decltype(f(a, b, c))
99             {
100                 return f(a, b, c);
101             }
102         };
103 
104         // SFINAE for our calling syntax, the forwarders are stored based
105         // on what function call gives a proper result
106         // this code can probably be more generic once implementations are
107         // steady
108         template <typename F>
do_callboost::spirit::traits::action_dispatch109         static auto do_call(F && f, ...)
110            -> typename fwd_storage<decltype(f()), fwd_none>::type
111         {
112             return {};
113         }
114 
115         template <typename F, typename A>
do_callboost::spirit::traits::action_dispatch116         static auto do_call(F && f, fwd_tag<A>, ...)
117            -> typename fwd_storage<decltype(f(BOOST_SPIRIT_FAKE_CALL(A)))
118                  , fwd_attrib>::type
119         {
120             return {};
121         }
122 
123         template <typename F, typename A, typename B>
do_callboost::spirit::traits::action_dispatch124         static auto do_call(F && f, fwd_tag<A>, fwd_tag<B>, ...)
125            -> typename fwd_storage<
126                     decltype(f(BOOST_SPIRIT_FAKE_CALL(A), BOOST_SPIRIT_FAKE_CALL(B)))
127                 , fwd_attrib_context>::type
128         {
129             return {};
130         }
131 
132         template <typename F, typename A, typename B, typename C>
do_callboost::spirit::traits::action_dispatch133         static auto do_call(F && f, fwd_tag<A>, fwd_tag<B>, fwd_tag<C>, ...)
134            -> typename fwd_storage<
135                   decltype(f(BOOST_SPIRIT_FAKE_CALL(A), BOOST_SPIRIT_FAKE_CALL(B)
136                     , BOOST_SPIRIT_FAKE_CALL(C)))
137                 , fwd_attrib_context_pass>::type
138         {
139             return {};
140         }
141 
142         // this function calls the forwarder and is responsible for
143         // stripping the tail of the parameters
144         template <typename F, typename... A>
callerboost::spirit::traits::action_dispatch145         static void caller(F && f, A && ... a)
146         {
147             do_call(f, fwd_tag<typename std::remove_reference<A>::type>()...)
148                 (std::forward<F>(f), std::forward<A>(a)...);
149         }
150 
151 #undef BOOST_SPIRIT_FAKE_CALL
152 
153     public:
154         template <typename F, typename Attribute, typename Context>
operator ()boost::spirit::traits::action_dispatch155         bool operator()(F const& f, Attribute& attr, Context& context)
156         {
157             bool pass = true;
158             caller(f, attr, context, pass);
159             return pass;
160         }
161 #else
162         // general handler for everything not explicitly specialized below
163         template <typename F, typename Attribute, typename Context>
164         bool operator()(F const& f, Attribute& attr, Context& context)
165         {
166             bool pass = true;
167             f(attr, context, pass);
168             return pass;
169         }
170 #endif
171 
172         // handler for phoenix actors
173 
174         // If the component this action has to be invoked for is a tuple, we
175         // wrap any non-fusion tuple into a fusion tuple (done by pass_attribute)
176         // and pass through any fusion tuple.
177         template <typename Eval, typename Attribute, typename Context>
operator ()boost::spirit::traits::action_dispatch178         bool operator()(phoenix::actor<Eval> const& f
179           , Attribute& attr, Context& context)
180         {
181             bool pass = true;
182             typename pass_attribute<Component, Attribute>::type attr_wrap(attr);
183             f(attr_wrap, context, pass);
184             return pass;
185         }
186 
187         // specializations for plain function pointers taking different number of
188         // arguments
189         template <typename RT, typename A0, typename A1, typename A2
190           , typename Attribute, typename Context>
operator ()boost::spirit::traits::action_dispatch191         bool operator()(RT(*f)(A0, A1, A2), Attribute& attr, Context& context)
192         {
193             bool pass = true;
194             f(attr, context, pass);
195             return pass;
196         }
197 
198         template <typename RT, typename A0, typename A1
199           , typename Attribute, typename Context>
operator ()boost::spirit::traits::action_dispatch200         bool operator()(RT(*f)(A0, A1), Attribute& attr, Context& context)
201         {
202             f(attr, context);
203             return true;
204         }
205 
206         template <typename RT, typename A0, typename Attribute, typename Context>
operator ()boost::spirit::traits::action_dispatch207         bool operator()(RT(*f)(A0), Attribute& attr, Context&)
208         {
209             f(attr);
210             return true;
211         }
212 
213         template <typename RT, typename Attribute, typename Context>
operator ()boost::spirit::traits::action_dispatch214         bool operator()(RT(*f)(), Attribute&, Context&)
215         {
216             f();
217             return true;
218         }
219     };
220 }}}
221 
222 #endif
223