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