]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/proto/test/examples.cpp
import new upstream nautilus stable release 14.2.8
[ceph.git] / ceph / src / boost / libs / proto / test / examples.cpp
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_ = {{}};
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>
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(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 //
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 }