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. >>*/ |
85 | 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. >>*/ |
122 | 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_ = {.child0: {}}; |
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_ = {.child0: {}}; |
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> |
301 | 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 |
374 | 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 | |
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 | |
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(t: 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(t: 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(t: 1), i, i); |
480 | #ifndef BOOST_MSVC |
481 | SquareAndPromoteInt()(proto::lit(t: 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 | // |
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 | |