1 ///////////////////////////////////////////////////////////////////////////////
2 // examples.hpp
3 //
4 //  Copyright 2008 Eric Niebler. Distributed under the Boost
5 //  Software License, Version 1.0. (See accompanying file
6 //  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7 
8 #include <iostream>
9 #include <boost/config.hpp>
10 #include <boost/mpl/min_max.hpp>
11 #include <boost/proto/core.hpp>
12 #include <boost/proto/transform.hpp>
13 #include <boost/proto/functional/fusion.hpp>
14 #include <boost/utility/result_of.hpp>
15 #include <boost/fusion/include/cons.hpp>
16 #include <boost/fusion/include/tuple.hpp>
17 #include <boost/fusion/include/pop_front.hpp>
18 #include <boost/test/unit_test.hpp>
19 
20 namespace mpl = boost::mpl;
21 namespace proto = boost::proto;
22 namespace fusion = boost::fusion;
23 using proto::_;
24 
25 template<int I>
26 struct placeholder
27 {};
28 
29 namespace test1
30 {
31 //[ CalcGrammar
32     // This is the grammar for calculator expressions,
33     // to which we will attach transforms for computing
34     // the expressions' arity.
35     /*<< A Calculator expression is ... >>*/
36     struct CalcArity
37       : proto::or_<
38             /*<< _1, or ... >>*/
39             proto::terminal< placeholder<0> >
40           /*<< _2, or ... >>*/
41           , proto::terminal< placeholder<1> >
42           /*<< some other terminal, or ... >>*/
43           , proto::terminal< _ >
44           /*<< a unary expression where the operand is a calculator expression, or ... >>*/
45           , proto::unary_expr< _, CalcArity >
46           /*<< a binary expression where the operands are calculator expressions >>*/
47           , proto::binary_expr< _, CalcArity, CalcArity >
48         >
49     {};
50 //]
51 }
52 
53 //[ binary_arity
54 /*<< The `CalculatorArity` is a transform for calculating
55 the arity of a calculator expression. It will be define in
56 terms of `binary_arity`, which is defined in terms of
57 `CalculatorArity`; hence, the definition is recursive.>>*/
58 struct CalculatorArity;
59 
60 // A custom transform that returns the arity of a unary
61 // calculator expression by finding the arity of the
62 // child expression.
63 struct unary_arity
64   /*<< Custom transforms should inherit from
65   transform<>. In some cases, (e.g., when the transform
66   is a template), it is also necessary to specialize
67   the proto::is_callable<> trait. >>*/
68   : proto::transform<unary_arity>
69 {
70     template<typename Expr, typename State, typename Data>
71     /*<< Transforms have a nested `impl<>` that is
72     a valid TR1 function object. >>*/
73     struct impl
74       : proto::transform_impl<Expr, State, Data>
75     {
76         /*<< Get the child. >>*/
77         typedef typename proto::result_of::child<Expr>::type child_expr;
78 
79         /*<< Apply `CalculatorArity` to find the arity of the child. >>*/
80         typedef typename boost::result_of<CalculatorArity(child_expr, State, Data)>::type result_type;
81 
82         /*<< The `unary_arity` transform doesn't have an interesting
83         runtime counterpart, so just return a default-constructed object
84         of the correct type. >>*/
operator ()unary_arity::impl85         result_type operator ()(proto::ignore, proto::ignore, proto::ignore) const
86         {
87             return result_type();
88         }
89     };
90 };
91 
92 // A custom transform that returns the arity of a binary
93 // calculator expression by finding the maximum of the
94 // arities of the mpl::int_<2> child expressions.
95 struct binary_arity
96   /*<< All custom transforms should inherit from
97   transform. In some cases, (e.g., when the transform
98   is a template), it is also necessary to specialize
99   the proto::is_callable<> trait. >>*/
100   : proto::transform<binary_arity>
101 {
102     template<typename Expr, typename State, typename Data>
103     /*<< Transforms have a nested `impl<>` that is
104     a valid TR1 function object. >>*/
105     struct impl
106       : proto::transform_impl<Expr, State, Data>
107     {
108         /*<< Get the left and right children. >>*/
109         typedef typename proto::result_of::left<Expr>::type left_expr;
110         typedef typename proto::result_of::right<Expr>::type right_expr;
111 
112         /*<< Apply `CalculatorArity` to find the arity of the left and right children. >>*/
113         typedef typename boost::result_of<CalculatorArity(left_expr, State, Data)>::type left_arity;
114         typedef typename boost::result_of<CalculatorArity(right_expr, State, Data)>::type right_arity;
115 
116         /*<< The return type is the maximum of the children's arities. >>*/
117         typedef typename mpl::max<left_arity, right_arity>::type result_type;
118 
119         /*<< The `unary_arity` transform doesn't have an interesting
120         runtime counterpart, so just return a default-constructed object
121         of the correct type. >>*/
operator ()binary_arity::impl122         result_type operator ()(proto::ignore, proto::ignore, proto::ignore) const
123         {
124             return result_type();
125         }
126     };
127 };
128 //]
129 
130 proto::terminal< placeholder<0> >::type const _1 = {};
131 proto::terminal< placeholder<1> >::type const _2 = {};
132 
133 //[ CalculatorArityGrammar
134 struct CalculatorArity
135   : proto::or_<
136         proto::when< proto::terminal< placeholder<0> >,  mpl::int_<1>() >
137       , proto::when< proto::terminal< placeholder<1> >,  mpl::int_<2>() >
138       , proto::when< proto::terminal<_>,                 mpl::int_<0>() >
139       , proto::when< proto::unary_expr<_, _>,            unary_arity >
140       , proto::when< proto::binary_expr<_, _, _>,        binary_arity >
141     >
142 {};
143 //]
144 
145 //[ CalcArity
146 struct CalcArity
147   : proto::or_<
148         proto::when< proto::terminal< placeholder<0> >,
149             mpl::int_<1>()
150         >
151       , proto::when< proto::terminal< placeholder<1> >,
152             mpl::int_<2>()
153         >
154       , proto::when< proto::terminal<_>,
155             mpl::int_<0>()
156         >
157       , proto::when< proto::unary_expr<_, CalcArity>,
158             CalcArity(proto::_child)
159         >
160       , proto::when< proto::binary_expr<_, CalcArity, CalcArity>,
161             mpl::max<CalcArity(proto::_left),
162                      CalcArity(proto::_right)>()
163         >
164     >
165 {};
166 //]
167 
168 // BUGBUG find workaround for this
169 #if BOOST_WORKAROUND(BOOST_MSVC, == 1310)
170 #define _pop_front(x) call<proto::_pop_front(x)>
171 #define _value(x)     call<proto::_value(x)>
172 #endif
173 
174 //[ AsArgList
175 // This transform matches function invocations such as foo(1,'a',"b")
176 // and transforms them into Fusion cons lists of their arguments. In this
177 // case, the result would be cons(1, cons('a', cons("b", nil()))).
178 struct ArgsAsList
179   : proto::when<
180         proto::function<proto::terminal<_>, proto::vararg<proto::terminal<_> > >
181       /*<< Use a `fold<>` transform to iterate over the children of this
182       node in forward order, building a fusion list from front to back. >>*/
183       , proto::fold<
184             /*<< The first child expression of a `function<>` node is the
185             function being invoked. We don't want that in our list, so use
186             `pop_front()` to remove it. >>*/
187             proto::_pop_front(_)
188           /*<< `nil` is the initial state used by the `fold<>` transform. >>*/
189           , fusion::nil()
190           /*<< Put the rest of the function arguments in a fusion cons
191           list. >>*/
192           , proto::functional::push_back(proto::_state, proto::_value)
193         >
194     >
195 {};
196 //]
197 
198 //[ FoldTreeToList
199 // This transform matches expressions of the form (_1=1,'a',"b")
200 // (note the use of the comma operator) and transforms it into a
201 // Fusion cons list of their arguments. In this case, the result
202 // would be cons(1, cons('a', cons("b", nil()))).
203 struct FoldTreeToList
204   : proto::or_<
205         // This grammar describes what counts as the terminals in expressions
206         // of the form (_1=1,'a',"b"), which will be flattened using
207         // reverse_fold_tree<> below.
208         proto::when< proto::assign<_, proto::terminal<_> >
209           , proto::_value(proto::_right)
210         >
211       , proto::when< proto::terminal<_>
212           , proto::_value
213         >
214       , proto::when<
215             proto::comma<FoldTreeToList, FoldTreeToList>
216           /*<< Fold all terminals that are separated by commas into a Fusion cons list. >>*/
217           , proto::reverse_fold_tree<
218                 _
219               , fusion::nil()
220               , fusion::cons<FoldTreeToList, proto::_state>(FoldTreeToList, proto::_state)
221             >
222         >
223     >
224 {};
225 //]
226 
227 //[ Promote
228 // This transform finds all float terminals in an expression and promotes
229 // them to doubles.
230 struct Promote
231   : proto::or_<
232         /*<< Match a `terminal<float>`, then construct a
233         `terminal<double>::type` with the `float`. >>*/
234         proto::when<proto::terminal<float>, proto::terminal<double>::type(proto::_value) >
235       , proto::when<proto::terminal<_> >
236       /*<< `nary_expr<>` has a pass-through transform which
237       will transform each child sub-expression using the
238       `Promote` transform. >>*/
239       , proto::when<proto::nary_expr<_, proto::vararg<Promote> > >
240     >
241 {};
242 //]
243 
244 //[ LazyMakePair
245 struct make_pair_tag {};
246 proto::terminal<make_pair_tag>::type const make_pair_ = {{}};
247 
248 // This transform matches lazy function invocations like
249 // `make_pair_(1, 3.14)` and actually builds a `std::pair<>`
250 // from the arguments.
251 struct MakePair
252   : proto::when<
253         /*<< Match expressions like `make_pair_(1, 3.14)` >>*/
254         proto::function<
255             proto::terminal<make_pair_tag>
256           , proto::terminal<_>
257           , proto::terminal<_>
258         >
259       /*<< Return `std::pair<F,S>(f,s)` where `f` and `s` are the
260       first and second arguments to the lazy `make_pair_()` function.
261       (This uses `proto::make<>` under the covers to evaluate the
262       transform.)>>*/
263       , std::pair<
264             proto::_value(proto::_child1)
265           , proto::_value(proto::_child2)
266         >(
267             proto::_value(proto::_child1)
268           , proto::_value(proto::_child2)
269         )
270     >
271 {};
272 //]
273 
274 namespace lazy_make_pair2
275 {
276     //[ LazyMakePair2
277     struct make_pair_tag {};
278     proto::terminal<make_pair_tag>::type const make_pair_ = {{}};
279 
280     // Like std::make_pair(), only as a function object.
281     /*<<Inheriting from `proto::callable` lets Proto know
282     that this is a callable transform, so we can use it
283     without having to wrap it in `proto::call<>`.>>*/
284     struct make_pair : proto::callable
285     {
286         template<typename Sig> struct result;
287 
288         template<typename This, typename First, typename Second>
289         struct result<This(First, Second)>
290         {
291             typedef
292                 std::pair<
293                     BOOST_PROTO_UNCVREF(First)
294                   , BOOST_PROTO_UNCVREF(Second)
295                 >
296             type;
297         };
298 
299         template<typename First, typename Second>
300         std::pair<First, Second>
operator ()lazy_make_pair2::make_pair301         operator()(First const &first, Second const &second) const
302         {
303             return std::make_pair(first, second);
304         }
305     };
306 
307     // This transform matches lazy function invocations like
308     // `make_pair_(1, 3.14)` and actually builds a `std::pair<>`
309     // from the arguments.
310     struct MakePair
311       : proto::when<
312             /*<< Match expressions like `make_pair_(1, 3.14)` >>*/
313             proto::function<
314                 proto::terminal<make_pair_tag>
315               , proto::terminal<_>
316               , proto::terminal<_>
317             >
318           /*<< Return `make_pair()(f,s)` where `f` and `s` are the
319           first and second arguments to the lazy `make_pair_()` function.
320           (This uses `proto::call<>` under the covers  to evaluate the
321           transform.)>>*/
322           , make_pair(
323                 proto::_value(proto::_child1)
324               , proto::_value(proto::_child2)
325             )
326         >
327     {};
328     //]
329 }
330 
331 
332 //[ NegateInt
333 struct NegateInt
334   : proto::when<proto::terminal<int>, proto::negate<_>(_)>
335 {};
336 //]
337 
338 #ifndef BOOST_MSVC
339 //[ SquareAndPromoteInt
340 struct SquareAndPromoteInt
341   : proto::when<
342         proto::terminal<int>
343       , proto::_make_multiplies(
344             proto::terminal<long>::type(proto::_value)
345           , proto::terminal<long>::type(proto::_value)
346         )
347     >
348 {};
349 //]
350 #endif
351 
352 namespace lambda_transform
353 {
354     //[LambdaTransform
355     template<typename N>
356     struct placeholder : N {};
357 
358     // A function object that calls fusion::at()
359     struct at : proto::callable
360     {
361         template<typename Sig>
362         struct result;
363 
364         template<typename This, typename Cont, typename Index>
365         struct result<This(Cont, Index)>
366           : fusion::result_of::at<
367                 typename boost::remove_reference<Cont>::type
368               , typename boost::remove_reference<Index>::type
369             >
370         {};
371 
372         template<typename Cont, typename Index>
373         typename fusion::result_of::at<Cont, Index>::type
operator ()lambda_transform::at374         operator ()(Cont &cont, Index const &) const
375         {
376             return fusion::at<Index>(cont);
377         }
378     };
379 
380     // A transform that evaluates a lambda expression.
381     struct LambdaEval
382       : proto::or_<
383             /*<<When you match a placeholder ...>>*/
384             proto::when<
385                 proto::terminal<placeholder<_> >
386               /*<<... call at() with the data parameter, which
387               is a tuple, and the placeholder, which is an MPL
388               Integral Constant.>>*/
389               , at(proto::_data, proto::_value)
390             >
391             /*<<Otherwise, use the _default<> transform, which
392             gives the operators their usual C++ meanings.>>*/
393           , proto::otherwise< proto::_default<LambdaEval> >
394         >
395     {};
396 
397     // Define the lambda placeholders
398     proto::terminal<placeholder<mpl::int_<0> > >::type const _1 = {};
399     proto::terminal<placeholder<mpl::int_<1> > >::type const _2 = {};
400 
test_lambda()401     void test_lambda()
402     {
403         // a tuple that contains the values
404         // of _1 and _2
405         fusion::tuple<int, int> tup(2,3);
406 
407         // Use LambdaEval to evaluate a lambda expression
408         int j = LambdaEval()( _2 - _1, 0, tup );
409         BOOST_CHECK_EQUAL(j, 1);
410 
411         // You can mutate leaves in an expression tree
412         proto::literal<int> k(42);
413         int &l = LambdaEval()( k += 4, 0, tup );
414         BOOST_CHECK_EQUAL(k.get(), 46);
415         BOOST_CHECK_EQUAL(&l, &k.get());
416 
417         // You can mutate the values in the tuple, too.
418         LambdaEval()( _1 += 4, 0, tup );
419         BOOST_CHECK_EQUAL(6, fusion::at_c<0>(tup));
420     }
421     //]
422 }
423 
test_examples()424 void test_examples()
425 {
426     //[ CalculatorArityTest
427     int i = 0; // not used, dummy state and data parameter
428 
429     std::cout << CalculatorArity()( proto::lit(100) * 200, i, i) << '\n';
430     std::cout << CalculatorArity()( (_1 - _1) / _1 * 100, i, i) << '\n';
431     std::cout << CalculatorArity()( (_2 - _1) / _2 * 100, i, i) << '\n';
432     //]
433 
434     BOOST_CHECK_EQUAL(0, CalculatorArity()( proto::lit(100) * 200, i, i));
435     BOOST_CHECK_EQUAL(1, CalculatorArity()( (_1 - _1) / _1 * 100, i, i));
436     BOOST_CHECK_EQUAL(2, CalculatorArity()( (_2 - _1) / _2 * 100, i, i));
437 
438     BOOST_CHECK_EQUAL(0, CalcArity()( proto::lit(100) * 200, i, i));
439     BOOST_CHECK_EQUAL(1, CalcArity()( (_1 - _1) / _1 * 100, i, i));
440     BOOST_CHECK_EQUAL(2, CalcArity()( (_2 - _1) / _2 * 100, i, i));
441 
442     using boost::fusion::cons;
443     using boost::fusion::nil;
444     cons<int, cons<char, cons<std::string> > > args(ArgsAsList()( _1(1, 'a', std::string("b")), i, i ));
445     BOOST_CHECK_EQUAL(args.car, 1);
446     BOOST_CHECK_EQUAL(args.cdr.car, 'a');
447     BOOST_CHECK_EQUAL(args.cdr.cdr.car, std::string("b"));
448 
449     cons<int, cons<char, cons<std::string> > > lst(FoldTreeToList()( (_1 = 1, 'a', std::string("b")), i, i ));
450     BOOST_CHECK_EQUAL(lst.car, 1);
451     BOOST_CHECK_EQUAL(lst.cdr.car, 'a');
452     BOOST_CHECK_EQUAL(lst.cdr.cdr.car, std::string("b"));
453 
454     proto::plus<
455         proto::terminal<double>::type
456       , proto::terminal<double>::type
457     >::type p = Promote()( proto::lit(1.f) + 2.f, i, i );
458 
459     //[ LazyMakePairTest
460     int j = 0; // not used, dummy state and data parameter
461 
462     std::pair<int, double> p2 = MakePair()( make_pair_(1, 3.14), j, j );
463 
464     std::cout << p2.first << std::endl;
465     std::cout << p2.second << std::endl;
466     //]
467 
468     BOOST_CHECK_EQUAL(p2.first, 1);
469     BOOST_CHECK_EQUAL(p2.second, 3.14);
470 
471     std::pair<int, double> p3 = lazy_make_pair2::MakePair()( lazy_make_pair2::make_pair_(1, 3.14), j, j );
472 
473     std::cout << p3.first << std::endl;
474     std::cout << p3.second << std::endl;
475 
476     BOOST_CHECK_EQUAL(p3.first, 1);
477     BOOST_CHECK_EQUAL(p3.second, 3.14);
478 
479     NegateInt()(proto::lit(1), i, i);
480     #ifndef BOOST_MSVC
481     SquareAndPromoteInt()(proto::lit(1), i, i);
482     #endif
483 
484     lambda_transform::test_lambda();
485 }
486 
487 using namespace boost::unit_test;
488 ///////////////////////////////////////////////////////////////////////////////
489 // init_unit_test_suite
490 //
init_unit_test_suite(int argc,char * argv[])491 test_suite* init_unit_test_suite( int argc, char* argv[] )
492 {
493     test_suite *test = BOOST_TEST_SUITE("test examples from the documentation");
494 
495     test->add(BOOST_TEST_CASE(&test_examples));
496 
497     return test;
498 }
499