1 | // Boost.TypeErasure library |
2 | // |
3 | // Copyright 2015 Steven Watanabe |
4 | // |
5 | // Distributed under the Boost Software License Version 1.0. (See |
6 | // accompanying file LICENSE_1_0.txt or copy at |
7 | // http://www.boost.org/LICENSE_1_0.txt) |
8 | // |
9 | // $Id$ |
10 | |
11 | #include <boost/type_erasure/any.hpp> |
12 | #include <boost/type_erasure/builtin.hpp> |
13 | #include <boost/type_erasure/operators.hpp> |
14 | #include <boost/type_erasure/dynamic_any_cast.hpp> |
15 | #include <boost/type_erasure/any_cast.hpp> |
16 | #include <boost/mpl/vector.hpp> |
17 | #include <boost/mpl/map.hpp> |
18 | |
19 | #define BOOST_TEST_MAIN |
20 | #include <boost/test/unit_test.hpp> |
21 | |
22 | using namespace boost::type_erasure; |
23 | |
24 | template<class T = _self> |
25 | struct common : ::boost::mpl::vector< |
26 | copy_constructible<T>, |
27 | typeid_<T> |
28 | > {}; |
29 | |
30 | struct fixture |
31 | { |
32 | fixture() |
33 | { |
34 | register_binding<common<>, int>(); |
35 | register_binding<incrementable<>, int>(); |
36 | register_binding<addable<_self, _self, _a> >(make_binding<boost::mpl::map<boost::mpl::pair<_self, int>, boost::mpl::pair<_a, int> > >()); |
37 | } |
38 | }; |
39 | |
40 | BOOST_GLOBAL_FIXTURE(fixture); |
41 | |
42 | BOOST_AUTO_TEST_CASE(test_identical) |
43 | { |
44 | any<common<> > x(1); |
45 | any<common<> > y = dynamic_any_cast<any<common<> > >(arg&: x); |
46 | BOOST_CHECK_EQUAL(any_cast<int>(y), 1); |
47 | } |
48 | |
49 | BOOST_AUTO_TEST_CASE(test_downcast) |
50 | { |
51 | any<common<> > x(1); |
52 | typedef any< ::boost::mpl::vector<common<>, incrementable<> > > incrementable_any; |
53 | incrementable_any y = dynamic_any_cast<incrementable_any>(arg&: x); |
54 | ++y; |
55 | BOOST_CHECK_EQUAL(any_cast<int>(y), 2); |
56 | } |
57 | |
58 | BOOST_AUTO_TEST_CASE(test_cross_cast) |
59 | { |
60 | any< ::boost::mpl::vector<common<>, decrementable<> > > x(1); |
61 | typedef any< ::boost::mpl::vector<common<>, incrementable<> > > incrementable_any; |
62 | incrementable_any y = dynamic_any_cast<incrementable_any>(arg&: x); |
63 | ++y; |
64 | BOOST_CHECK_EQUAL(any_cast<int>(y), 2); |
65 | } |
66 | |
67 | BOOST_AUTO_TEST_CASE(test_cast_placeholder) |
68 | { |
69 | any<common<> > x(1); |
70 | typedef any< ::boost::mpl::vector<common<_a>, incrementable<_a> >, _a> incrementable_any; |
71 | incrementable_any y = dynamic_any_cast<incrementable_any>(arg&: x); |
72 | ++y; |
73 | BOOST_CHECK_EQUAL(any_cast<int>(y), 2); |
74 | } |
75 | |
76 | BOOST_AUTO_TEST_CASE(test_throw) |
77 | { |
78 | any<common<> > x("42" ); |
79 | typedef any< ::boost::mpl::vector<common<_a>, incrementable<_a> >, _a> incrementable_any; |
80 | BOOST_CHECK_THROW(dynamic_any_cast<incrementable_any>(x), bad_any_cast); |
81 | } |
82 | |
83 | // make sure that a function registered with _self can |
84 | // be found with _a. |
85 | BOOST_AUTO_TEST_CASE(test_other_placeholder) |
86 | { |
87 | any<common<_a>, _a> x(1); |
88 | typedef any< ::boost::mpl::vector<common<_a>, incrementable<_a> >, _a> incrementable_any; |
89 | incrementable_any y = dynamic_any_cast<incrementable_any>(arg&: x); |
90 | ++y; |
91 | BOOST_CHECK_EQUAL(any_cast<int>(y), 2); |
92 | } |
93 | |
94 | // Casting to a value only requires the target to provide |
95 | // a copy constructor. |
96 | BOOST_AUTO_TEST_CASE(test_add_copy) |
97 | { |
98 | any< ::boost::mpl::vector<destructible<>, typeid_<> > > x(1); |
99 | any<common<> > y = dynamic_any_cast<any<common<> > >(arg&: x); |
100 | BOOST_CHECK_EQUAL(any_cast<int>(y), 1); |
101 | } |
102 | |
103 | template<class T, class U> |
104 | struct choose_second |
105 | { |
106 | typedef U type; |
107 | }; |
108 | |
109 | BOOST_AUTO_TEST_CASE(test_deduced) |
110 | { |
111 | typedef deduced<choose_second<_self, int> > _p2; |
112 | any< ::boost::mpl::vector<common<>, common<_p2> > > x(1); |
113 | typedef ::boost::mpl::vector<common<>, common<_p2>, incrementable<_p2>, addable<_self, _self, _p2> > dest_concept; |
114 | any<dest_concept> y = dynamic_any_cast<any<dest_concept> >(arg&: x); |
115 | any<dest_concept, _p2> z = y + y; |
116 | ++z; |
117 | BOOST_CHECK_EQUAL(any_cast<int>(z), 3); |
118 | } |
119 | |
120 | BOOST_AUTO_TEST_CASE(test_multiple_placeholders) |
121 | { |
122 | typedef ::boost::mpl::map< ::boost::mpl::pair<_a, int>, boost::mpl::pair<_b, int> > init_map; |
123 | any< ::boost::mpl::vector<common<_a>, common<_b> >, _a> x(1, make_binding<init_map>()); |
124 | typedef ::boost::mpl::vector<common<_a>, common<_b>, incrementable<_b>, addable<_a, _a, _b> > dest_concept; |
125 | typedef ::boost::mpl::map< ::boost::mpl::pair<_a, _a>, ::boost::mpl::pair<_b, _b> > placeholder_map; |
126 | any<dest_concept, _a> y = dynamic_any_cast<any<dest_concept, _a> >(arg&: x, map: make_binding<placeholder_map>()); |
127 | any<dest_concept, _b> z = y + y; |
128 | ++z; |
129 | BOOST_CHECK_EQUAL(any_cast<int>(z), 3); |
130 | } |
131 | |
132 | BOOST_AUTO_TEST_CASE(test_multiple_placeholders_switch) |
133 | { |
134 | typedef ::boost::mpl::map< ::boost::mpl::pair<_a, int>, boost::mpl::pair<_b, int> > init_map; |
135 | any< ::boost::mpl::vector<common<_a>, common<_b> >, _a> x(1, make_binding<init_map>()); |
136 | typedef ::boost::mpl::vector<common<_c>, common<_d>, incrementable<_d>, addable<_c, _c, _d> > dest_concept; |
137 | typedef ::boost::mpl::map< ::boost::mpl::pair<_c, _a>, ::boost::mpl::pair<_d, _b> > placeholder_map; |
138 | any<dest_concept, _c> y = dynamic_any_cast<any<dest_concept, _c> >(arg&: x, map: make_binding<placeholder_map>()); |
139 | any<dest_concept, _d> z = y + y; |
140 | ++z; |
141 | BOOST_CHECK_EQUAL(any_cast<int>(z), 3); |
142 | } |
143 | |
144 | template<class T> |
145 | T as_rvalue(const T& arg) { return arg; } |
146 | template<class T> |
147 | const T& as_const(const T& arg) { return arg; } |
148 | |
149 | BOOST_AUTO_TEST_CASE(test_val) |
150 | { |
151 | any<common<> > x(1); |
152 | // value |
153 | any<common<> > y1 = dynamic_any_cast<any<common<> > >(arg&: x); |
154 | BOOST_CHECK_EQUAL(any_cast<int>(x), any_cast<int>(y1)); |
155 | any<common<> > y2 = dynamic_any_cast<any<common<> > >(arg: as_rvalue(arg: x)); |
156 | BOOST_CHECK_EQUAL(any_cast<int>(x), any_cast<int>(y2)); |
157 | any<common<> > y3 = dynamic_any_cast<any<common<> > >(arg: as_const(arg: x)); |
158 | BOOST_CHECK_EQUAL(any_cast<int>(x), any_cast<int>(y3)); |
159 | |
160 | // lvalue reference |
161 | any<common<>, _self&> r(x); |
162 | any<common<> > z1 = dynamic_any_cast<any<common<> > >(arg&: r); |
163 | BOOST_CHECK_EQUAL(any_cast<int>(x), any_cast<int>(z1)); |
164 | any<common<> > z2 = dynamic_any_cast<any<common<> > >(arg: as_rvalue(arg: r)); |
165 | BOOST_CHECK_EQUAL(any_cast<int>(x), any_cast<int>(z2)); |
166 | any<common<> > z3 = dynamic_any_cast<any<common<> > >(arg: as_const(arg: r)); |
167 | BOOST_CHECK_EQUAL(any_cast<int>(x), any_cast<int>(z3)); |
168 | |
169 | // const reference |
170 | any<common<>, const _self&> cr(x); |
171 | any<common<> > w1 = dynamic_any_cast<any<common<> > >(arg&: cr); |
172 | BOOST_CHECK_EQUAL(any_cast<int>(x), any_cast<int>(w1)); |
173 | any<common<> > w2 = dynamic_any_cast<any<common<> > >(arg: as_rvalue(arg: cr)); |
174 | BOOST_CHECK_EQUAL(any_cast<int>(x), any_cast<int>(w2)); |
175 | any<common<> > w3 = dynamic_any_cast<any<common<> > >(arg: as_const(arg: cr)); |
176 | BOOST_CHECK_EQUAL(any_cast<int>(x), any_cast<int>(w3)); |
177 | |
178 | #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES |
179 | // rvalue reference |
180 | any<common<>, _self&&> rr(std::move(x)); |
181 | any<common<> > v1 = dynamic_any_cast<any<common<> > >(arg&: rr); |
182 | BOOST_CHECK_EQUAL(any_cast<int>(x), any_cast<int>(v1)); |
183 | any<common<> > v2 = dynamic_any_cast<any<common<> > >(arg: as_rvalue(arg: rr)); |
184 | BOOST_CHECK_EQUAL(any_cast<int>(x), any_cast<int>(v2)); |
185 | any<common<> > v3 = dynamic_any_cast<any<common<> > >(arg: as_const(arg: rr)); |
186 | BOOST_CHECK_EQUAL(any_cast<int>(x), any_cast<int>(v3)); |
187 | #endif |
188 | } |
189 | |
190 | BOOST_AUTO_TEST_CASE(test_ref) |
191 | { |
192 | // A non-const reference can only bind to a few cases |
193 | any<common<> > x(1); |
194 | any<common<>, _self&> y = dynamic_any_cast<any<common<>, _self&> >(arg&: x); |
195 | BOOST_CHECK_EQUAL(any_cast<int*>(&x), any_cast<int*>(&y)); |
196 | |
197 | any<common<>, _self&> z = dynamic_any_cast<any<common<>, _self&> >(arg&: y); |
198 | BOOST_CHECK_EQUAL(any_cast<int*>(&x), any_cast<int*>(&z)); |
199 | any<common<>, _self&> w = dynamic_any_cast<any<common<>, _self&> >(arg: as_rvalue(arg: y)); |
200 | BOOST_CHECK_EQUAL(any_cast<int*>(&x), any_cast<int*>(&w)); |
201 | any<common<>, _self&> v = dynamic_any_cast<any<common<>, _self&> >(arg: as_const(arg: y)); |
202 | BOOST_CHECK_EQUAL(any_cast<int*>(&x), any_cast<int*>(&v)); |
203 | } |
204 | |
205 | BOOST_AUTO_TEST_CASE(test_cref) |
206 | { |
207 | any<common<> > x(1); |
208 | typedef any<common<>, const _self&> dest_type; |
209 | |
210 | // value |
211 | dest_type y1 = dynamic_any_cast<dest_type>(arg&: x); |
212 | BOOST_CHECK_EQUAL(any_cast<const int*>(&x), any_cast<const int*>(&y1)); |
213 | // as_rvalue creates a temporary |
214 | BOOST_CHECK_EQUAL(any_cast<int>(x), any_cast<int>(dynamic_any_cast<dest_type>(as_rvalue(x)))); |
215 | dest_type y3 = dynamic_any_cast<dest_type>(arg: as_const(arg: x)); |
216 | BOOST_CHECK_EQUAL(any_cast<const int*>(&x), any_cast<const int*>(&y3)); |
217 | |
218 | // lvalue reference |
219 | any<common<>, _self&> r(x); |
220 | dest_type z1 = dynamic_any_cast<dest_type>(arg&: r); |
221 | BOOST_CHECK_EQUAL(any_cast<const int*>(&x), any_cast<const int*>(&z1)); |
222 | dest_type z2 = dynamic_any_cast<dest_type>(arg: as_rvalue(arg: r)); |
223 | BOOST_CHECK_EQUAL(any_cast<const int*>(&x), any_cast<const int*>(&z2)); |
224 | dest_type z3 = dynamic_any_cast<dest_type>(arg: as_const(arg: r)); |
225 | BOOST_CHECK_EQUAL(any_cast<const int*>(&x), any_cast<const int*>(&z3)); |
226 | |
227 | // const reference |
228 | any<common<>, const _self&> cr(x); |
229 | dest_type w1 = dynamic_any_cast<dest_type>(arg&: cr); |
230 | BOOST_CHECK_EQUAL(any_cast<const int*>(&x), any_cast<const int*>(&w1)); |
231 | dest_type w2 = dynamic_any_cast<dest_type>(arg: as_rvalue(arg: cr)); |
232 | BOOST_CHECK_EQUAL(any_cast<const int*>(&x), any_cast<const int*>(&w2)); |
233 | dest_type w3 = dynamic_any_cast<dest_type>(arg: as_const(arg: cr)); |
234 | BOOST_CHECK_EQUAL(any_cast<const int*>(&x), any_cast<const int*>(&w3)); |
235 | |
236 | #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES |
237 | // rvalue reference |
238 | any<common<>, _self&&> rr(std::move(x)); |
239 | dest_type v1 = dynamic_any_cast<dest_type>(arg&: rr); |
240 | BOOST_CHECK_EQUAL(any_cast<const int*>(&x), any_cast<const int*>(&v1)); |
241 | dest_type v2 = dynamic_any_cast<dest_type>(arg: as_rvalue(arg: rr)); |
242 | BOOST_CHECK_EQUAL(any_cast<const int*>(&x), any_cast<const int*>(&v2)); |
243 | dest_type v3 = dynamic_any_cast<dest_type>(arg: as_const(arg: rr)); |
244 | BOOST_CHECK_EQUAL(any_cast<const int*>(&x), any_cast<const int*>(&v3)); |
245 | #endif |
246 | } |
247 | |
248 | #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES |
249 | |
250 | BOOST_AUTO_TEST_CASE(test_rref) |
251 | { |
252 | any<common<> > x(1); |
253 | typedef any<common<>, _self&&> dest_type; |
254 | |
255 | // value |
256 | dest_type y2 = dynamic_any_cast<dest_type>(arg: std::move(x)); |
257 | BOOST_CHECK_EQUAL(any_cast<int*>(&x), any_cast<int*>(&y2)); |
258 | |
259 | // rvalue reference |
260 | any<common<>, _self&&> rr(std::move(x)); |
261 | dest_type v2 = dynamic_any_cast<dest_type>(arg: std::move(rr)); |
262 | BOOST_CHECK_EQUAL(any_cast<int*>(&x), any_cast<int*>(&v2)); |
263 | } |
264 | |
265 | #endif |
266 | |