]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/proto/test/examples.cpp
add subtree-ish sources for 12.0.3
[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 `reverse_fold<>` transform to iterate over the children
182 of this node in reverse order, building a fusion list from back to
183 front. >>*/
184 , proto::reverse_fold<
185 /*<< The first child expression of a `function<>` node is the
186 function being invoked. We don't want that in our list, so use
187 `pop_front()` to remove it. >>*/
188 proto::_pop_front(_)
189 /*<< `nil` is the initial state used by the `reverse_fold<>`
190 transform. >>*/
191 , fusion::nil()
192 /*<< Put the rest of the function arguments in a fusion cons
193 list. >>*/
194 , fusion::cons<proto::_value, proto::_state>(proto::_value, proto::_state)
195 >
196 >
197 {};
198 //]
199
200 //[ FoldTreeToList
201 // This transform matches expressions of the form (_1=1,'a',"b")
202 // (note the use of the comma operator) and transforms it into a
203 // Fusion cons list of their arguments. In this case, the result
204 // would be cons(1, cons('a', cons("b", nil()))).
205 struct FoldTreeToList
206 : proto::or_<
207 // This grammar describes what counts as the terminals in expressions
208 // of the form (_1=1,'a',"b"), which will be flattened using
209 // reverse_fold_tree<> below.
210 proto::when< proto::assign<_, proto::terminal<_> >
211 , proto::_value(proto::_right)
212 >
213 , proto::when< proto::terminal<_>
214 , proto::_value
215 >
216 , proto::when<
217 proto::comma<FoldTreeToList, FoldTreeToList>
218 /*<< Fold all terminals that are separated by commas into a Fusion cons list. >>*/
219 , proto::reverse_fold_tree<
220 _
221 , fusion::nil()
222 , fusion::cons<FoldTreeToList, proto::_state>(FoldTreeToList, proto::_state)
223 >
224 >
225 >
226 {};
227 //]
228
229 //[ Promote
230 // This transform finds all float terminals in an expression and promotes
231 // them to doubles.
232 struct Promote
233 : proto::or_<
234 /*<< Match a `terminal<float>`, then construct a
235 `terminal<double>::type` with the `float`. >>*/
236 proto::when<proto::terminal<float>, proto::terminal<double>::type(proto::_value) >
237 , proto::when<proto::terminal<_> >
238 /*<< `nary_expr<>` has a pass-through transform which
239 will transform each child sub-expression using the
240 `Promote` transform. >>*/
241 , proto::when<proto::nary_expr<_, proto::vararg<Promote> > >
242 >
243 {};
244 //]
245
246 //[ LazyMakePair
247 struct make_pair_tag {};
248 proto::terminal<make_pair_tag>::type const make_pair_ = {{}};
249
250 // This transform matches lazy function invocations like
251 // `make_pair_(1, 3.14)` and actually builds a `std::pair<>`
252 // from the arguments.
253 struct MakePair
254 : proto::when<
255 /*<< Match expressions like `make_pair_(1, 3.14)` >>*/
256 proto::function<
257 proto::terminal<make_pair_tag>
258 , proto::terminal<_>
259 , proto::terminal<_>
260 >
261 /*<< Return `std::pair<F,S>(f,s)` where `f` and `s` are the
262 first and second arguments to the lazy `make_pair_()` function.
263 (This uses `proto::make<>` under the covers to evaluate the
264 transform.)>>*/
265 , std::pair<
266 proto::_value(proto::_child1)
267 , proto::_value(proto::_child2)
268 >(
269 proto::_value(proto::_child1)
270 , proto::_value(proto::_child2)
271 )
272 >
273 {};
274 //]
275
276 namespace lazy_make_pair2
277 {
278 //[ LazyMakePair2
279 struct make_pair_tag {};
280 proto::terminal<make_pair_tag>::type const make_pair_ = {{}};
281
282 // Like std::make_pair(), only as a function object.
283 /*<<Inheriting from `proto::callable` lets Proto know
284 that this is a callable transform, so we can use it
285 without having to wrap it in `proto::call<>`.>>*/
286 struct make_pair : proto::callable
287 {
288 template<typename Sig> struct result;
289
290 template<typename This, typename First, typename Second>
291 struct result<This(First, Second)>
292 {
293 typedef
294 std::pair<
295 BOOST_PROTO_UNCVREF(First)
296 , BOOST_PROTO_UNCVREF(Second)
297 >
298 type;
299 };
300
301 template<typename First, typename Second>
302 std::pair<First, Second>
303 operator()(First const &first, Second const &second) const
304 {
305 return std::make_pair(first, second);
306 }
307 };
308
309 // This transform matches lazy function invocations like
310 // `make_pair_(1, 3.14)` and actually builds a `std::pair<>`
311 // from the arguments.
312 struct MakePair
313 : proto::when<
314 /*<< Match expressions like `make_pair_(1, 3.14)` >>*/
315 proto::function<
316 proto::terminal<make_pair_tag>
317 , proto::terminal<_>
318 , proto::terminal<_>
319 >
320 /*<< Return `make_pair()(f,s)` where `f` and `s` are the
321 first and second arguments to the lazy `make_pair_()` function.
322 (This uses `proto::call<>` under the covers to evaluate the
323 transform.)>>*/
324 , make_pair(
325 proto::_value(proto::_child1)
326 , proto::_value(proto::_child2)
327 )
328 >
329 {};
330 //]
331 }
332
333
334 //[ NegateInt
335 struct NegateInt
336 : proto::when<proto::terminal<int>, proto::negate<_>(_)>
337 {};
338 //]
339
340 #ifndef BOOST_MSVC
341 //[ SquareAndPromoteInt
342 struct SquareAndPromoteInt
343 : proto::when<
344 proto::terminal<int>
345 , proto::_make_multiplies(
346 proto::terminal<long>::type(proto::_value)
347 , proto::terminal<long>::type(proto::_value)
348 )
349 >
350 {};
351 //]
352 #endif
353
354 namespace lambda_transform
355 {
356 //[LambdaTransform
357 template<typename N>
358 struct placeholder
359 {
360 typedef typename N::type type;
361 static typename N::value_type const value = N::value;
362 };
363
364 // A function object that calls fusion::at()
365 struct at : proto::callable
366 {
367 template<typename Sig>
368 struct result;
369
370 template<typename This, typename Cont, typename Index>
371 struct result<This(Cont, Index)>
372 : fusion::result_of::at<
373 typename boost::remove_reference<Cont>::type
374 , typename boost::remove_reference<Index>::type
375 >
376 {};
377
378 template<typename Cont, typename Index>
379 typename fusion::result_of::at<Cont, Index>::type
380 operator ()(Cont &cont, Index const &) const
381 {
382 return fusion::at<Index>(cont);
383 }
384 };
385
386 // A transform that evaluates a lambda expression.
387 struct LambdaEval
388 : proto::or_<
389 /*<<When you match a placeholder ...>>*/
390 proto::when<
391 proto::terminal<placeholder<_> >
392 /*<<... call at() with the data parameter, which
393 is a tuple, and the placeholder, which is an MPL
394 Integral Constant.>>*/
395 , at(proto::_data, proto::_value)
396 >
397 /*<<Otherwise, use the _default<> transform, which
398 gives the operators their usual C++ meanings.>>*/
399 , proto::otherwise< proto::_default<LambdaEval> >
400 >
401 {};
402
403 // Define the lambda placeholders
404 proto::terminal<placeholder<mpl::int_<0> > >::type const _1 = {{}};
405 proto::terminal<placeholder<mpl::int_<1> > >::type const _2 = {{}};
406
407 void test_lambda()
408 {
409 // a tuple that contains the values
410 // of _1 and _2
411 fusion::tuple<int, int> tup(2,3);
412
413 // Use LambdaEval to evaluate a lambda expression
414 int j = LambdaEval()( _2 - _1, 0, tup );
415 BOOST_CHECK_EQUAL(j, 1);
416
417 // You can mutate leaves in an expression tree
418 proto::literal<int> k(42);
419 int &l = LambdaEval()( k += 4, 0, tup );
420 BOOST_CHECK_EQUAL(k.get(), 46);
421 BOOST_CHECK_EQUAL(&l, &k.get());
422
423 // You can mutate the values in the tuple, too.
424 LambdaEval()( _1 += 4, 0, tup );
425 BOOST_CHECK_EQUAL(6, fusion::at_c<0>(tup));
426 }
427 //]
428 }
429
430 void test_examples()
431 {
432 //[ CalculatorArityTest
433 int i = 0; // not used, dummy state and data parameter
434
435 std::cout << CalculatorArity()( proto::lit(100) * 200, i, i) << '\n';
436 std::cout << CalculatorArity()( (_1 - _1) / _1 * 100, i, i) << '\n';
437 std::cout << CalculatorArity()( (_2 - _1) / _2 * 100, i, i) << '\n';
438 //]
439
440 BOOST_CHECK_EQUAL(0, CalculatorArity()( proto::lit(100) * 200, i, i));
441 BOOST_CHECK_EQUAL(1, CalculatorArity()( (_1 - _1) / _1 * 100, i, i));
442 BOOST_CHECK_EQUAL(2, CalculatorArity()( (_2 - _1) / _2 * 100, i, i));
443
444 BOOST_CHECK_EQUAL(0, CalcArity()( proto::lit(100) * 200, i, i));
445 BOOST_CHECK_EQUAL(1, CalcArity()( (_1 - _1) / _1 * 100, i, i));
446 BOOST_CHECK_EQUAL(2, CalcArity()( (_2 - _1) / _2 * 100, i, i));
447
448 using boost::fusion::cons;
449 using boost::fusion::nil;
450 cons<int, cons<char, cons<std::string> > > args(ArgsAsList()( _1(1, 'a', std::string("b")), i, i ));
451 BOOST_CHECK_EQUAL(args.car, 1);
452 BOOST_CHECK_EQUAL(args.cdr.car, 'a');
453 BOOST_CHECK_EQUAL(args.cdr.cdr.car, std::string("b"));
454
455 cons<int, cons<char, cons<std::string> > > lst(FoldTreeToList()( (_1 = 1, 'a', std::string("b")), i, i ));
456 BOOST_CHECK_EQUAL(lst.car, 1);
457 BOOST_CHECK_EQUAL(lst.cdr.car, 'a');
458 BOOST_CHECK_EQUAL(lst.cdr.cdr.car, std::string("b"));
459
460 proto::plus<
461 proto::terminal<double>::type
462 , proto::terminal<double>::type
463 >::type p = Promote()( proto::lit(1.f) + 2.f, i, i );
464
465 //[ LazyMakePairTest
466 int j = 0; // not used, dummy state and data parameter
467
468 std::pair<int, double> p2 = MakePair()( make_pair_(1, 3.14), j, j );
469
470 std::cout << p2.first << std::endl;
471 std::cout << p2.second << std::endl;
472 //]
473
474 BOOST_CHECK_EQUAL(p2.first, 1);
475 BOOST_CHECK_EQUAL(p2.second, 3.14);
476
477 std::pair<int, double> p3 = lazy_make_pair2::MakePair()( lazy_make_pair2::make_pair_(1, 3.14), j, j );
478
479 std::cout << p3.first << std::endl;
480 std::cout << p3.second << std::endl;
481
482 BOOST_CHECK_EQUAL(p3.first, 1);
483 BOOST_CHECK_EQUAL(p3.second, 3.14);
484
485 NegateInt()(proto::lit(1), i, i);
486 #ifndef BOOST_MSVC
487 SquareAndPromoteInt()(proto::lit(1), i, i);
488 #endif
489
490 lambda_transform::test_lambda();
491 }
492
493 using namespace boost::unit_test;
494 ///////////////////////////////////////////////////////////////////////////////
495 // init_unit_test_suite
496 //
497 test_suite* init_unit_test_suite( int argc, char* argv[] )
498 {
499 test_suite *test = BOOST_TEST_SUITE("test examples from the documentation");
500
501 test->add(BOOST_TEST_CASE(&test_examples));
502
503 return test;
504 }