lambda.cpp 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. ///////////////////////////////////////////////////////////////////////////////
  2. // lambda.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 <sstream>
  8. #include <boost/mpl/int.hpp>
  9. #include <boost/mpl/min_max.hpp>
  10. #include <boost/mpl/eval_if.hpp>
  11. #include <boost/mpl/identity.hpp>
  12. #include <boost/mpl/next_prior.hpp>
  13. #include <boost/fusion/tuple.hpp>
  14. #include <boost/typeof/typeof.hpp>
  15. #include <boost/typeof/std/sstream.hpp>
  16. #include <boost/typeof/std/ostream.hpp>
  17. #include <boost/typeof/std/iostream.hpp>
  18. #include <boost/type_traits/add_const.hpp>
  19. #include <boost/type_traits/add_reference.hpp>
  20. #include <boost/proto/core.hpp>
  21. #include <boost/proto/context.hpp>
  22. #include <boost/proto/transform.hpp>
  23. #include <boost/test/unit_test.hpp>
  24. #include <boost/test/floating_point_comparison.hpp>
  25. using namespace boost;
  26. // Forward declaration of the lambda expression wrapper
  27. template<typename T>
  28. struct lambda;
  29. struct lambda_domain
  30. : proto::domain<proto::pod_generator<lambda> >
  31. {};
  32. template<typename I>
  33. struct placeholder
  34. {
  35. typedef I arity;
  36. };
  37. template<typename T>
  38. struct placeholder_arity
  39. {
  40. typedef typename T::arity type;
  41. };
  42. namespace grammar
  43. {
  44. using namespace proto;
  45. // The lambda grammar, with the transforms for calculating the max arity
  46. struct Lambda
  47. : or_<
  48. when< terminal< placeholder<_> >, mpl::next<placeholder_arity<_value> >() >
  49. , when< terminal<_>, mpl::int_<0>() >
  50. , when< nary_expr<_, vararg<_> >, fold<_, mpl::int_<0>(), mpl::max<Lambda,_state>()> >
  51. >
  52. {};
  53. }
  54. // simple wrapper for calculating a lambda expression's arity.
  55. template<typename Expr>
  56. struct lambda_arity
  57. : boost::result_of<grammar::Lambda(Expr, mpl::void_, mpl::void_)>
  58. {};
  59. // The lambda context is the same as the default context
  60. // with the addition of special handling for lambda placeholders
  61. template<typename Tuple>
  62. struct lambda_context
  63. : proto::callable_context<lambda_context<Tuple> const>
  64. {
  65. lambda_context(Tuple const &args)
  66. : args_(args)
  67. {}
  68. template<typename Sig>
  69. struct result;
  70. template<typename This, typename I>
  71. struct result<This(proto::tag::terminal, placeholder<I> const &)>
  72. : fusion::result_of::at<Tuple, I>
  73. {};
  74. template<typename I>
  75. typename fusion::result_of::at<Tuple, I>::type
  76. operator ()(proto::tag::terminal, placeholder<I> const &) const
  77. {
  78. return fusion::at<I>(this->args_);
  79. }
  80. Tuple args_;
  81. };
  82. // The lambda<> expression wrapper makes expressions polymorphic
  83. // function objects
  84. template<typename T>
  85. struct lambda
  86. {
  87. BOOST_PROTO_BASIC_EXTENDS(T, lambda<T>, lambda_domain)
  88. BOOST_PROTO_EXTENDS_ASSIGN()
  89. BOOST_PROTO_EXTENDS_SUBSCRIPT()
  90. // Careful not to evaluate the return type of the nullary function
  91. // unless we have a nullary lambda!
  92. typedef typename mpl::eval_if<
  93. typename lambda_arity<T>::type
  94. , mpl::identity<void>
  95. , proto::result_of::eval<T const, lambda_context<fusion::tuple<> > >
  96. >::type nullary_type;
  97. // Define our operator () that evaluates the lambda expression.
  98. nullary_type operator ()() const
  99. {
  100. fusion::tuple<> args;
  101. lambda_context<fusion::tuple<> > ctx(args);
  102. return proto::eval(*this, ctx);
  103. }
  104. #define M0(N, typename_A, A_const_ref, A_const_ref_a, ref_a) \
  105. template<typename_A(N)> \
  106. typename proto::result_of::eval<T const, lambda_context<fusion::tuple<A_const_ref(N)> > >::type \
  107. operator ()(A_const_ref_a(N)) const \
  108. { \
  109. fusion::tuple<A_const_ref(N)> args(ref_a(N)); \
  110. lambda_context<fusion::tuple<A_const_ref(N)> > ctx(args); \
  111. return proto::eval(*this, ctx); \
  112. } \
  113. /**/
  114. BOOST_PROTO_REPEAT_FROM_TO(1, 4, M0)
  115. #undef M0
  116. };
  117. // Define some lambda placeholders
  118. lambda<proto::terminal<placeholder<mpl::int_<0> > >::type> const _1 = {{}};
  119. lambda<proto::terminal<placeholder<mpl::int_<1> > >::type> const _2 = {{}};
  120. lambda<proto::terminal<placeholder<mpl::int_<3> > >::type> const _3 = {{}};
  121. template<typename T>
  122. lambda<typename proto::terminal<T>::type> const val(T const &t)
  123. {
  124. lambda<typename proto::terminal<T>::type> that = {{t}};
  125. return that;
  126. }
  127. template<typename T>
  128. lambda<typename proto::terminal<T &>::type> const var(T &t)
  129. {
  130. lambda<typename proto::terminal<T &>::type> that = {{t}};
  131. return that;
  132. }
  133. void test_lambda()
  134. {
  135. BOOST_CHECK_EQUAL(11, ( (_1 + 2) / 4 )(42));
  136. BOOST_CHECK_EQUAL(-11, ( (-(_1 + 2)) / 4 )(42));
  137. BOOST_CHECK_CLOSE(2.58, ( (4 - _2) * 3 )(42, 3.14), 0.1);
  138. // check non-const ref terminals
  139. std::stringstream sout;
  140. (sout << _1 << " -- " << _2)(42, "Life, the Universe and Everything!");
  141. BOOST_CHECK_EQUAL("42 -- Life, the Universe and Everything!", sout.str());
  142. // check nullary lambdas
  143. BOOST_CHECK_EQUAL(3, (val(1) + val(2))());
  144. // check array indexing for kicks
  145. int integers[5] = {0};
  146. (var(integers)[2] = 2)();
  147. (var(integers)[_1] = _1)(3);
  148. BOOST_CHECK_EQUAL(2, integers[2]);
  149. BOOST_CHECK_EQUAL(3, integers[3]);
  150. }
  151. using namespace unit_test;
  152. ///////////////////////////////////////////////////////////////////////////////
  153. // init_unit_test_suite
  154. //
  155. test_suite* init_unit_test_suite( int argc, char* argv[] )
  156. {
  157. test_suite *test = BOOST_TEST_SUITE("test expression template domains");
  158. test->add(BOOST_TEST_CASE(&test_lambda));
  159. return test;
  160. }