examples.cpp 16 KB

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