1 | // |
2 | // Copyright Chris Glover, 2016. |
3 | // |
4 | // Distributed under the Boost Software License, Version 1.0. (See |
5 | // accompanying file LICENSE_1_0.txt or copy at |
6 | // http://www.boost.org/LICENSE_1_0.txt) |
7 | |
8 | // #include <boost/type_index/runtime_cast.hpp> |
9 | // #include <boost/type_index/runtime_reference_cast.hpp> |
10 | |
11 | #include <boost/type_index/runtime_cast.hpp> |
12 | #include <boost/type_index/runtime_cast/boost_shared_ptr_cast.hpp> |
13 | #include <boost/smart_ptr/make_shared.hpp> |
14 | |
15 | #include <boost/core/lightweight_test.hpp> |
16 | |
17 | #if !defined(BOOST_NO_CXX11_SMART_PTR) |
18 | # include <boost/type_index/runtime_cast/std_shared_ptr_cast.hpp> |
19 | #endif |
20 | |
21 | // Classes include a member variable "name" with the |
22 | // name of the class hard coded so we can be sure that |
23 | // the pointer offsets are all working, since we're doing |
24 | // a cast from void* at some point. |
25 | |
26 | #define IMPLEMENT_CLASS(type_name) \ |
27 | type_name() : name( #type_name ) {} \ |
28 | std::string name; |
29 | |
30 | struct base { |
31 | BOOST_TYPE_INDEX_IMPLEMENT_RUNTIME_CAST() |
32 | IMPLEMENT_CLASS(base) |
33 | }; |
34 | |
35 | struct single_derived : base { |
36 | BOOST_TYPE_INDEX_IMPLEMENT_RUNTIME_CAST(base) |
37 | IMPLEMENT_CLASS(single_derived) |
38 | }; |
39 | |
40 | struct base1 { |
41 | BOOST_TYPE_INDEX_IMPLEMENT_RUNTIME_CAST() |
42 | IMPLEMENT_CLASS(base1) |
43 | }; |
44 | |
45 | struct base2 { |
46 | BOOST_TYPE_INDEX_IMPLEMENT_RUNTIME_CAST() |
47 | IMPLEMENT_CLASS(base2) |
48 | }; |
49 | |
50 | struct multiple_derived : base1, base2 { |
51 | BOOST_TYPE_INDEX_IMPLEMENT_RUNTIME_CAST(base1, base2) |
52 | IMPLEMENT_CLASS(multiple_derived) |
53 | }; |
54 | |
55 | struct baseV1 : virtual base { |
56 | BOOST_TYPE_INDEX_IMPLEMENT_RUNTIME_CAST(base) |
57 | IMPLEMENT_CLASS(baseV1) |
58 | }; |
59 | |
60 | struct baseV2 : virtual base { |
61 | BOOST_TYPE_INDEX_IMPLEMENT_RUNTIME_CAST(base) |
62 | IMPLEMENT_CLASS(baseV2) |
63 | }; |
64 | |
65 | struct multiple_virtual_derived : baseV1, baseV2 { |
66 | BOOST_TYPE_INDEX_IMPLEMENT_RUNTIME_CAST(baseV1, baseV2) |
67 | IMPLEMENT_CLASS(multiple_virtual_derived) |
68 | }; |
69 | |
70 | struct unrelated { |
71 | BOOST_TYPE_INDEX_IMPLEMENT_RUNTIME_CAST() |
72 | IMPLEMENT_CLASS(unrelated) |
73 | }; |
74 | |
75 | struct unrelated_with_base : base { |
76 | BOOST_TYPE_INDEX_IMPLEMENT_RUNTIME_CAST(base) |
77 | IMPLEMENT_CLASS(unrelated_with_base) |
78 | }; |
79 | |
80 | struct unrelatedV1 : virtual base { |
81 | BOOST_TYPE_INDEX_IMPLEMENT_RUNTIME_CAST(base) |
82 | IMPLEMENT_CLASS(unrelatedV1) |
83 | }; |
84 | |
85 | struct level1_a : base { |
86 | BOOST_TYPE_INDEX_IMPLEMENT_RUNTIME_CAST(base) |
87 | IMPLEMENT_CLASS(level1_a) |
88 | }; |
89 | |
90 | struct level1_b : base { |
91 | BOOST_TYPE_INDEX_IMPLEMENT_RUNTIME_CAST(base) |
92 | IMPLEMENT_CLASS(level1_b) |
93 | }; |
94 | |
95 | struct level2 : level1_a, level1_b { |
96 | BOOST_TYPE_INDEX_IMPLEMENT_RUNTIME_CAST(level1_a, level1_b) |
97 | IMPLEMENT_CLASS(level2) |
98 | }; |
99 | |
100 | struct reg_base { |
101 | BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS() |
102 | }; |
103 | |
104 | struct reg_derived : reg_base { |
105 | BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS(reg_base) |
106 | }; |
107 | |
108 | void no_base() |
109 | { |
110 | using namespace boost::typeindex; |
111 | base b; |
112 | base* b2 = runtime_pointer_cast<base>(u: &b); |
113 | BOOST_TEST_NE(b2, (base*)NULL); |
114 | BOOST_TEST_EQ(b2->name, "base" ); |
115 | |
116 | BOOST_TEST_EQ(runtime_pointer_cast<unrelated>(&b), (unrelated*)NULL); |
117 | BOOST_TEST_EQ(runtime_pointer_cast<single_derived>(&b), (single_derived*)NULL); |
118 | BOOST_TEST_EQ(runtime_pointer_cast<unrelatedV1>(&b), (unrelatedV1*)NULL); |
119 | BOOST_TEST_EQ(runtime_pointer_cast<unrelated_with_base>(&b), (unrelated_with_base*)NULL); |
120 | } |
121 | |
122 | void single_base() |
123 | { |
124 | using namespace boost::typeindex; |
125 | single_derived d; |
126 | base* b = &d; |
127 | single_derived* d2 = runtime_pointer_cast<single_derived>(u: b); |
128 | BOOST_TEST_NE(d2, (single_derived*)NULL); |
129 | BOOST_TEST_EQ(d2->name, "single_derived" ); |
130 | |
131 | BOOST_TEST_EQ(runtime_pointer_cast<unrelated>(&d), (unrelated*)NULL); |
132 | BOOST_TEST_EQ(runtime_pointer_cast<unrelated>(b), (unrelated*)NULL); |
133 | BOOST_TEST_EQ(runtime_pointer_cast<unrelated_with_base>(b), (unrelated_with_base*)NULL); |
134 | } |
135 | |
136 | void multiple_base() |
137 | { |
138 | using namespace boost::typeindex; |
139 | multiple_derived d; |
140 | base1* b1 = &d; |
141 | multiple_derived* d2 = runtime_pointer_cast<multiple_derived>(u: b1); |
142 | BOOST_TEST_NE(d2, (multiple_derived*)NULL); |
143 | BOOST_TEST_EQ(d2->name, "multiple_derived" ); |
144 | |
145 | base2* b2 = runtime_pointer_cast<base2>(u: b1); |
146 | BOOST_TEST_NE(b2, (base2*)NULL); |
147 | BOOST_TEST_EQ(b2->name, "base2" ); |
148 | |
149 | BOOST_TEST_EQ(runtime_pointer_cast<unrelated>(&d), (unrelated*)NULL); |
150 | BOOST_TEST_EQ(runtime_pointer_cast<unrelated>(b1), (unrelated*)NULL); |
151 | BOOST_TEST_EQ(runtime_pointer_cast<unrelated_with_base>(b1), (unrelated_with_base*)NULL); |
152 | } |
153 | |
154 | void virtual_base() |
155 | { |
156 | using namespace boost::typeindex; |
157 | multiple_virtual_derived d; |
158 | base* b = &d; |
159 | multiple_virtual_derived* d2 = runtime_pointer_cast<multiple_virtual_derived>(u: b); |
160 | baseV1* bv1 = runtime_pointer_cast<baseV1>(u: b); |
161 | baseV2* bv2 = runtime_pointer_cast<baseV2>(u: b); |
162 | |
163 | BOOST_TEST_NE(d2, (multiple_virtual_derived*)NULL); |
164 | BOOST_TEST_EQ(d2->name, "multiple_virtual_derived" ); |
165 | |
166 | BOOST_TEST_NE(bv1, (baseV1*)NULL); |
167 | BOOST_TEST_EQ(bv1->name, "baseV1" ); |
168 | |
169 | BOOST_TEST_NE(bv2, (baseV2*)NULL); |
170 | BOOST_TEST_EQ(bv2->name, "baseV2" ); |
171 | |
172 | BOOST_TEST_EQ(runtime_pointer_cast<unrelated>(b), (unrelated*)NULL); |
173 | BOOST_TEST_EQ(runtime_pointer_cast<unrelated>(&d), (unrelated*)NULL); |
174 | BOOST_TEST_EQ(runtime_pointer_cast<unrelated_with_base>(b), (unrelated_with_base*)NULL); |
175 | } |
176 | |
177 | void pointer_interface() |
178 | { |
179 | using namespace boost::typeindex; |
180 | single_derived d; |
181 | base* b = &d; |
182 | single_derived* d2 = runtime_cast<single_derived*>(u: b); |
183 | BOOST_TEST_NE(d2, (single_derived*)NULL); |
184 | BOOST_TEST_EQ(d2->name, "single_derived" ); |
185 | BOOST_TEST_EQ(runtime_pointer_cast<unrelated>(b), (unrelated*)NULL); |
186 | } |
187 | |
188 | void reference_interface() |
189 | { |
190 | using namespace boost::typeindex; |
191 | single_derived d; |
192 | base& b = d; |
193 | single_derived& d2 = runtime_cast<single_derived&>(u&: b); |
194 | BOOST_TEST_EQ(d2.name, "single_derived" ); |
195 | |
196 | try { |
197 | unrelated& u = runtime_cast<unrelated&>(u&: b); |
198 | (void)u; |
199 | BOOST_TEST(!"should throw bad_runtime_cast" ); |
200 | } |
201 | catch(boost::typeindex::bad_runtime_cast&) { |
202 | } |
203 | catch(...) { |
204 | BOOST_TEST(!"should throw bad_runtime_cast" ); |
205 | } |
206 | } |
207 | |
208 | void const_pointer_interface() |
209 | { |
210 | using namespace boost::typeindex; |
211 | const single_derived d; |
212 | base const* b = &d; |
213 | single_derived const* d2 = runtime_cast<single_derived const*>(u: b); |
214 | BOOST_TEST_NE(d2, (single_derived*)NULL); |
215 | BOOST_TEST_EQ(d2->name, "single_derived" ); |
216 | BOOST_TEST_EQ(runtime_pointer_cast<unrelated>(b), (unrelated*)NULL); |
217 | } |
218 | |
219 | void const_reference_interface() |
220 | { |
221 | using namespace boost::typeindex; |
222 | const single_derived d; |
223 | base const& b = d; |
224 | single_derived const& d2 = runtime_cast<single_derived const&>(u: b); |
225 | BOOST_TEST_EQ(d2.name, "single_derived" ); |
226 | |
227 | try { |
228 | unrelated const& u = runtime_cast<unrelated const&>(u: b); |
229 | (void)u; |
230 | BOOST_TEST(!"should throw bad_runtime_cast" ); |
231 | } |
232 | catch(boost::typeindex::bad_runtime_cast&) { |
233 | } |
234 | catch(...) { |
235 | BOOST_TEST(!"should throw bad_runtime_cast" ); |
236 | } |
237 | } |
238 | |
239 | void diamond_non_virtual() |
240 | { |
241 | using namespace boost::typeindex; |
242 | level2 inst; |
243 | level1_a* l1a = &inst; |
244 | base* b1 = l1a; |
245 | level1_b* l1_b = runtime_cast<level1_b*>(u: b1); |
246 | BOOST_TEST_NE(l1_b, (level1_b*)NULL); |
247 | BOOST_TEST_EQ(l1_b->name, "level1_b" ); |
248 | } |
249 | |
250 | void boost_shared_ptr() |
251 | { |
252 | using namespace boost::typeindex; |
253 | boost::shared_ptr<single_derived> d = boost::make_shared<single_derived>(); |
254 | boost::shared_ptr<base> b = d; |
255 | boost::shared_ptr<single_derived> d2 = runtime_pointer_cast<single_derived>(u: b); |
256 | BOOST_TEST_NE(d2, boost::shared_ptr<single_derived>()); |
257 | BOOST_TEST_EQ(d2->name, "single_derived" ); |
258 | } |
259 | |
260 | void std_shared_ptr() |
261 | { |
262 | #if !defined(BOOST_NO_CXX11_SMART_PTR) |
263 | using namespace boost::typeindex; |
264 | std::shared_ptr<single_derived> d = std::make_shared<single_derived>(); |
265 | std::shared_ptr<base> b = d; |
266 | std::shared_ptr<single_derived> d2 = runtime_pointer_cast<single_derived>(u: b); |
267 | BOOST_TEST_NE(d2, std::shared_ptr<single_derived>()); |
268 | BOOST_TEST_EQ(d2->name, "single_derived" ); |
269 | #endif |
270 | } |
271 | |
272 | void register_runtime_class() |
273 | { |
274 | using namespace boost::typeindex; |
275 | reg_derived rd; |
276 | reg_base* rb = &rd; |
277 | reg_derived* prd = runtime_pointer_cast<reg_derived>(u: rb); |
278 | BOOST_TEST_NE(prd, (reg_derived*)NULL); |
279 | BOOST_TEST_EQ(type_id_runtime(*prd), type_id<reg_derived>()); |
280 | } |
281 | |
282 | int main() { |
283 | no_base(); |
284 | single_derived(); |
285 | multiple_base(); |
286 | virtual_base(); |
287 | pointer_interface(); |
288 | reference_interface(); |
289 | const_pointer_interface(); |
290 | const_reference_interface(); |
291 | diamond_non_virtual(); |
292 | boost_shared_ptr(); |
293 | std_shared_ptr(); |
294 | register_runtime_class(); |
295 | return boost::report_errors(); |
296 | } |
297 | |