Chris@16
|
1 ///////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
2 /// \file domain.hpp
|
Chris@16
|
3 /// Contains definition of domain\<\> class template and helpers for
|
Chris@16
|
4 /// defining domains with a generator and a grammar for controlling
|
Chris@16
|
5 /// operator overloading.
|
Chris@16
|
6 //
|
Chris@16
|
7 // Copyright 2008 Eric Niebler. Distributed under the Boost
|
Chris@16
|
8 // Software License, Version 1.0. (See accompanying file
|
Chris@16
|
9 // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
Chris@16
|
10
|
Chris@16
|
11 #ifndef BOOST_PROTO_DOMAIN_HPP_EAN_02_13_2007
|
Chris@16
|
12 #define BOOST_PROTO_DOMAIN_HPP_EAN_02_13_2007
|
Chris@16
|
13
|
Chris@16
|
14 #include <boost/ref.hpp>
|
Chris@16
|
15 #include <boost/type_traits/is_same.hpp>
|
Chris@16
|
16 #include <boost/proto/proto_fwd.hpp>
|
Chris@16
|
17 #include <boost/proto/generate.hpp>
|
Chris@16
|
18 #include <boost/proto/detail/as_expr.hpp>
|
Chris@16
|
19 #include <boost/proto/detail/deduce_domain.hpp>
|
Chris@16
|
20
|
Chris@101
|
21 #if defined(_MSC_VER)
|
Chris@16
|
22 # pragma warning(push)
|
Chris@16
|
23 # pragma warning(disable : 4714) // function 'xxx' marked as __forceinline not inlined
|
Chris@16
|
24 #endif
|
Chris@16
|
25
|
Chris@16
|
26 namespace boost { namespace proto
|
Chris@16
|
27 {
|
Chris@16
|
28
|
Chris@16
|
29 namespace detail
|
Chris@16
|
30 {
|
Chris@16
|
31 struct not_a_generator
|
Chris@16
|
32 {};
|
Chris@16
|
33
|
Chris@16
|
34 struct not_a_grammar
|
Chris@16
|
35 {};
|
Chris@16
|
36
|
Chris@16
|
37 struct not_a_domain
|
Chris@16
|
38 {};
|
Chris@16
|
39 }
|
Chris@16
|
40
|
Chris@16
|
41 namespace domainns_
|
Chris@16
|
42 {
|
Chris@16
|
43 /// \brief For use in defining domain tags to be used
|
Chris@16
|
44 /// with \c proto::extends\<\>. A \e Domain associates
|
Chris@16
|
45 /// an expression type with a \e Generator, and optionally
|
Chris@16
|
46 /// a \e Grammar.
|
Chris@16
|
47 ///
|
Chris@16
|
48 /// The Generator determines how new expressions in the
|
Chris@16
|
49 /// domain are constructed. Typically, a generator wraps
|
Chris@16
|
50 /// all new expressions in a wrapper that imparts
|
Chris@16
|
51 /// domain-specific behaviors to expressions within its
|
Chris@16
|
52 /// domain. (See \c proto::extends\<\>.)
|
Chris@16
|
53 ///
|
Chris@16
|
54 /// The Grammar determines whether a given expression is
|
Chris@16
|
55 /// valid within the domain, and automatically disables
|
Chris@16
|
56 /// any operator overloads which would cause an invalid
|
Chris@16
|
57 /// expression to be created. By default, the Grammar
|
Chris@16
|
58 /// parameter defaults to the wildcard, \c proto::_, which
|
Chris@16
|
59 /// makes all expressions valid within the domain.
|
Chris@16
|
60 ///
|
Chris@16
|
61 /// The Super declares the domain currently being defined
|
Chris@16
|
62 /// to be a sub-domain of Super. Expressions in sub-domains
|
Chris@16
|
63 /// can be freely combined with expressions in its super-
|
Chris@16
|
64 /// domain (and <I>its</I> super-domain, etc.).
|
Chris@16
|
65 ///
|
Chris@16
|
66 /// Example:
|
Chris@16
|
67 /// \code
|
Chris@16
|
68 /// template<typename Expr>
|
Chris@16
|
69 /// struct MyExpr;
|
Chris@16
|
70 ///
|
Chris@16
|
71 /// struct MyGrammar
|
Chris@16
|
72 /// : or_< terminal<_>, plus<MyGrammar, MyGrammar> >
|
Chris@16
|
73 /// {};
|
Chris@16
|
74 ///
|
Chris@16
|
75 /// // Define MyDomain, in which all expressions are
|
Chris@16
|
76 /// // wrapped in MyExpr<> and only expressions that
|
Chris@16
|
77 /// // conform to MyGrammar are allowed.
|
Chris@16
|
78 /// struct MyDomain
|
Chris@16
|
79 /// : domain<generator<MyExpr>, MyGrammar>
|
Chris@16
|
80 /// {};
|
Chris@16
|
81 ///
|
Chris@16
|
82 /// // Use MyDomain to define MyExpr
|
Chris@16
|
83 /// template<typename Expr>
|
Chris@16
|
84 /// struct MyExpr
|
Chris@16
|
85 /// : extends<Expr, MyExpr<Expr>, MyDomain>
|
Chris@16
|
86 /// {
|
Chris@16
|
87 /// // ...
|
Chris@16
|
88 /// };
|
Chris@16
|
89 /// \endcode
|
Chris@16
|
90 ///
|
Chris@16
|
91 template<
|
Chris@16
|
92 typename Generator // = default_generator
|
Chris@16
|
93 , typename Grammar // = proto::_
|
Chris@16
|
94 , typename Super // = no_super_domain
|
Chris@16
|
95 >
|
Chris@16
|
96 struct domain
|
Chris@16
|
97 : Generator
|
Chris@16
|
98 {
|
Chris@16
|
99 typedef Generator proto_generator;
|
Chris@16
|
100 typedef Grammar proto_grammar;
|
Chris@16
|
101 typedef Super proto_super_domain;
|
Chris@16
|
102 typedef domain proto_base_domain;
|
Chris@16
|
103
|
Chris@16
|
104 /// INTERNAL ONLY
|
Chris@16
|
105 typedef void proto_is_domain_;
|
Chris@16
|
106
|
Chris@16
|
107 /// \brief A unary MonomorphicFunctionObject that turns objects into Proto
|
Chris@16
|
108 /// expression objects in this domain.
|
Chris@16
|
109 ///
|
Chris@16
|
110 /// The <tt>as_expr\<\></tt> function object turns objects into Proto expressions, if
|
Chris@16
|
111 /// they are not already, by making them Proto terminals held by value if
|
Chris@16
|
112 /// possible. Objects that are already Proto expressions are left alone.
|
Chris@16
|
113 ///
|
Chris@16
|
114 /// If <tt>wants_basic_expr\<Generator\>::value</tt> is true, then let \c E be \c basic_expr;
|
Chris@16
|
115 /// otherwise, let \t E be \c expr. Given an lvalue \c t of type \c T:
|
Chris@16
|
116 ///
|
Chris@16
|
117 /// If \c T is not a Proto expression type the resulting terminal is
|
Chris@16
|
118 /// calculated as follows:
|
Chris@16
|
119 ///
|
Chris@16
|
120 /// If \c T is a function type, an abstract type, or a type derived from
|
Chris@16
|
121 /// \c std::ios_base, let \c A be <tt>T &</tt>.
|
Chris@16
|
122 /// Otherwise, let \c A be the type \c T stripped of cv-qualifiers.
|
Chris@16
|
123 /// Then, the result of applying <tt>as_expr\<T\>()(t)</tt> is
|
Chris@16
|
124 /// <tt>Generator()(E\<tag::terminal, term\<A\> \>::make(t))</tt>.
|
Chris@16
|
125 ///
|
Chris@16
|
126 /// If \c T is a Proto expression type and its generator type is different from
|
Chris@16
|
127 /// \c Generator, the result is <tt>Generator()(t)</tt>.
|
Chris@16
|
128 ///
|
Chris@16
|
129 /// Otherwise, the result is \c t converted to an (un-const) rvalue.
|
Chris@16
|
130 ///
|
Chris@16
|
131 template<typename T, typename IsExpr = void, typename Callable = proto::callable>
|
Chris@16
|
132 struct as_expr
|
Chris@16
|
133 : detail::as_expr<
|
Chris@16
|
134 T
|
Chris@16
|
135 , typename detail::base_generator<Generator>::type
|
Chris@16
|
136 , wants_basic_expr<Generator>::value
|
Chris@16
|
137 >
|
Chris@16
|
138 {
|
Chris@16
|
139 BOOST_PROTO_CALLABLE()
|
Chris@16
|
140 };
|
Chris@16
|
141
|
Chris@16
|
142 /// INTERNAL ONLY
|
Chris@16
|
143 ///
|
Chris@16
|
144 template<typename T>
|
Chris@16
|
145 struct as_expr<T, typename T::proto_is_expr_, proto::callable>
|
Chris@16
|
146 {
|
Chris@16
|
147 BOOST_PROTO_CALLABLE()
|
Chris@16
|
148 typedef typename remove_const<T>::type result_type;
|
Chris@16
|
149
|
Chris@16
|
150 BOOST_FORCEINLINE
|
Chris@16
|
151 result_type operator()(T &e) const
|
Chris@16
|
152 {
|
Chris@16
|
153 return e;
|
Chris@16
|
154 }
|
Chris@16
|
155 };
|
Chris@16
|
156
|
Chris@16
|
157 /// \brief A unary MonomorphicFunctionObject that turns objects into Proto
|
Chris@16
|
158 /// expression objects in this domain.
|
Chris@16
|
159 ///
|
Chris@16
|
160 /// The <tt>as_child\<\></tt> function object turns objects into Proto expressions, if
|
Chris@16
|
161 /// they are not already, by making them Proto terminals held by reference.
|
Chris@16
|
162 /// Objects that are already Proto expressions are simply returned by reference.
|
Chris@16
|
163 ///
|
Chris@16
|
164 /// If <tt>wants_basic_expr\<Generator\>::value</tt> is true, then let \c E be \c basic_expr;
|
Chris@16
|
165 /// otherwise, let \t E be \c expr. Given an lvalue \c t of type \c T:
|
Chris@16
|
166 ///
|
Chris@16
|
167 /// If \c T is not a Proto expression type the resulting terminal is
|
Chris@16
|
168 /// <tt>Generator()(E\<tag::terminal, term\<T &\> \>::make(t))</tt>.
|
Chris@16
|
169 ///
|
Chris@16
|
170 /// If \c T is a Proto expression type and its generator type is different from
|
Chris@16
|
171 /// \c Generator, the result is <tt>Generator()(t)</tt>.
|
Chris@16
|
172 ///
|
Chris@16
|
173 /// Otherwise, the result is the lvalue \c t.
|
Chris@16
|
174 ///
|
Chris@16
|
175 template<typename T, typename IsExpr = void, typename Callable = proto::callable>
|
Chris@16
|
176 struct as_child
|
Chris@16
|
177 : detail::as_child<
|
Chris@16
|
178 T
|
Chris@16
|
179 , typename detail::base_generator<Generator>::type
|
Chris@16
|
180 , wants_basic_expr<Generator>::value
|
Chris@16
|
181 >
|
Chris@16
|
182 {
|
Chris@16
|
183 BOOST_PROTO_CALLABLE()
|
Chris@16
|
184 };
|
Chris@16
|
185
|
Chris@16
|
186 /// INTERNAL ONLY
|
Chris@16
|
187 ///
|
Chris@16
|
188 template<typename T>
|
Chris@16
|
189 struct as_child<T, typename T::proto_is_expr_, proto::callable>
|
Chris@16
|
190 {
|
Chris@16
|
191 BOOST_PROTO_CALLABLE()
|
Chris@16
|
192 typedef T &result_type;
|
Chris@16
|
193
|
Chris@16
|
194 BOOST_FORCEINLINE
|
Chris@16
|
195 result_type operator()(T &e) const
|
Chris@16
|
196 {
|
Chris@16
|
197 return e;
|
Chris@16
|
198 }
|
Chris@16
|
199 };
|
Chris@16
|
200 };
|
Chris@16
|
201
|
Chris@16
|
202 /// \brief The domain expressions have by default, if
|
Chris@16
|
203 /// \c proto::extends\<\> has not been used to associate
|
Chris@16
|
204 /// a domain with an expression.
|
Chris@16
|
205 ///
|
Chris@16
|
206 struct default_domain
|
Chris@16
|
207 : domain<>
|
Chris@16
|
208 {};
|
Chris@16
|
209
|
Chris@16
|
210 /// \brief A domain to use when you prefer the use of
|
Chris@16
|
211 /// \c proto::basic_expr\<\> over \c proto::expr\<\>.
|
Chris@16
|
212 ///
|
Chris@16
|
213 struct basic_default_domain
|
Chris@16
|
214 : domain<basic_default_generator>
|
Chris@16
|
215 {};
|
Chris@16
|
216
|
Chris@16
|
217 /// \brief A pseudo-domain for use in functions and
|
Chris@16
|
218 /// metafunctions that require a domain parameter. It
|
Chris@16
|
219 /// indicates that the domain of the parent node should
|
Chris@16
|
220 /// be inferred from the domains of the child nodes.
|
Chris@16
|
221 ///
|
Chris@16
|
222 /// \attention \c deduce_domain is not itself a valid domain.
|
Chris@16
|
223 ///
|
Chris@16
|
224 struct deduce_domain
|
Chris@16
|
225 : domain<detail::not_a_generator, detail::not_a_grammar, detail::not_a_domain>
|
Chris@16
|
226 {};
|
Chris@16
|
227
|
Chris@16
|
228 /// \brief Given a domain, a tag type and an argument list,
|
Chris@16
|
229 /// compute the type of the expression to generate. This is
|
Chris@16
|
230 /// either an instance of \c proto::expr\<\> or
|
Chris@16
|
231 /// \c proto::basic_expr\<\>.
|
Chris@16
|
232 ///
|
Chris@16
|
233 template<typename Domain, typename Tag, typename Args, bool WantsBasicExpr>
|
Chris@16
|
234 struct base_expr
|
Chris@16
|
235 {
|
Chris@16
|
236 typedef proto::expr<Tag, Args, Args::arity> type;
|
Chris@16
|
237 };
|
Chris@16
|
238
|
Chris@16
|
239 /// INTERNAL ONLY
|
Chris@16
|
240 ///
|
Chris@16
|
241 template<typename Domain, typename Tag, typename Args>
|
Chris@16
|
242 struct base_expr<Domain, Tag, Args, true>
|
Chris@16
|
243 {
|
Chris@16
|
244 typedef proto::basic_expr<Tag, Args, Args::arity> type;
|
Chris@16
|
245 };
|
Chris@16
|
246
|
Chris@16
|
247 }
|
Chris@16
|
248
|
Chris@16
|
249 /// A metafunction that returns \c mpl::true_
|
Chris@16
|
250 /// if the type \c T is the type of a Proto domain;
|
Chris@16
|
251 /// \c mpl::false_ otherwise. If \c T inherits from
|
Chris@16
|
252 /// \c proto::domain\<\>, \c is_domain\<T\> is
|
Chris@16
|
253 /// \c mpl::true_.
|
Chris@16
|
254 template<typename T, typename Void /* = void*/>
|
Chris@16
|
255 struct is_domain
|
Chris@16
|
256 : mpl::false_
|
Chris@16
|
257 {};
|
Chris@16
|
258
|
Chris@16
|
259 /// INTERNAL ONLY
|
Chris@16
|
260 ///
|
Chris@16
|
261 template<typename T>
|
Chris@16
|
262 struct is_domain<T, typename T::proto_is_domain_>
|
Chris@16
|
263 : mpl::true_
|
Chris@16
|
264 {};
|
Chris@16
|
265
|
Chris@16
|
266 /// A metafunction that returns the domain of
|
Chris@16
|
267 /// a given type. If \c T is a Proto expression
|
Chris@16
|
268 /// type, it returns that expression's associated
|
Chris@16
|
269 /// domain. If not, it returns
|
Chris@16
|
270 /// \c proto::default_domain.
|
Chris@16
|
271 template<typename T, typename Void /* = void*/>
|
Chris@16
|
272 struct domain_of
|
Chris@16
|
273 {
|
Chris@16
|
274 typedef default_domain type;
|
Chris@16
|
275 };
|
Chris@16
|
276
|
Chris@16
|
277 /// INTERNAL ONLY
|
Chris@16
|
278 ///
|
Chris@16
|
279 template<typename T>
|
Chris@16
|
280 struct domain_of<T, typename T::proto_is_expr_>
|
Chris@16
|
281 {
|
Chris@16
|
282 typedef typename T::proto_domain type;
|
Chris@16
|
283 };
|
Chris@16
|
284
|
Chris@16
|
285 /// INTERNAL ONLY
|
Chris@16
|
286 ///
|
Chris@16
|
287 template<typename T>
|
Chris@16
|
288 struct domain_of<T &, void>
|
Chris@16
|
289 {
|
Chris@16
|
290 typedef typename domain_of<T>::type type;
|
Chris@16
|
291 };
|
Chris@16
|
292
|
Chris@16
|
293 /// INTERNAL ONLY
|
Chris@16
|
294 ///
|
Chris@16
|
295 template<typename T>
|
Chris@16
|
296 struct domain_of<boost::reference_wrapper<T>, void>
|
Chris@16
|
297 {
|
Chris@16
|
298 typedef typename domain_of<T>::type type;
|
Chris@16
|
299 };
|
Chris@16
|
300
|
Chris@16
|
301 /// INTERNAL ONLY
|
Chris@16
|
302 ///
|
Chris@16
|
303 template<typename T>
|
Chris@16
|
304 struct domain_of<boost::reference_wrapper<T> const, void>
|
Chris@16
|
305 {
|
Chris@16
|
306 typedef typename domain_of<T>::type type;
|
Chris@16
|
307 };
|
Chris@16
|
308
|
Chris@16
|
309 /// A metafunction that returns \c mpl::true_
|
Chris@16
|
310 /// if the type \c SubDomain is a sub-domain of
|
Chris@16
|
311 /// \c SuperDomain; \c mpl::false_ otherwise.
|
Chris@16
|
312 template<typename SubDomain, typename SuperDomain>
|
Chris@16
|
313 struct is_sub_domain_of
|
Chris@16
|
314 : is_sub_domain_of<typename SubDomain::proto_super_domain, SuperDomain>
|
Chris@16
|
315 {};
|
Chris@16
|
316
|
Chris@16
|
317 /// INTERNAL ONLY
|
Chris@16
|
318 ///
|
Chris@16
|
319 template<typename SuperDomain>
|
Chris@16
|
320 struct is_sub_domain_of<proto::no_super_domain, SuperDomain>
|
Chris@16
|
321 : mpl::false_
|
Chris@16
|
322 {};
|
Chris@16
|
323
|
Chris@16
|
324 /// INTERNAL ONLY
|
Chris@16
|
325 ///
|
Chris@16
|
326 template<typename SuperDomain>
|
Chris@16
|
327 struct is_sub_domain_of<SuperDomain, SuperDomain>
|
Chris@16
|
328 : mpl::true_
|
Chris@16
|
329 {};
|
Chris@16
|
330
|
Chris@16
|
331 }}
|
Chris@16
|
332
|
Chris@101
|
333 #if defined(_MSC_VER)
|
Chris@16
|
334 # pragma warning(pop)
|
Chris@16
|
335 #endif
|
Chris@16
|
336
|
Chris@16
|
337 #endif
|