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
15std::ostream &operator <<(std::ostream &sout, boost::proto::tag::shift_right)
16{
17 return sout << ">>";
18}
19
20std::ostream &operator <<(std::ostream &sout, boost::proto::tag::bitwise_or)
21{
22 return sout << "|";
23}
24
25template<typename Args>
26std::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
31template<typename Args>
32std::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
37template<typename Tag, typename Args>
38std::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
43template<typename Tag, typename Args>
44std::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
49template<typename Tag, typename Args>
50std::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
55template<typename Tag, typename Args>
56std::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//
64struct 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 }
75private:
76 std::ostream &sout_;
77};
78
79void 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
134template<typename Expr>
135struct My;
136
137struct MyDomain
138 : boost::proto::domain<boost::proto::pod_generator<My> >
139{};
140
141template<typename Expr>
142struct My
143{
144 BOOST_PROTO_EXTENDS(Expr, My<Expr>, MyDomain)
145};
146
147void 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
199using namespace boost::unit_test;
200///////////////////////////////////////////////////////////////////////////////
201// init_unit_test_suite
202//
203test_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

source code of boost/libs/proto/test/flatten.cpp