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
operator <<(std::ostream & sout,boost::proto::tag::shift_right)15 std::ostream &operator <<(std::ostream &sout, boost::proto::tag::shift_right)
16 {
17 return sout << ">>";
18 }
19
operator <<(std::ostream & sout,boost::proto::tag::bitwise_or)20 std::ostream &operator <<(std::ostream &sout, boost::proto::tag::bitwise_or)
21 {
22 return sout << "|";
23 }
24
25 template<typename Args>
operator <<(std::ostream & sout,boost::proto::expr<boost::proto::tag::terminal,Args,0> const * op)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>
operator <<(std::ostream & sout,boost::proto::basic_expr<boost::proto::tag::terminal,Args,0> const * op)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>
operator <<(std::ostream & sout,boost::proto::expr<Tag,Args,1> const * op)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>
operator <<(std::ostream & sout,boost::proto::basic_expr<Tag,Args,1> const * op)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>
operator <<(std::ostream & sout,boost::proto::expr<Tag,Args,2> const * op)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>
operator <<(std::ostream & sout,boost::proto::basic_expr<Tag,Args,2> const * op)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 {
to_stringto_string66 to_string(std::ostream &sout)
67 : sout_(sout)
68 {}
69
70 template<typename Op>
operator ()to_string71 void operator ()(Op const &op) const
72 {
73 this->sout_ << '(' << boost::addressof(op.proto_base()) << ')';
74 }
75 private:
76 std::ostream &sout_;
77 };
78
test1()79 void test1()
80 {
81 using boost::proto::flatten;
82
83 boost::proto::terminal<char>::type a_ = {'a'};
84 boost::proto::terminal<char>::type b_ = {'b'};
85 boost::proto::terminal<char>::type c_ = {'c'};
86 boost::proto::terminal<char>::type d_ = {'d'};
87 boost::proto::terminal<char>::type e_ = {'e'};
88 boost::proto::terminal<char>::type f_ = {'f'};
89 boost::proto::terminal<char>::type g_ = {'g'};
90 boost::proto::terminal<char>::type h_ = {'h'};
91 boost::proto::terminal<char>::type i_ = {'i'};
92
93 std::stringstream sout;
94
95 // Test for 1-way branching "tree"
96 sout.str("");
97 boost::fusion::for_each(flatten(!!!!(a_ >> b_)), to_string(sout));
98 BOOST_CHECK_EQUAL("(a>>b)", sout.str());
99
100 // Tests for 2-way branching trees
101 sout.str("");
102 boost::fusion::for_each(flatten(a_ >> b_ >> c_), to_string(sout));
103 BOOST_CHECK_EQUAL("(a)(b)(c)", sout.str());
104
105 sout.str("");
106 boost::fusion::for_each(flatten(a_ | b_ | c_), to_string(sout));
107 BOOST_CHECK_EQUAL("(a)(b)(c)", sout.str());
108
109 sout.str("");
110 boost::fusion::for_each(flatten(a_ >> b_ | c_ >> d_), to_string(sout));
111 BOOST_CHECK_EQUAL("(a>>b)(c>>d)", sout.str());
112
113 sout.str("");
114 boost::fusion::for_each(flatten(a_ | b_ >> c_ | d_), to_string(sout));
115 BOOST_CHECK_EQUAL("(a)(b>>c)(d)", sout.str());
116
117 sout.str("");
118 boost::fusion::for_each(flatten(a_ >> b_ | c_ >> d_ | e_ >> f_ >> g_), to_string(sout));
119 BOOST_CHECK_EQUAL("(a>>b)(c>>d)(e>>f>>g)", sout.str());
120
121 sout.str("");
122 boost::fusion::for_each(flatten(a_ >> b_ | c_ >> d_ | e_ >> (f_ | g_) >> h_), 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("");
127 boost::fusion::for_each(flatten(a_(b_(c_ >> d_, e_ | f_), g_ >> h_)(i_)), 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
test2()147 void test2()
148 {
149 using boost::proto::flatten;
150
151 My<boost::proto::terminal<char>::type> a_ = {{'a'}};
152 My<boost::proto::terminal<char>::type> b_ = {{'b'}};
153 My<boost::proto::terminal<char>::type> c_ = {{'c'}};
154 My<boost::proto::terminal<char>::type> d_ = {{'d'}};
155 My<boost::proto::terminal<char>::type> e_ = {{'e'}};
156 My<boost::proto::terminal<char>::type> f_ = {{'f'}};
157 My<boost::proto::terminal<char>::type> g_ = {{'g'}};
158 My<boost::proto::terminal<char>::type> h_ = {{'h'}};
159 My<boost::proto::terminal<char>::type> i_ = {{'i'}};
160
161 std::stringstream sout;
162
163 // Test for 1-way branching "tree"
164 sout.str("");
165 boost::fusion::for_each(flatten(!!!!(a_ >> b_)), to_string(sout));
166 BOOST_CHECK_EQUAL("(a>>b)", sout.str());
167
168 // Tests for 2-way branching trees
169 sout.str("");
170 boost::fusion::for_each(flatten(a_ >> b_ >> c_), to_string(sout));
171 BOOST_CHECK_EQUAL("(a)(b)(c)", sout.str());
172
173 sout.str("");
174 boost::fusion::for_each(flatten(a_ | b_ | c_), to_string(sout));
175 BOOST_CHECK_EQUAL("(a)(b)(c)", sout.str());
176
177 sout.str("");
178 boost::fusion::for_each(flatten(a_ >> b_ | c_ >> d_), to_string(sout));
179 BOOST_CHECK_EQUAL("(a>>b)(c>>d)", sout.str());
180
181 sout.str("");
182 boost::fusion::for_each(flatten(a_ | b_ >> c_ | d_), to_string(sout));
183 BOOST_CHECK_EQUAL("(a)(b>>c)(d)", sout.str());
184
185 sout.str("");
186 boost::fusion::for_each(flatten(a_ >> b_ | c_ >> d_ | e_ >> f_ >> g_), to_string(sout));
187 BOOST_CHECK_EQUAL("(a>>b)(c>>d)(e>>f>>g)", sout.str());
188
189 sout.str("");
190 boost::fusion::for_each(flatten(a_ >> b_ | c_ >> d_ | e_ >> (f_ | g_) >> h_), 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("");
195 boost::fusion::for_each(flatten(a_(b_(c_ >> d_, e_ | f_), g_ >> h_)(i_)), 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 //
init_unit_test_suite(int argc,char * argv[])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