1 | /////////////////////////////////////////////////////////////////////////////// |
2 | // proto_fusion_s.cpp |
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/core.hpp> |
9 | #include <boost/proto/fusion.hpp> |
10 | #include <boost/fusion/include/for_each.hpp> |
11 | #include <boost/test/unit_test.hpp> |
12 | #include <boost/utility/addressof.hpp> |
13 | #include <sstream> |
14 | |
15 | std::ostream &operator <<(std::ostream &sout, boost::proto::tag::shift_right) |
16 | { |
17 | return sout << ">>" ; |
18 | } |
19 | |
20 | std::ostream &operator <<(std::ostream &sout, boost::proto::tag::bitwise_or) |
21 | { |
22 | return sout << "|" ; |
23 | } |
24 | |
25 | template<typename Args> |
26 | std::ostream &operator <<(std::ostream &sout, boost::proto::expr<boost::proto::tag::terminal, Args, 0> const *op) |
27 | { |
28 | return sout << boost::proto::value(*op); |
29 | } |
30 | |
31 | template<typename Args> |
32 | std::ostream &operator <<(std::ostream &sout, boost::proto::basic_expr<boost::proto::tag::terminal, Args, 0> const *op) |
33 | { |
34 | return sout << boost::proto::value(*op); |
35 | } |
36 | |
37 | template<typename Tag, typename Args> |
38 | std::ostream &operator <<(std::ostream &sout, boost::proto::expr<Tag, Args, 1> const *op) |
39 | { |
40 | return sout << Tag() << boost::addressof(boost::proto::child(*op).proto_base()); |
41 | } |
42 | |
43 | template<typename Tag, typename Args> |
44 | std::ostream &operator <<(std::ostream &sout, boost::proto::basic_expr<Tag, Args, 1> const *op) |
45 | { |
46 | return sout << Tag() << boost::addressof(boost::proto::child(*op).proto_base()); |
47 | } |
48 | |
49 | template<typename Tag, typename Args> |
50 | std::ostream &operator <<(std::ostream &sout, boost::proto::expr<Tag, Args, 2> const *op) |
51 | { |
52 | return sout << boost::addressof(boost::proto::left(*op).proto_base()) << Tag() << boost::addressof(boost::proto::right(*op).proto_base()); |
53 | } |
54 | |
55 | template<typename Tag, typename Args> |
56 | std::ostream &operator <<(std::ostream &sout, boost::proto::basic_expr<Tag, Args, 2> const *op) |
57 | { |
58 | return sout << boost::addressof(boost::proto::left(*op).proto_base()) << Tag() << boost::addressof(boost::proto::right(*op).proto_base()); |
59 | } |
60 | |
61 | /////////////////////////////////////////////////////////////////////////////// |
62 | // to_string |
63 | // |
64 | struct to_string |
65 | { |
66 | to_string(std::ostream &sout) |
67 | : sout_(sout) |
68 | {} |
69 | |
70 | template<typename Op> |
71 | void operator ()(Op const &op) const |
72 | { |
73 | this->sout_ << '(' << boost::addressof(op.proto_base()) << ')'; |
74 | } |
75 | private: |
76 | std::ostream &sout_; |
77 | }; |
78 | |
79 | void test1() |
80 | { |
81 | using boost::proto::flatten; |
82 | |
83 | boost::proto::terminal<char>::type a_ = {.child0: 'a'}; |
84 | boost::proto::terminal<char>::type b_ = {.child0: 'b'}; |
85 | boost::proto::terminal<char>::type c_ = {.child0: 'c'}; |
86 | boost::proto::terminal<char>::type d_ = {.child0: 'd'}; |
87 | boost::proto::terminal<char>::type e_ = {.child0: 'e'}; |
88 | boost::proto::terminal<char>::type f_ = {.child0: 'f'}; |
89 | boost::proto::terminal<char>::type g_ = {.child0: 'g'}; |
90 | boost::proto::terminal<char>::type h_ = {.child0: 'h'}; |
91 | boost::proto::terminal<char>::type i_ = {.child0: 'i'}; |
92 | |
93 | std::stringstream sout; |
94 | |
95 | // Test for 1-way branching "tree" |
96 | sout.str(s: "" ); |
97 | boost::fusion::for_each(seq: flatten(e: !!!!(a_ >> b_)), f: to_string(sout)); |
98 | BOOST_CHECK_EQUAL("(a>>b)" , sout.str()); |
99 | |
100 | // Tests for 2-way branching trees |
101 | sout.str(s: "" ); |
102 | boost::fusion::for_each(seq: flatten(e: a_ >> b_ >> c_), f: to_string(sout)); |
103 | BOOST_CHECK_EQUAL("(a)(b)(c)" , sout.str()); |
104 | |
105 | sout.str(s: "" ); |
106 | boost::fusion::for_each(seq: flatten(e: a_ | b_ | c_), f: to_string(sout)); |
107 | BOOST_CHECK_EQUAL("(a)(b)(c)" , sout.str()); |
108 | |
109 | sout.str(s: "" ); |
110 | boost::fusion::for_each(seq: flatten(e: a_ >> b_ | c_ >> d_), f: to_string(sout)); |
111 | BOOST_CHECK_EQUAL("(a>>b)(c>>d)" , sout.str()); |
112 | |
113 | sout.str(s: "" ); |
114 | boost::fusion::for_each(seq: flatten(e: a_ | b_ >> c_ | d_), f: to_string(sout)); |
115 | BOOST_CHECK_EQUAL("(a)(b>>c)(d)" , sout.str()); |
116 | |
117 | sout.str(s: "" ); |
118 | boost::fusion::for_each(seq: flatten(e: a_ >> b_ | c_ >> d_ | e_ >> f_ >> g_), f: to_string(sout)); |
119 | BOOST_CHECK_EQUAL("(a>>b)(c>>d)(e>>f>>g)" , sout.str()); |
120 | |
121 | sout.str(s: "" ); |
122 | boost::fusion::for_each(seq: flatten(e: a_ >> b_ | c_ >> d_ | e_ >> (f_ | g_) >> h_), f: to_string(sout)); |
123 | BOOST_CHECK_EQUAL("(a>>b)(c>>d)(e>>f|g>>h)" , sout.str()); |
124 | |
125 | // Test for n-way branching tree |
126 | sout.str(s: "" ); |
127 | boost::fusion::for_each(seq: flatten(e: a_(b_(c_ >> d_, e_ | f_), g_ >> h_)(i_)), f: to_string(sout)); |
128 | BOOST_CHECK_EQUAL("(a)(b)(c>>d)(e|f)(g>>h)(i)" , sout.str()); |
129 | } |
130 | |
131 | //////////////////////////////////////////////////////////////////////// |
132 | // Test that EXTENDS expression wrappers are also valid fusion sequences |
133 | |
134 | template<typename Expr> |
135 | struct My; |
136 | |
137 | struct MyDomain |
138 | : boost::proto::domain<boost::proto::pod_generator<My> > |
139 | {}; |
140 | |
141 | template<typename Expr> |
142 | struct My |
143 | { |
144 | BOOST_PROTO_EXTENDS(Expr, My<Expr>, MyDomain) |
145 | }; |
146 | |
147 | void test2() |
148 | { |
149 | using boost::proto::flatten; |
150 | |
151 | My<boost::proto::terminal<char>::type> a_ = {.proto_expr_: {.child0: 'a'}}; |
152 | My<boost::proto::terminal<char>::type> b_ = {.proto_expr_: {.child0: 'b'}}; |
153 | My<boost::proto::terminal<char>::type> c_ = {.proto_expr_: {.child0: 'c'}}; |
154 | My<boost::proto::terminal<char>::type> d_ = {.proto_expr_: {.child0: 'd'}}; |
155 | My<boost::proto::terminal<char>::type> e_ = {.proto_expr_: {.child0: 'e'}}; |
156 | My<boost::proto::terminal<char>::type> f_ = {.proto_expr_: {.child0: 'f'}}; |
157 | My<boost::proto::terminal<char>::type> g_ = {.proto_expr_: {.child0: 'g'}}; |
158 | My<boost::proto::terminal<char>::type> h_ = {.proto_expr_: {.child0: 'h'}}; |
159 | My<boost::proto::terminal<char>::type> i_ = {.proto_expr_: {.child0: 'i'}}; |
160 | |
161 | std::stringstream sout; |
162 | |
163 | // Test for 1-way branching "tree" |
164 | sout.str(s: "" ); |
165 | boost::fusion::for_each(seq: flatten(e: !!!!(a_ >> b_)), f: to_string(sout)); |
166 | BOOST_CHECK_EQUAL("(a>>b)" , sout.str()); |
167 | |
168 | // Tests for 2-way branching trees |
169 | sout.str(s: "" ); |
170 | boost::fusion::for_each(seq: flatten(e: a_ >> b_ >> c_), f: to_string(sout)); |
171 | BOOST_CHECK_EQUAL("(a)(b)(c)" , sout.str()); |
172 | |
173 | sout.str(s: "" ); |
174 | boost::fusion::for_each(seq: flatten(e: a_ | b_ | c_), f: to_string(sout)); |
175 | BOOST_CHECK_EQUAL("(a)(b)(c)" , sout.str()); |
176 | |
177 | sout.str(s: "" ); |
178 | boost::fusion::for_each(seq: flatten(e: a_ >> b_ | c_ >> d_), f: to_string(sout)); |
179 | BOOST_CHECK_EQUAL("(a>>b)(c>>d)" , sout.str()); |
180 | |
181 | sout.str(s: "" ); |
182 | boost::fusion::for_each(seq: flatten(e: a_ | b_ >> c_ | d_), f: to_string(sout)); |
183 | BOOST_CHECK_EQUAL("(a)(b>>c)(d)" , sout.str()); |
184 | |
185 | sout.str(s: "" ); |
186 | boost::fusion::for_each(seq: flatten(e: a_ >> b_ | c_ >> d_ | e_ >> f_ >> g_), f: to_string(sout)); |
187 | BOOST_CHECK_EQUAL("(a>>b)(c>>d)(e>>f>>g)" , sout.str()); |
188 | |
189 | sout.str(s: "" ); |
190 | boost::fusion::for_each(seq: flatten(e: a_ >> b_ | c_ >> d_ | e_ >> (f_ | g_) >> h_), f: to_string(sout)); |
191 | BOOST_CHECK_EQUAL("(a>>b)(c>>d)(e>>f|g>>h)" , sout.str()); |
192 | |
193 | // Test for n-way branching tree |
194 | sout.str(s: "" ); |
195 | boost::fusion::for_each(seq: flatten(e: a_(b_(c_ >> d_, e_ | f_), g_ >> h_)(i_)), f: to_string(sout)); |
196 | BOOST_CHECK_EQUAL("(a)(b)(c>>d)(e|f)(g>>h)(i)" , sout.str()); |
197 | } |
198 | |
199 | using namespace boost::unit_test; |
200 | /////////////////////////////////////////////////////////////////////////////// |
201 | // init_unit_test_suite |
202 | // |
203 | test_suite* init_unit_test_suite( int argc, char* argv[] ) |
204 | { |
205 | test_suite *test = BOOST_TEST_SUITE("test proto and segmented fusion integration" ); |
206 | |
207 | test->add(BOOST_TEST_CASE(&test1)); |
208 | test->add(BOOST_TEST_CASE(&test2)); |
209 | |
210 | return test; |
211 | } |
212 | |