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