]>
git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/proto/test/examples.cpp
1 ///////////////////////////////////////////////////////////////////////////////
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)
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>
20 namespace mpl
= boost::mpl
;
21 namespace proto
= boost::proto
;
22 namespace fusion
= boost::fusion
;
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 ... >>*/
39 proto::terminal
< placeholder
<0> >
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
>
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
;
60 // A custom transform that returns the arity of a unary
61 // calculator expression by finding the arity of the
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
>
70 template<typename Expr
, typename State
, typename Data
>
71 /*<< Transforms have a nested `impl<>` that is
72 a valid TR1 function object. >>*/
74 : proto::transform_impl
<Expr
, State
, Data
>
76 /*<< Get the child. >>*/
77 typedef typename
proto::result_of::child
<Expr
>::type child_expr
;
79 /*<< Apply `CalculatorArity` to find the arity of the child. >>*/
80 typedef typename
boost::result_of
<CalculatorArity(child_expr
, State
, Data
)>::type result_type
;
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
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.
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
>
102 template<typename Expr
, typename State
, typename Data
>
103 /*<< Transforms have a nested `impl<>` that is
104 a valid TR1 function object. >>*/
106 : proto::transform_impl
<Expr
, State
, Data
>
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
;
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
;
116 /*<< The return type is the maximum of the children's arities. >>*/
117 typedef typename
mpl::max
<left_arity
, right_arity
>::type result_type
;
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
124 return result_type();
130 proto::terminal
< placeholder
<0> >::type
const _1
= {};
131 proto::terminal
< placeholder
<1> >::type
const _2
= {};
133 //[ CalculatorArityGrammar
134 struct CalculatorArity
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
>
148 proto::when
< proto::terminal
< placeholder
<0> >,
151 , proto::when
< proto::terminal
< placeholder
<1> >,
154 , proto::when
< proto::terminal
<_
>,
157 , proto::when
< proto::unary_expr
<_
, CalcArity
>,
158 CalcArity(proto::_child
)
160 , proto::when
< proto::binary_expr
<_
, CalcArity
, CalcArity
>,
161 mpl::max
<CalcArity(proto::_left
),
162 CalcArity(proto::_right
)>()
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)>
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()))).
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. >>*/
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. >>*/
188 /*<< `nil` is the initial state used by the `fold<>` transform. >>*/
190 /*<< Put the rest of the function arguments in a fusion cons
192 , proto::functional::push_back(proto::_state
, proto::_value
)
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
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
)
211 , proto::when
< proto::terminal
<_
>
215 proto::comma
<FoldTreeToList
, FoldTreeToList
>
216 /*<< Fold all terminals that are separated by commas into a Fusion cons list. >>*/
217 , proto::reverse_fold_tree
<
220 , fusion::cons
<FoldTreeToList
, proto::_state
>(FoldTreeToList
, proto::_state
)
228 // This transform finds all float terminals in an expression and promotes
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
> > >
245 struct make_pair_tag
{};
246 proto::terminal
<make_pair_tag
>::type
const make_pair_
= {{}};
248 // This transform matches lazy function invocations like
249 // `make_pair_(1, 3.14)` and actually builds a `std::pair<>`
250 // from the arguments.
253 /*<< Match expressions like `make_pair_(1, 3.14)` >>*/
255 proto::terminal
<make_pair_tag
>
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
264 proto::_value(proto::_child1
)
265 , proto::_value(proto::_child2
)
267 proto::_value(proto::_child1
)
268 , proto::_value(proto::_child2
)
274 namespace lazy_make_pair2
277 struct make_pair_tag
{};
278 proto::terminal
<make_pair_tag
>::type
const make_pair_
= {{}};
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
286 template<typename Sig
> struct result
;
288 template<typename This
, typename First
, typename Second
>
289 struct result
<This(First
, Second
)>
293 BOOST_PROTO_UNCVREF(First
)
294 , BOOST_PROTO_UNCVREF(Second
)
299 template<typename First
, typename Second
>
300 std::pair
<First
, Second
>
301 operator()(First
const &first
, Second
const &second
) const
303 return std::make_pair(first
, second
);
307 // This transform matches lazy function invocations like
308 // `make_pair_(1, 3.14)` and actually builds a `std::pair<>`
309 // from the arguments.
312 /*<< Match expressions like `make_pair_(1, 3.14)` >>*/
314 proto::terminal
<make_pair_tag
>
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
323 proto::_value(proto::_child1
)
324 , proto::_value(proto::_child2
)
334 : proto::when
<proto::terminal
<int>, proto::negate
<_
>(_
)>
339 //[ SquareAndPromoteInt
340 struct SquareAndPromoteInt
343 , proto::_make_multiplies(
344 proto::terminal
<long>::type(proto::_value
)
345 , proto::terminal
<long>::type(proto::_value
)
352 namespace lambda_transform
356 struct placeholder
: N
{};
358 // A function object that calls fusion::at()
359 struct at
: proto::callable
361 template<typename Sig
>
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
372 template<typename Cont
, typename Index
>
373 typename
fusion::result_of::at
<Cont
, Index
>::type
374 operator ()(Cont
&cont
, Index
const &) const
376 return fusion::at
<Index
>(cont
);
380 // A transform that evaluates a lambda expression.
383 /*<<When you match a placeholder ...>>*/
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
)
391 /*<<Otherwise, use the _default<> transform, which
392 gives the operators their usual C++ meanings.>>*/
393 , proto::otherwise
< proto::_default
<LambdaEval
> >
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
= {};
403 // a tuple that contains the values
405 fusion::tuple
<int, int> tup(2,3);
407 // Use LambdaEval to evaluate a lambda expression
408 int j
= LambdaEval()( _2
- _1
, 0, tup
);
409 BOOST_CHECK_EQUAL(j
, 1);
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());
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
));
426 //[ CalculatorArityTest
427 int i
= 0; // not used, dummy state and data parameter
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';
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
));
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
));
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"));
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"));
455 proto::terminal
<double>::type
456 , proto::terminal
<double>::type
457 >::type p
= Promote()( proto::lit(1.f
) + 2.f
, i
, i
);
460 int j
= 0; // not used, dummy state and data parameter
462 std::pair
<int, double> p2
= MakePair()( make_pair_(1, 3.14), j
, j
);
464 std::cout
<< p2
.first
<< std::endl
;
465 std::cout
<< p2
.second
<< std::endl
;
468 BOOST_CHECK_EQUAL(p2
.first
, 1);
469 BOOST_CHECK_EQUAL(p2
.second
, 3.14);
471 std::pair
<int, double> p3
= lazy_make_pair2::MakePair()( lazy_make_pair2::make_pair_(1, 3.14), j
, j
);
473 std::cout
<< p3
.first
<< std::endl
;
474 std::cout
<< p3
.second
<< std::endl
;
476 BOOST_CHECK_EQUAL(p3
.first
, 1);
477 BOOST_CHECK_EQUAL(p3
.second
, 3.14);
479 NegateInt()(proto::lit(1), i
, i
);
481 SquareAndPromoteInt()(proto::lit(1), i
, i
);
484 lambda_transform::test_lambda();
487 using namespace boost::unit_test
;
488 ///////////////////////////////////////////////////////////////////////////////
489 // init_unit_test_suite
491 test_suite
* init_unit_test_suite( int argc
, char* argv
[] )
493 test_suite
*test
= BOOST_TEST_SUITE("test examples from the documentation");
495 test
->add(BOOST_TEST_CASE(&test_examples
));