1 ///////////////////////////////////////////////////////////////////////////////
2 /// \file generate.hpp
3 /// Contains definition of generate\<\> class template, which end users can
4 /// specialize for generating domain-specific expression wrappers.
5 //
6 //  Copyright 2008 Eric Niebler. Distributed under the Boost
7 //  Software License, Version 1.0. (See accompanying file
8 //  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
9 
10 #ifndef BOOST_PROTO_GENERATE_HPP_EAN_02_13_2007
11 #define BOOST_PROTO_GENERATE_HPP_EAN_02_13_2007
12 
13 #include <boost/config.hpp>
14 #include <boost/version.hpp>
15 #include <boost/preprocessor/cat.hpp>
16 #include <boost/preprocessor/iteration/iterate.hpp>
17 #include <boost/preprocessor/facilities/intercept.hpp>
18 #include <boost/preprocessor/repetition/enum_params.hpp>
19 #include <boost/preprocessor/repetition/enum_binary_params.hpp>
20 #include <boost/preprocessor/repetition/enum_trailing_params.hpp>
21 #include <boost/mpl/bool.hpp>
22 #include <boost/utility/enable_if.hpp>
23 #include <boost/utility/result_of.hpp>
24 #include <boost/proto/proto_fwd.hpp>
25 #include <boost/proto/args.hpp>
26 
27 #if defined(_MSC_VER)
28 # pragma warning(push)
29 # pragma warning(disable : 4714) // function 'xxx' marked as __forceinline not inlined
30 #endif
31 
32 namespace boost { namespace proto
33 {
34 
35     namespace detail
36     {
37         template<typename Expr>
38         struct by_value_generator_;
39 
40         template<typename Tag, typename Arg>
41         struct by_value_generator_<proto::expr<Tag, term<Arg>, 0> >
42         {
43             typedef
44                 proto::expr<
45                     Tag
46                   , term<typename detail::term_traits<Arg>::value_type>
47                   , 0
48                 >
49             type;
50 
51             BOOST_FORCEINLINE
callboost::proto::detail::by_value_generator_52             static type const call(proto::expr<Tag, term<Arg>, 0> const &e)
53             {
54                 type that = {e.child0};
55                 return that;
56             }
57         };
58 
59         template<typename Tag, typename Arg>
60         struct by_value_generator_<proto::basic_expr<Tag, term<Arg>, 0> >
61         {
62             typedef
63                 proto::basic_expr<
64                     Tag
65                   , term<typename detail::term_traits<Arg>::value_type>
66                   , 0
67                 >
68             type;
69 
70             BOOST_FORCEINLINE
callboost::proto::detail::by_value_generator_71             static type const call(proto::basic_expr<Tag, term<Arg>, 0> const &e)
72             {
73                 type that = {e.child0};
74                 return that;
75             }
76         };
77 
78         // Include the other specializations of by_value_generator_
79         #include <boost/proto/detail/generate_by_value.hpp>
80     }
81 
82     /// \brief Annotate a generator to indicate that it would
83     /// prefer to be passed instances of \c proto::basic_expr\<\> rather
84     /// than \c proto::expr\<\>. <tt>use_basic_expr\<Generator\></tt> is
85     /// itself a generator.
86     ///
87     template<typename Generator>
88     struct use_basic_expr
89       : Generator
90     {
91         BOOST_PROTO_USE_BASIC_EXPR()
92     };
93 
94     /// \brief A simple generator that passes an expression
95     /// through unchanged.
96     ///
97     /// Generators are intended for use as the first template parameter
98     /// to the \c domain\<\> class template and control if and how
99     /// expressions within that domain are to be customized.
100     /// The \c default_generator makes no modifications to the expressions
101     /// passed to it.
102     struct default_generator
103     {
104         BOOST_PROTO_CALLABLE()
105 
106         template<typename Sig>
107         struct result;
108 
109         template<typename This, typename Expr>
110         struct result<This(Expr)>
111         {
112             typedef Expr type;
113         };
114 
115         /// \param expr A Proto expression
116         /// \return expr
117         template<typename Expr>
118         BOOST_FORCEINLINE
BOOST_PROTO_RETURN_TYPE_STRICT_LOOSEboost::proto::default_generator119         BOOST_PROTO_RETURN_TYPE_STRICT_LOOSE(Expr, Expr const &)
120         operator ()(Expr const &e) const
121         {
122             return e;
123         }
124     };
125 
126     /// \brief A simple generator that passes an expression
127     /// through unchanged and specifies a preference for
128     /// \c proto::basic_expr\<\> over \c proto::expr\<\>.
129     ///
130     /// Generators are intended for use as the first template parameter
131     /// to the \c domain\<\> class template and control if and how
132     /// expressions within that domain are to be customized.
133     /// The \c default_generator makes no modifications to the expressions
134     /// passed to it.
135     struct basic_default_generator
136       : proto::use_basic_expr<default_generator>
137     {};
138 
139     /// \brief A generator that wraps expressions passed
140     /// to it in the specified extension wrapper.
141     ///
142     /// Generators are intended for use as the first template parameter
143     /// to the \c domain\<\> class template and control if and how
144     /// expressions within that domain are to be customized.
145     /// \c generator\<\> wraps each expression passed to it in
146     /// the \c Extends\<\> wrapper.
147     template<template<typename> class Extends>
148     struct generator
149     {
150         BOOST_PROTO_CALLABLE()
151         BOOST_PROTO_USE_BASIC_EXPR()
152 
153         template<typename Sig>
154         struct result;
155 
156         template<typename This, typename Expr>
157         struct result<This(Expr)>
158         {
159             typedef Extends<Expr> type;
160         };
161 
162         template<typename This, typename Expr>
163         struct result<This(Expr &)>
164         {
165             typedef Extends<Expr> type;
166         };
167 
168         template<typename This, typename Expr>
169         struct result<This(Expr const &)>
170         {
171             typedef Extends<Expr> type;
172         };
173 
174         /// \param expr A Proto expression
175         /// \return Extends<Expr>(expr)
176         template<typename Expr>
177         BOOST_FORCEINLINE
operator ()boost::proto::generator178         Extends<Expr> operator ()(Expr const &e) const
179         {
180             return Extends<Expr>(e);
181         }
182     };
183 
184     /// \brief A generator that wraps expressions passed
185     /// to it in the specified extension wrapper and uses
186     /// aggregate initialization for the wrapper.
187     ///
188     /// Generators are intended for use as the first template parameter
189     /// to the \c domain\<\> class template and control if and how
190     /// expressions within that domain are to be customized.
191     /// \c pod_generator\<\> wraps each expression passed to it in
192     /// the \c Extends\<\> wrapper, and uses aggregate initialzation
193     /// for the wrapped object.
194     template<template<typename> class Extends>
195     struct pod_generator
196     {
197         BOOST_PROTO_CALLABLE()
198         BOOST_PROTO_USE_BASIC_EXPR()
199 
200         template<typename Sig>
201         struct result;
202 
203         template<typename This, typename Expr>
204         struct result<This(Expr)>
205         {
206             typedef Extends<Expr> type;
207         };
208 
209         template<typename This, typename Expr>
210         struct result<This(Expr &)>
211         {
212             typedef Extends<Expr> type;
213         };
214 
215         template<typename This, typename Expr>
216         struct result<This(Expr const &)>
217         {
218             typedef Extends<Expr> type;
219         };
220 
221         /// \param expr The expression to wrap
222         /// \return <tt>Extends\<Expr\> that = {expr}; return that;</tt>
223         template<typename Expr>
224         BOOST_FORCEINLINE
operator ()boost::proto::pod_generator225         Extends<Expr> operator ()(Expr const &e) const
226         {
227             Extends<Expr> that = {e};
228             return that;
229         }
230 
231         // Work-around for:
232         // https://connect.microsoft.com/VisualStudio/feedback/details/765449/codegen-stack-corruption-using-runtime-checks-when-aggregate-initializing-struct
233     #if BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1700))
234         template<typename Class, typename Member>
235         BOOST_FORCEINLINE
operator ()boost::proto::pod_generator236         Extends<expr<tag::terminal, proto::term<Member Class::*> > > operator ()(expr<tag::terminal, proto::term<Member Class::*> > const &e) const
237         {
238             Extends<expr<tag::terminal, proto::term<Member Class::*> > > that;
239             proto::value(that.proto_expr_) = proto::value(e);
240             return that;
241         }
242 
243         template<typename Class, typename Member>
244         BOOST_FORCEINLINE
operator ()boost::proto::pod_generator245         Extends<basic_expr<tag::terminal, proto::term<Member Class::*> > > operator ()(basic_expr<tag::terminal, proto::term<Member Class::*> > const &e) const
246         {
247             Extends<basic_expr<tag::terminal, proto::term<Member Class::*> > > that;
248             proto::value(that.proto_expr_) = proto::value(e);
249             return that;
250         }
251     #endif
252     };
253 
254     /// \brief A generator that replaces child nodes held by
255     /// reference with ones held by value. Use with
256     /// \c compose_generators to forward that result to another
257     /// generator.
258     ///
259     /// Generators are intended for use as the first template parameter
260     /// to the \c domain\<\> class template and control if and how
261     /// expressions within that domain are to be customized.
262     /// \c by_value_generator ensures all child nodes are
263     /// held by value. This generator is typically composed with a
264     /// second generator for further processing, as
265     /// <tt>compose_generators\<by_value_generator, MyGenerator\></tt>.
266     struct by_value_generator
267     {
268         BOOST_PROTO_CALLABLE()
269 
270         template<typename Sig>
271         struct result;
272 
273         template<typename This, typename Expr>
274         struct result<This(Expr)>
275         {
276             typedef
277                 typename detail::by_value_generator_<Expr>::type
278             type;
279         };
280 
281         template<typename This, typename Expr>
282         struct result<This(Expr &)>
283         {
284             typedef
285                 typename detail::by_value_generator_<Expr>::type
286             type;
287         };
288 
289         template<typename This, typename Expr>
290         struct result<This(Expr const &)>
291         {
292             typedef
293                 typename detail::by_value_generator_<Expr>::type
294             type;
295         };
296 
297         /// \param expr The expression to modify.
298         /// \return <tt>deep_copy(expr)</tt>
299         template<typename Expr>
300         BOOST_FORCEINLINE
operator ()boost::proto::by_value_generator301         typename result<by_value_generator(Expr)>::type operator ()(Expr const &e) const
302         {
303             return detail::by_value_generator_<Expr>::call(e);
304         }
305     };
306 
307     /// \brief A composite generator that first applies one
308     /// transform to an expression and then forwards the result
309     /// on to another generator for further transformation.
310     ///
311     /// Generators are intended for use as the first template parameter
312     /// to the \c domain\<\> class template and control if and how
313     /// expressions within that domain are to be customized.
314     /// \c compose_generators\<\> is a composite generator that first
315     /// applies one transform to an expression and then forwards the
316     /// result on to another generator for further transformation.
317     template<typename First, typename Second>
318     struct compose_generators
319     {
320         BOOST_PROTO_CALLABLE()
321 
322         template<typename Sig>
323         struct result;
324 
325         template<typename This, typename Expr>
326         struct result<This(Expr)>
327         {
328             typedef
329                 typename Second::template result<
330                     Second(typename First::template result<First(Expr)>::type)
331                 >::type
332             type;
333         };
334 
335         template<typename This, typename Expr>
336         struct result<This(Expr &)>
337         {
338             typedef
339                 typename Second::template result<
340                     Second(typename First::template result<First(Expr)>::type)
341                 >::type
342             type;
343         };
344 
345         template<typename This, typename Expr>
346         struct result<This(Expr const &)>
347         {
348             typedef
349                 typename Second::template result<
350                     Second(typename First::template result<First(Expr)>::type)
351                 >::type
352             type;
353         };
354 
355         /// \param expr The expression to modify.
356         /// \return Second()(First()(expr))
357         template<typename Expr>
358         BOOST_FORCEINLINE
operator ()boost::proto::compose_generators359         typename result<compose_generators(Expr)>::type operator ()(Expr const &e) const
360         {
361             return Second()(First()(e));
362         }
363     };
364 
365     /// \brief Tests a generator to see whether it would prefer
366     /// to be passed instances of \c proto::basic_expr\<\> rather than
367     /// \c proto::expr\<\>.
368     ///
369     template<typename Generator, typename Void>
370     struct wants_basic_expr
371       : mpl::false_
372     {};
373 
374     template<typename Generator>
375     struct wants_basic_expr<Generator, typename Generator::proto_use_basic_expr_>
376       : mpl::true_
377     {};
378 
379     /// INTERNAL ONLY
380     template<>
381     struct is_callable<default_generator>
382       : mpl::true_
383     {};
384 
385     /// INTERNAL ONLY
386     template<template<typename> class Extends>
387     struct is_callable<generator<Extends> >
388       : mpl::true_
389     {};
390 
391     /// INTERNAL ONLY
392     template<template<typename> class Extends>
393     struct is_callable<pod_generator<Extends> >
394       : mpl::true_
395     {};
396 
397     /// INTERNAL ONLY
398     template<>
399     struct is_callable<by_value_generator>
400       : mpl::true_
401     {};
402 
403     /// INTERNAL ONLY
404     template<typename First, typename Second>
405     struct is_callable<compose_generators<First, Second> >
406       : mpl::true_
407     {};
408 
409 }}
410 
411 // Specializations of boost::result_of and boost::tr1_result_of to eliminate
412 // some unnecessary template instantiations
413 namespace boost
414 {
415     template<typename Expr>
416     struct result_of<proto::default_domain(Expr)>
417     {
418         typedef Expr type;
419     };
420 
421     template<typename Expr>
422     struct result_of<proto::basic_default_domain(Expr)>
423     {
424         typedef Expr type;
425     };
426 
427     template<typename Expr>
428     struct result_of<proto::default_generator(Expr)>
429     {
430         typedef Expr type;
431     };
432 
433     template<typename Expr>
434     struct result_of<proto::basic_default_generator(Expr)>
435     {
436         typedef Expr type;
437     };
438 
439     #if BOOST_VERSION >= 104400
440     template<typename Expr>
441     struct tr1_result_of<proto::default_domain(Expr)>
442     {
443         typedef Expr type;
444     };
445 
446     template<typename Expr>
447     struct tr1_result_of<proto::basic_default_domain(Expr)>
448     {
449         typedef Expr type;
450     };
451 
452     template<typename Expr>
453     struct tr1_result_of<proto::default_generator(Expr)>
454     {
455         typedef Expr type;
456     };
457 
458     template<typename Expr>
459     struct tr1_result_of<proto::basic_default_generator(Expr)>
460     {
461         typedef Expr type;
462     };
463     #endif
464 }
465 
466 #if defined(_MSC_VER)
467 # pragma warning(pop)
468 #endif
469 
470 #endif // BOOST_PROTO_GENERATE_HPP_EAN_02_13_2007
471