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 | { |
27 | explicit ewrap(E const &e = E()) |
28 | : proto::extends<E, ewrap<E>, mydomain>(e) |
29 | {} |
30 | }; |
31 | |
32 | void test_make_expr() |
33 | { |
34 | int i = 42; |
35 | proto::terminal<int>::type t1 = proto::make_expr<proto::tag::terminal>(a0: 1); |
36 | proto::terminal<int>::type t2 = proto::make_expr<proto::tag::terminal>(a0: i); |
37 | proto::unary_plus<proto::terminal<int>::type>::type p1 = proto::make_expr<proto::tag::unary_plus>(a0: 1); |
38 | proto::unary_plus<proto::terminal<int>::type>::type p2 = proto::make_expr<proto::tag::unary_plus>(a0: 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>(c0: 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>(a0: p3, a1: 0); |
66 | BOOST_CHECK_EQUAL(proto::value(proto::child(proto::left(p4))), 42); |
67 | } |
68 | |
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>(a0: boost::cref(t: ci)); |
74 | proto::terminal<int &>::type t2 = proto::make_expr<proto::tag::terminal>(a0: boost::ref(t&: 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>(a0: boost::cref(t: ci)); |
77 | proto::unary_plus<proto::terminal<int &>::type>::type p2 = proto::make_expr<proto::tag::unary_plus>(a0: boost::ref(t&: 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>(c0: boost::ref(t&: 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>(a0: boost::ref(t&: p3), a1: 0); |
105 | BOOST_CHECK_EQUAL(proto::value(proto::child(proto::left(p4))), 42); |
106 | } |
107 | |
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 | |
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(t: ci)); |
149 | proto::terminal<int &>::type t2 = proto::functional::make_expr<proto::tag::terminal>()(boost::ref(t&: 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(t: ci)); |
152 | proto::unary_plus<proto::terminal<int &>::type>::type p2 = proto::functional::make_expr<proto::tag::unary_plus>()(boost::ref(t&: 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(t&: 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(t&: p3), 0); |
180 | BOOST_CHECK_EQUAL(proto::value(proto::child(proto::left(p4))), 42); |
181 | } |
182 | |
183 | void test_unpack_expr() |
184 | { |
185 | int i = 42; |
186 | proto::terminal<int>::type t1 = proto::unpack_expr<proto::tag::terminal>(sequence: fusion::make_tuple(arg: 1)); |
187 | proto::terminal<int &>::type t2 = proto::unpack_expr<proto::tag::terminal>(sequence: fusion::make_tuple(arg: boost::ref(t&: i))); |
188 | proto::unary_plus<proto::terminal<int>::type>::type p1 = proto::unpack_expr<proto::tag::unary_plus>(sequence: fusion::make_tuple(arg: 1)); |
189 | proto::unary_plus<proto::terminal<int &>::type>::type p2 = proto::unpack_expr<proto::tag::unary_plus>(sequence: fusion::make_tuple(arg: boost::ref(t&: 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>(sequence2: fusion::make_tuple(arg: boost::ref(t&: 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>(sequence: fusion::make_tuple(arg: boost::ref(t&: p3), arg: 0)); |
217 | BOOST_CHECK_EQUAL(proto::value(proto::child(proto::left(p4))), 42); |
218 | } |
219 | |
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(arg: 1)); |
224 | proto::terminal<int &>::type t2 = proto::functional::unpack_expr<proto::tag::terminal>()(fusion::make_tuple(arg: boost::ref(t&: i))); |
225 | proto::unary_plus<proto::terminal<int>::type>::type p1 = proto::functional::unpack_expr<proto::tag::unary_plus>()(fusion::make_tuple(arg: 1)); |
226 | proto::unary_plus<proto::terminal<int &>::type>::type p2 = proto::functional::unpack_expr<proto::tag::unary_plus>()(fusion::make_tuple(arg: boost::ref(t&: 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(arg: boost::ref(t&: 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(arg: boost::ref(t&: p3), arg: 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 | |
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(t: 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(t: 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(t: 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(t: 1) + 1); |
323 | } |
324 | |
325 | |
326 | struct length_impl {}; |
327 | struct dot_impl {}; |
328 | |
329 | proto::terminal<length_impl>::type const length = {.child0: {}}; |
330 | proto::terminal<dot_impl>::type const dot = {.child0: {}}; |
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> |
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 | |
375 | void test_make_expr_transform2() |
376 | { |
377 | test_make_expr_transform2_test(expr: 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 | // |
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 | |