• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 ///////////////////////////////////////////////////////////////////////////////
2 // pack_expansion.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 <boost/proto/proto.hpp>
9 #include <boost/test/unit_test.hpp>
10 #include <boost/typeof/typeof.hpp>
11 
12 namespace mpl = boost::mpl;
13 namespace proto = boost::proto;
14 using proto::_;
15 
16 template<typename T> T declval();
17 
18 struct eval_ : proto::callable
19 {
20     template<typename Sig>
21     struct result;
22 
23 #define UNARY_OP(TAG, OP)                                                       \
24     template<typename This, typename Arg>                                       \
25     struct result<This(proto::tag::TAG, Arg)>                                   \
26     {                                                                           \
27         BOOST_TYPEOF_NESTED_TYPEDEF_TPL(nested, (OP declval<Arg>()))            \
28         typedef typename nested::type type;                                     \
29     };                                                                          \
30                                                                                 \
31     template<typename Arg>                                                      \
32     typename result<eval_(proto::tag::TAG, Arg)>::type                          \
33     operator()(proto::tag::TAG, Arg arg) const                                  \
34     {                                                                           \
35         return OP arg;                                                          \
36     }                                                                           \
37     /**/
38 
39 #define BINARY_OP(TAG, OP)                                                      \
40     template<typename This, typename Left, typename Right>                      \
41     struct result<This(proto::tag::TAG, Left, Right)>                           \
42     {                                                                           \
43         BOOST_TYPEOF_NESTED_TYPEDEF_TPL(nested, (declval<Left>() OP declval<Right>())) \
44         typedef typename nested::type type;                                     \
45     };                                                                          \
46                                                                                 \
47     template<typename Left, typename Right>                                     \
48     typename result<eval_(proto::tag::TAG, Left, Right)>::type                  \
49     operator()(proto::tag::TAG, Left left, Right right) const                   \
50     {                                                                           \
51         return left OP right;                                                   \
52     }                                                                           \
53     /**/
54 
55     UNARY_OP(negate, -)
56     BINARY_OP(plus, +)
57     BINARY_OP(minus, -)
58     BINARY_OP(multiplies, *)
59     BINARY_OP(divides, /)
60     /*... others ...*/
61 };
62 
63 struct eval1
64   : proto::or_<
65         proto::when<proto::terminal<_>, proto::_value>
66       , proto::otherwise<eval_(proto::tag_of<_>(), eval1(proto::pack(_))...)>
67     >
68 {};
69 
70 struct eval2
71   : proto::or_<
72         proto::when<proto::terminal<_>, proto::_value>
73       , proto::otherwise<proto::call<eval_(proto::tag_of<_>(), eval2(proto::pack(_))...)> >
74     >
75 {};
76 
test_call_pack()77 void test_call_pack()
78 {
79     proto::terminal<int>::type i = {42};
80     int res = eval1()(i);
81     BOOST_CHECK_EQUAL(res, 42);
82     res = eval1()(i + 2);
83     BOOST_CHECK_EQUAL(res, 44);
84     res = eval1()(i * 2);
85     BOOST_CHECK_EQUAL(res, 84);
86     res = eval1()(i * 2 + 4);
87     BOOST_CHECK_EQUAL(res, 88);
88 
89     res = eval2()(i + 2);
90     BOOST_CHECK_EQUAL(res, 44);
91     res = eval2()(i * 2);
92     BOOST_CHECK_EQUAL(res, 84);
93     res = eval2()(i * 2 + 4);
94     BOOST_CHECK_EQUAL(res, 88);
95 }
96 
97 struct make_pair
98   : proto::when<
99         proto::binary_expr<_, proto::terminal<int>, proto::terminal<int> >
100       , std::pair<int, int>(proto::_value(proto::pack(_))...)
101     >
102 {};
103 
test_make_pack()104 void test_make_pack()
105 {
106     proto::terminal<int>::type i = {42};
107     std::pair<int, int> p = make_pair()(i + 43);
108     BOOST_CHECK_EQUAL(p.first, 42);
109     BOOST_CHECK_EQUAL(p.second, 43);
110 }
111 
112 using namespace boost::unit_test;
113 ///////////////////////////////////////////////////////////////////////////////
114 // init_unit_test_suite
115 //
init_unit_test_suite(int argc,char * argv[])116 test_suite* init_unit_test_suite( int argc, char* argv[] )
117 {
118     test_suite *test = BOOST_TEST_SUITE("test immediate evaluation of proto parse trees");
119 
120     test->add(BOOST_TEST_CASE(&test_call_pack));
121     test->add(BOOST_TEST_CASE(&test_make_pack));
122 
123     return test;
124 }
125