]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | /////////////////////////////////////////////////////////////////////////////// |
2 | /// \file callable.hpp | |
3 | /// Definintion of callable_context\<\>, an evaluation context for | |
4 | /// proto::eval() that explodes each node and calls the derived context | |
5 | /// type with the expressions constituents. If the derived context doesn't | |
6 | /// have an overload that handles this node, fall back to some other | |
7 | /// context. | |
8 | // | |
9 | // Copyright 2008 Eric Niebler. Distributed under the Boost | |
10 | // Software License, Version 1.0. (See accompanying file | |
11 | // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | |
12 | ||
13 | #ifndef BOOST_PROTO_CONTEXT_CALLABLE_HPP_EAN_06_23_2007 | |
14 | #define BOOST_PROTO_CONTEXT_CALLABLE_HPP_EAN_06_23_2007 | |
15 | ||
16 | #include <boost/config.hpp> | |
17 | #include <boost/detail/workaround.hpp> | |
18 | #include <boost/preprocessor/cat.hpp> | |
19 | #include <boost/preprocessor/iteration/iterate.hpp> | |
20 | #include <boost/preprocessor/facilities/intercept.hpp> | |
21 | #include <boost/preprocessor/repetition/repeat.hpp> | |
22 | #include <boost/preprocessor/repetition/enum_params.hpp> | |
23 | #include <boost/preprocessor/repetition/enum_trailing.hpp> | |
24 | #include <boost/preprocessor/repetition/enum_trailing_params.hpp> | |
25 | #include <boost/preprocessor/arithmetic/inc.hpp> | |
26 | #include <boost/preprocessor/selection/max.hpp> | |
27 | #include <boost/mpl/if.hpp> | |
28 | #include <boost/mpl/bool.hpp> | |
29 | #include <boost/utility/result_of.hpp> | |
30 | #include <boost/type_traits/remove_cv.hpp> | |
31 | #include <boost/proto/proto_fwd.hpp> | |
32 | #include <boost/proto/traits.hpp> // for child_c | |
33 | ||
34 | namespace boost { namespace proto | |
35 | { | |
36 | namespace detail | |
37 | { | |
38 | template<typename Context> | |
39 | struct callable_context_wrapper | |
40 | : remove_cv<Context>::type | |
41 | { | |
42 | callable_context_wrapper(); | |
43 | typedef private_type_ fun_type(...); | |
44 | operator fun_type *() const; | |
45 | private: | |
46 | callable_context_wrapper &operator =(callable_context_wrapper const &); | |
47 | }; | |
48 | ||
49 | template<typename T> | |
50 | yes_type check_is_expr_handled(T const &); | |
51 | ||
52 | no_type check_is_expr_handled(private_type_ const &); | |
53 | ||
54 | template<typename Expr, typename Context, long Arity = Expr::proto_arity_c> | |
55 | struct is_expr_handled; | |
56 | ||
57 | template<typename Expr, typename Context> | |
58 | struct is_expr_handled<Expr, Context, 0> | |
59 | { | |
60 | static callable_context_wrapper<Context> &sctx_; | |
61 | static Expr &sexpr_; | |
62 | static typename Expr::proto_tag &stag_; | |
63 | ||
64 | static const bool value = | |
65 | sizeof(yes_type) == | |
66 | sizeof( | |
67 | detail::check_is_expr_handled( | |
68 | (sctx_(stag_, proto::value(sexpr_)), 0) | |
69 | ) | |
70 | ); | |
71 | ||
72 | typedef mpl::bool_<value> type; | |
73 | }; | |
74 | } | |
75 | ||
76 | namespace context | |
77 | { | |
78 | /// \brief A BinaryFunction that accepts a Proto expression and a | |
79 | /// callable context and calls the context with the expression tag | |
80 | /// and children as arguments, effectively fanning the expression | |
81 | /// out. | |
82 | /// | |
83 | /// <tt>callable_eval\<\></tt> requires that \c Context is a | |
84 | /// PolymorphicFunctionObject that can be invoked with \c Expr's | |
85 | /// tag and children as expressions, as follows: | |
86 | /// | |
87 | /// \code | |
88 | /// context(Expr::proto_tag(), child_c<0>(expr), child_c<1>(expr), ...) | |
89 | /// \endcode | |
90 | template< | |
91 | typename Expr | |
92 | , typename Context | |
93 | , long Arity // = Expr::proto_arity_c | |
94 | > | |
95 | struct callable_eval | |
96 | {}; | |
97 | ||
98 | /// \brief A BinaryFunction that accepts a Proto expression and a | |
99 | /// callable context and calls the context with the expression tag | |
100 | /// and children as arguments, effectively fanning the expression | |
101 | /// out. | |
102 | /// | |
103 | /// <tt>callable_eval\<\></tt> requires that \c Context is a | |
104 | /// PolymorphicFunctionObject that can be invoked with \c Expr's | |
105 | /// tag and children as expressions, as follows: | |
106 | /// | |
107 | /// \code | |
108 | /// context(Expr::proto_tag(), value(expr)) | |
109 | /// \endcode | |
110 | template<typename Expr, typename Context> | |
111 | struct callable_eval<Expr, Context, 0> | |
112 | { | |
113 | typedef typename proto::result_of::value<Expr const &>::type value_type; | |
114 | ||
115 | typedef | |
116 | typename BOOST_PROTO_RESULT_OF< | |
117 | Context(typename Expr::proto_tag, value_type) | |
118 | >::type | |
119 | result_type; | |
120 | ||
121 | /// \param expr The current expression | |
122 | /// \param context The callable evaluation context | |
123 | /// \return <tt>context(Expr::proto_tag(), value(expr))</tt> | |
124 | result_type operator ()(Expr &expr, Context &context) const | |
125 | { | |
126 | return context(typename Expr::proto_tag(), proto::value(expr)); | |
127 | } | |
128 | }; | |
129 | ||
130 | /// \brief An evaluation context adaptor that makes authoring a | |
131 | /// context a simple matter of writing function overloads, rather | |
132 | /// then writing template specializations. | |
133 | /// | |
134 | /// <tt>callable_context\<\></tt> is a base class that implements | |
135 | /// the context protocol by passing fanned-out expression nodes to | |
136 | /// the derived context, making it easy to customize the handling | |
137 | /// of expression types by writing function overloads. Only those | |
138 | /// expression types needing special handling require explicit | |
139 | /// handling. All others are dispatched to a user-specified | |
140 | /// default context, \c DefaultCtx. | |
141 | /// | |
142 | /// <tt>callable_context\<\></tt> is defined simply as: | |
143 | /// | |
144 | /// \code | |
145 | /// template<typename Context, typename DefaultCtx = default_context> | |
146 | /// struct callable_context | |
147 | /// { | |
148 | /// template<typename Expr, typename ThisContext = Context> | |
149 | /// struct eval | |
150 | /// : mpl::if_< | |
151 | /// is_expr_handled_<Expr, Context> // For exposition | |
152 | /// , callable_eval<Expr, ThisContext> | |
153 | /// , typename DefaultCtx::template eval<Expr, Context> | |
154 | /// >::type | |
155 | /// {}; | |
156 | /// }; | |
157 | /// \endcode | |
158 | /// | |
159 | /// The Boolean metafunction <tt>is_expr_handled_\<\></tt> uses | |
160 | /// metaprogramming tricks to determine whether \c Context has | |
161 | /// an overloaded function call operator that accepts the | |
162 | /// fanned-out constituents of an expression of type \c Expr. | |
163 | /// If so, the handling of the expression is dispatched to | |
164 | /// <tt>callable_eval\<\></tt>. If not, it is dispatched to | |
165 | /// the user-specified \c DefaultCtx. | |
166 | /// | |
167 | /// Below is an example of how to use <tt>callable_context\<\></tt>: | |
168 | /// | |
169 | /// \code | |
170 | /// // An evaluation context that increments all | |
171 | /// // integer terminals in-place. | |
172 | /// struct increment_ints | |
173 | /// : callable_context< | |
174 | /// increment_ints const // derived context | |
175 | /// , null_context const // fall-back context | |
176 | /// > | |
177 | /// { | |
178 | /// typedef void result_type; | |
179 | /// | |
180 | /// // Handle int terminals here: | |
181 | /// void operator()(proto::tag::terminal, int &i) const | |
182 | /// { | |
183 | /// ++i; | |
184 | /// } | |
185 | /// }; | |
186 | /// \endcode | |
187 | /// | |
188 | /// With \c increment_ints, we can do the following: | |
189 | /// | |
190 | /// \code | |
191 | /// literal<int> i = 0, j = 10; | |
192 | /// proto::eval( i - j * 3.14, increment_ints() ); | |
193 | /// | |
194 | /// assert( i.get() == 1 && j.get() == 11 ); | |
195 | /// \endcode | |
196 | template< | |
197 | typename Context | |
198 | , typename DefaultCtx // = default_context | |
199 | > | |
200 | struct callable_context | |
201 | { | |
202 | /// A BinaryFunction that accepts an \c Expr and a | |
203 | /// \c Context, and either fans out the expression and passes | |
204 | /// it to the context, or else hands off the expression to | |
205 | /// \c DefaultCtx. | |
206 | /// | |
207 | /// If \c Context is a PolymorphicFunctionObject such that | |
208 | /// it can be invoked with the tag and children of \c Expr, | |
209 | /// as <tt>ctx(Expr::proto_tag(), child_c\<0\>(expr), child_c\<1\>(expr)...)</tt>, | |
210 | /// then <tt>eval\<Expr, ThisContext\></tt> inherits from | |
211 | /// <tt>callable_eval\<Expr, ThisContext\></tt>. Otherwise, | |
212 | /// <tt>eval\<Expr, ThisContext\></tt> inherits from | |
213 | /// <tt>DefaultCtx::eval\<Expr, Context\></tt>. | |
214 | template<typename Expr, typename ThisContext = Context> | |
215 | struct eval | |
216 | : mpl::if_c< | |
217 | detail::is_expr_handled<Expr, Context>::value | |
218 | , callable_eval<Expr, ThisContext> | |
219 | , typename DefaultCtx::template eval<Expr, Context> | |
220 | >::type | |
221 | {}; | |
222 | }; | |
223 | } | |
224 | ||
225 | #include <boost/proto/context/detail/callable_eval.hpp> | |
226 | ||
227 | }} | |
228 | ||
229 | #endif |