• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 ///////////////////////////////////////////////////////////////////////////////
2 // proto::make_expr.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 <sstream>
9 #include <boost/proto/core.hpp>
10 #include <boost/proto/transform.hpp>
11 #include <boost/utility/addressof.hpp>
12 #include <boost/fusion/tuple.hpp>
13 #include <boost/test/unit_test.hpp>
14 
15 namespace fusion = boost::fusion;
16 namespace proto = boost::proto;
17 
18 template<typename E> struct ewrap;
19 
20 struct mydomain
21   : proto::domain<proto::generator<ewrap> >
22 {};
23 
24 template<typename E> struct ewrap
25   : proto::extends<E, ewrap<E>, mydomain>
26 {
ewrapewrap27     explicit ewrap(E const &e = E())
28       : proto::extends<E, ewrap<E>, mydomain>(e)
29     {}
30 };
31 
test_make_expr()32 void test_make_expr()
33 {
34     int i = 42;
35     proto::terminal<int>::type t1 = proto::make_expr<proto::tag::terminal>(1);
36     proto::terminal<int>::type t2 = proto::make_expr<proto::tag::terminal>(i);
37     proto::unary_plus<proto::terminal<int>::type>::type p1 = proto::make_expr<proto::tag::unary_plus>(1);
38     proto::unary_plus<proto::terminal<int>::type>::type p2 = proto::make_expr<proto::tag::unary_plus>(i);
39     BOOST_CHECK_EQUAL(proto::value(proto::child(p2)), 42);
40 
41     typedef
42         ewrap<
43             proto::basic_expr<
44                 proto::tag::unary_plus
45               , proto::list1<
46                     ewrap<proto::basic_expr<proto::tag::terminal, proto::term<int> > >
47                 >
48             >
49         >
50     p3_type;
51     p3_type p3 = proto::make_expr<proto::tag::unary_plus, mydomain>(i);
52     BOOST_CHECK_EQUAL(proto::value(proto::child(p3)), 42);
53 
54     typedef
55         ewrap<
56             proto::basic_expr<
57                 proto::tag::plus
58               , proto::list2<
59                     p3_type
60                   , ewrap<proto::basic_expr<proto::tag::terminal, proto::term<int> > >
61                 >
62             >
63         >
64     p4_type;
65     p4_type p4 = proto::make_expr<proto::tag::plus>(p3, 0);
66     BOOST_CHECK_EQUAL(proto::value(proto::child(proto::left(p4))), 42);
67 }
68 
test_make_expr_ref()69 void test_make_expr_ref()
70 {
71     int i = 42;
72     int const ci = 84;
73     proto::terminal<int const &>::type t1 = proto::make_expr<proto::tag::terminal>(boost::cref(ci));
74     proto::terminal<int &>::type t2 = proto::make_expr<proto::tag::terminal>(boost::ref(i));
75     BOOST_CHECK_EQUAL(&i, &proto::value(t2));
76     proto::unary_plus<proto::terminal<int const &>::type>::type p1 = proto::make_expr<proto::tag::unary_plus>(boost::cref(ci));
77     proto::unary_plus<proto::terminal<int &>::type>::type p2 = proto::make_expr<proto::tag::unary_plus>(boost::ref(i));
78     BOOST_CHECK_EQUAL(proto::value(proto::child(p2)), 42);
79 
80     typedef
81         ewrap<
82             proto::basic_expr<
83                 proto::tag::unary_plus
84               , proto::list1<
85                     ewrap<proto::basic_expr<proto::tag::terminal, proto::term<int &> > >
86                 >
87             >
88         >
89     p3_type;
90     p3_type p3 = proto::make_expr<proto::tag::unary_plus, mydomain>(boost::ref(i));
91     BOOST_CHECK_EQUAL(proto::value(proto::child(p3)), 42);
92 
93     typedef
94         ewrap<
95             proto::basic_expr<
96                 proto::tag::plus
97               , proto::list2<
98                     p3_type &
99                   , ewrap<proto::basic_expr<proto::tag::terminal, proto::term<int> > >
100                 >
101             >
102         >
103     p4_type;
104     p4_type p4 = proto::make_expr<proto::tag::plus>(boost::ref(p3), 0);
105     BOOST_CHECK_EQUAL(proto::value(proto::child(proto::left(p4))), 42);
106 }
107 
test_make_expr_functional()108 void test_make_expr_functional()
109 {
110     int i = 42;
111     proto::terminal<int>::type t1 = proto::functional::make_expr<proto::tag::terminal>()(1);
112     proto::terminal<int>::type t2 = proto::functional::make_expr<proto::tag::terminal>()(i);
113     proto::unary_plus<proto::terminal<int>::type>::type p1 = proto::functional::make_expr<proto::tag::unary_plus>()(1);
114     proto::unary_plus<proto::terminal<int>::type>::type p2 = proto::functional::make_expr<proto::tag::unary_plus>()(i);
115     BOOST_CHECK_EQUAL(proto::value(proto::child(p2)), 42);
116 
117     typedef
118         ewrap<
119             proto::basic_expr<
120                 proto::tag::unary_plus
121               , proto::list1<
122                     ewrap<proto::basic_expr<proto::tag::terminal, proto::term<int> > >
123                 >
124             >
125         >
126     p3_type;
127     p3_type p3 = proto::functional::make_expr<proto::tag::unary_plus, mydomain>()(i);
128     BOOST_CHECK_EQUAL(proto::value(proto::child(p3)), 42);
129 
130     typedef
131         ewrap<
132             proto::basic_expr<
133                 proto::tag::plus
134               , proto::list2<
135                     p3_type
136                   , ewrap<proto::basic_expr<proto::tag::terminal, proto::term<int> > >
137                 >
138             >
139         >
140     p4_type;
141     p4_type p4 = proto::functional::make_expr<proto::tag::plus>()(p3, 0);
142 }
143 
test_make_expr_functional_ref()144 void test_make_expr_functional_ref()
145 {
146     int i = 42;
147     int const ci = 84;
148     proto::terminal<int const &>::type t1 = proto::functional::make_expr<proto::tag::terminal>()(boost::cref(ci));
149     proto::terminal<int &>::type t2 = proto::functional::make_expr<proto::tag::terminal>()(boost::ref(i));
150     BOOST_CHECK_EQUAL(&i, &proto::value(t2));
151     proto::unary_plus<proto::terminal<int const &>::type>::type p1 = proto::functional::make_expr<proto::tag::unary_plus>()(boost::cref(ci));
152     proto::unary_plus<proto::terminal<int &>::type>::type p2 = proto::functional::make_expr<proto::tag::unary_plus>()(boost::ref(i));
153     BOOST_CHECK_EQUAL(proto::value(proto::child(p2)), 42);
154 
155     typedef
156         ewrap<
157             proto::basic_expr<
158                 proto::tag::unary_plus
159               , proto::list1<
160                     ewrap<proto::basic_expr<proto::tag::terminal, proto::term<int &> > >
161                 >
162             >
163         >
164     p3_type;
165     p3_type p3 = proto::functional::make_expr<proto::tag::unary_plus, mydomain>()(boost::ref(i));
166     BOOST_CHECK_EQUAL(proto::value(proto::child(p3)), 42);
167 
168     typedef
169         ewrap<
170             proto::basic_expr<
171                 proto::tag::plus
172               , proto::list2<
173                     p3_type &
174                   , ewrap<proto::basic_expr<proto::tag::terminal, proto::term<int> > >
175                 >
176             >
177         >
178     p4_type;
179     p4_type p4 = proto::functional::make_expr<proto::tag::plus>()(boost::ref(p3), 0);
180     BOOST_CHECK_EQUAL(proto::value(proto::child(proto::left(p4))), 42);
181 }
182 
test_unpack_expr()183 void test_unpack_expr()
184 {
185     int i = 42;
186     proto::terminal<int>::type t1 = proto::unpack_expr<proto::tag::terminal>(fusion::make_tuple(1));
187     proto::terminal<int &>::type t2 = proto::unpack_expr<proto::tag::terminal>(fusion::make_tuple(boost::ref(i)));
188     proto::unary_plus<proto::terminal<int>::type>::type p1 = proto::unpack_expr<proto::tag::unary_plus>(fusion::make_tuple(1));
189     proto::unary_plus<proto::terminal<int &>::type>::type p2 = proto::unpack_expr<proto::tag::unary_plus>(fusion::make_tuple(boost::ref(i)));
190     BOOST_CHECK_EQUAL(proto::value(proto::child(p2)), 42);
191 
192     typedef
193         ewrap<
194             proto::basic_expr<
195                 proto::tag::unary_plus
196               , proto::list1<
197                     ewrap<proto::basic_expr<proto::tag::terminal, proto::term<int &> > >
198                 >
199             >
200         >
201     p3_type;
202     p3_type p3 = proto::unpack_expr<proto::tag::unary_plus, mydomain>(fusion::make_tuple(boost::ref(i)));
203     BOOST_CHECK_EQUAL(proto::value(proto::child(p3)), 42);
204 
205     typedef
206         ewrap<
207             proto::basic_expr<
208                 proto::tag::plus
209               , proto::list2<
210                     p3_type &
211                   , ewrap<proto::basic_expr<proto::tag::terminal, proto::term<int> > >
212                 >
213             >
214         >
215     p4_type;
216     p4_type p4 = proto::unpack_expr<proto::tag::plus>(fusion::make_tuple(boost::ref(p3), 0));
217     BOOST_CHECK_EQUAL(proto::value(proto::child(proto::left(p4))), 42);
218 }
219 
test_unpack_expr_functional()220 void test_unpack_expr_functional()
221 {
222     int i = 42;
223     proto::terminal<int>::type t1 = proto::functional::unpack_expr<proto::tag::terminal>()(fusion::make_tuple(1));
224     proto::terminal<int &>::type t2 = proto::functional::unpack_expr<proto::tag::terminal>()(fusion::make_tuple(boost::ref(i)));
225     proto::unary_plus<proto::terminal<int>::type>::type p1 = proto::functional::unpack_expr<proto::tag::unary_plus>()(fusion::make_tuple(1));
226     proto::unary_plus<proto::terminal<int &>::type>::type p2 = proto::functional::unpack_expr<proto::tag::unary_plus>()(fusion::make_tuple(boost::ref(i)));
227     BOOST_CHECK_EQUAL(proto::value(proto::child(p2)), 42);
228 
229     typedef
230         ewrap<
231             proto::basic_expr<
232                 proto::tag::unary_plus
233               , proto::list1<
234                     ewrap<proto::basic_expr<proto::tag::terminal, proto::term<int &> > >
235                 >
236             >
237         >
238     p3_type;
239     p3_type p3 = proto::functional::unpack_expr<proto::tag::unary_plus, mydomain>()(fusion::make_tuple(boost::ref(i)));
240     BOOST_CHECK_EQUAL(proto::value(proto::child(p3)), 42);
241 
242     typedef
243         ewrap<
244             proto::basic_expr<
245                 proto::tag::plus
246               , proto::list2<
247                     p3_type &
248                   , ewrap<proto::basic_expr<proto::tag::terminal, proto::term<int> > >
249                 >
250             >
251         >
252     p4_type;
253     p4_type p4 = proto::functional::unpack_expr<proto::tag::plus>()(fusion::make_tuple(boost::ref(p3), 0));
254     BOOST_CHECK_EQUAL(proto::value(proto::child(proto::left(p4))), 42);
255 }
256 
257 #if BOOST_WORKAROUND(BOOST_MSVC, == 1310)
258 #define _byref(x) call<proto::_byref(x)>
259 #define _byval(x) call<proto::_byval(x)>
260 #define Minus(x) proto::call<Minus(x)>
261 #endif
262 
263 // Turn all terminals held by reference into ones held by value
264 struct ByVal
265   : proto::or_<
266         proto::when<proto::terminal<proto::_>, proto::_make_terminal(proto::_byval(proto::_value))>
267       , proto::when<proto::nary_expr<proto::_, proto::vararg<ByVal> > >
268     >
269 {};
270 
271 // Turn all terminals held by value into ones held by reference (not safe in general)
272 struct ByRef
273   : proto::or_<
274         proto::when<proto::terminal<proto::_>, proto::_make_terminal(proto::_byref(proto::_value))>
275       , proto::when<proto::nary_expr<proto::_, proto::vararg<ByRef> > >
276     >
277 {};
278 
279 // turn all proto::plus nodes to minus nodes:
280 struct Minus
281   : proto::or_<
282         proto::when<proto::terminal<proto::_> >
283       , proto::when<proto::plus<Minus, Minus>, proto::_make_minus(Minus(proto::_left), Minus(proto::_right)) >
284     >
285 {};
286 
287 struct Square
288   : proto::or_<
289         // Not creating new proto::terminal nodes here,
290         // so hold the existing terminals by reference:
291         proto::when<proto::terminal<proto::_>, proto::_make_multiplies(proto::_, proto::_)>
292       , proto::when<proto::plus<Square, Square> >
293     >
294 {};
295 
296 #if BOOST_WORKAROUND(BOOST_MSVC, == 1310)
297 #undef _byref
298 #undef _byval
299 #undef Minus
300 #endif
301 
test_make_expr_transform()302 void test_make_expr_transform()
303 {
304     proto::plus<
305         proto::terminal<int>::type
306       , proto::terminal<int>::type
307     >::type t1 = ByVal()(proto::as_expr(1) + 1);
308 
309     proto::plus<
310         proto::terminal<int const &>::type
311       , proto::terminal<int const &>::type
312     >::type t2 = ByRef()(proto::as_expr(1) + 1);
313 
314     proto::minus<
315         proto::terminal<int>::type const &
316       , proto::terminal<int const &>::type const &
317     >::type t3 = Minus()(proto::as_expr(1) + 1);
318 
319     proto::plus<
320         proto::multiplies<proto::terminal<int>::type const &, proto::terminal<int>::type const &>::type
321       , proto::multiplies<proto::terminal<int const &>::type const &, proto::terminal<int const &>::type const &>::type
322     >::type t4 = Square()(proto::as_expr(1) + 1);
323 }
324 
325 
326 struct length_impl {};
327 struct dot_impl {};
328 
329 proto::terminal<length_impl>::type const length = {{}};
330 proto::terminal<dot_impl>::type const dot = {{}};
331 
332 // work around msvc bugs...
333 #if BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1500))
334 #define _byref(a) call<proto::_byref(a)>
335 #define _byval(a) call<proto::_byval(a)>
336 #define _child1(a) call<proto::_child1(a)>
337 #define _make_terminal(a) call<proto::_make_terminal(a)>
338 #define _make_function(a,b,c) call<proto::_make_function(a,b,c)>
339 #define dot_impl() proto::make<dot_impl()>
340 #endif
341 
342 // convert length(a) < length(b) to dot(a,a) < dot(b,b)
343 struct Convert
344   : proto::when<
345         proto::less<
346             proto::function<proto::terminal<length_impl>, proto::_>
347           , proto::function<proto::terminal<length_impl>, proto::_>
348         >
349       , proto::_make_less(
350             proto::_make_function(
351                 proto::_make_terminal(dot_impl())
352               , proto::_child1(proto::_child0)
353               , proto::_child1(proto::_child0)
354             )
355           , proto::_make_function(
356                 proto::_make_terminal(dot_impl())
357               , proto::_child1(proto::_child1)
358               , proto::_child1(proto::_child1)
359             )
360         )
361     >
362 {};
363 
364 template<typename Expr>
test_make_expr_transform2_test(Expr const & expr)365 void test_make_expr_transform2_test(Expr const &expr)
366 {
367     void const *addr1 = boost::addressof(proto::child_c<1>(proto::child_c<0>(expr)));
368     void const *addr2 = boost::addressof(proto::child_c<1>(proto::child_c<0>(Convert()(expr))));
369     BOOST_CHECK_EQUAL(addr1, addr2);
370 
371     BOOST_CHECK_EQUAL(1, proto::value(proto::child_c<1>(proto::child_c<0>(expr))));
372     BOOST_CHECK_EQUAL(1, proto::value(proto::child_c<1>(proto::child_c<0>(Convert()(expr)))));
373 }
374 
test_make_expr_transform2()375 void test_make_expr_transform2()
376 {
377     test_make_expr_transform2_test(length(1) < length(2));
378 }
379 
380 #if BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1500))
381 #undef _byref
382 #undef _byval
383 #undef _child1
384 #undef _make_terminal
385 #undef _make_function
386 #undef dot_impl
387 #endif
388 
389 using namespace boost::unit_test;
390 ///////////////////////////////////////////////////////////////////////////////
391 // init_unit_test_suite
392 //
init_unit_test_suite(int argc,char * argv[])393 test_suite* init_unit_test_suite( int argc, char* argv[] )
394 {
395     test_suite *test = BOOST_TEST_SUITE("test proto::make_expr, proto::unpack_expr and friends");
396 
397     test->add(BOOST_TEST_CASE(&test_make_expr));
398     test->add(BOOST_TEST_CASE(&test_make_expr_ref));
399     test->add(BOOST_TEST_CASE(&test_make_expr_functional));
400     test->add(BOOST_TEST_CASE(&test_make_expr_functional_ref));
401     test->add(BOOST_TEST_CASE(&test_unpack_expr));
402     test->add(BOOST_TEST_CASE(&test_unpack_expr_functional));
403     test->add(BOOST_TEST_CASE(&test_make_expr_transform));
404     test->add(BOOST_TEST_CASE(&test_make_expr_transform2));
405 
406     return test;
407 }
408