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
30struct base {
31 BOOST_TYPE_INDEX_IMPLEMENT_RUNTIME_CAST()
32 IMPLEMENT_CLASS(base)
33};
34
35struct single_derived : base {
36 BOOST_TYPE_INDEX_IMPLEMENT_RUNTIME_CAST(base)
37 IMPLEMENT_CLASS(single_derived)
38};
39
40struct base1 {
41 BOOST_TYPE_INDEX_IMPLEMENT_RUNTIME_CAST()
42 IMPLEMENT_CLASS(base1)
43};
44
45struct base2 {
46 BOOST_TYPE_INDEX_IMPLEMENT_RUNTIME_CAST()
47 IMPLEMENT_CLASS(base2)
48};
49
50struct multiple_derived : base1, base2 {
51 BOOST_TYPE_INDEX_IMPLEMENT_RUNTIME_CAST(base1, base2)
52 IMPLEMENT_CLASS(multiple_derived)
53};
54
55struct baseV1 : virtual base {
56 BOOST_TYPE_INDEX_IMPLEMENT_RUNTIME_CAST(base)
57 IMPLEMENT_CLASS(baseV1)
58};
59
60struct baseV2 : virtual base {
61 BOOST_TYPE_INDEX_IMPLEMENT_RUNTIME_CAST(base)
62 IMPLEMENT_CLASS(baseV2)
63};
64
65struct multiple_virtual_derived : baseV1, baseV2 {
66 BOOST_TYPE_INDEX_IMPLEMENT_RUNTIME_CAST(baseV1, baseV2)
67 IMPLEMENT_CLASS(multiple_virtual_derived)
68};
69
70struct unrelated {
71 BOOST_TYPE_INDEX_IMPLEMENT_RUNTIME_CAST()
72 IMPLEMENT_CLASS(unrelated)
73};
74
75struct unrelated_with_base : base {
76 BOOST_TYPE_INDEX_IMPLEMENT_RUNTIME_CAST(base)
77 IMPLEMENT_CLASS(unrelated_with_base)
78};
79
80struct unrelatedV1 : virtual base {
81 BOOST_TYPE_INDEX_IMPLEMENT_RUNTIME_CAST(base)
82 IMPLEMENT_CLASS(unrelatedV1)
83};
84
85struct level1_a : base {
86 BOOST_TYPE_INDEX_IMPLEMENT_RUNTIME_CAST(base)
87 IMPLEMENT_CLASS(level1_a)
88};
89
90struct level1_b : base {
91 BOOST_TYPE_INDEX_IMPLEMENT_RUNTIME_CAST(base)
92 IMPLEMENT_CLASS(level1_b)
93};
94
95struct level2 : level1_a, level1_b {
96 BOOST_TYPE_INDEX_IMPLEMENT_RUNTIME_CAST(level1_a, level1_b)
97 IMPLEMENT_CLASS(level2)
98};
99
100struct reg_base {
101 BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS()
102};
103
104struct reg_derived : reg_base {
105 BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS(reg_base)
106};
107
108void 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
122void 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
136void 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
154void 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
177void 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
188void 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
208void 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
219void 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
239void 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
250void 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
260void 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
272void 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
282int 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

source code of boost/libs/type_index/test/type_index_runtime_cast_test.cpp