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