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(BOOST_TYPE_INDEX_NO_BASE_CLASS)
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(BOOST_TYPE_INDEX_NO_BASE_CLASS)
42 IMPLEMENT_CLASS(base1)
43 };
44
45 struct base2 {
46 BOOST_TYPE_INDEX_IMPLEMENT_RUNTIME_CAST(BOOST_TYPE_INDEX_NO_BASE_CLASS)
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(BOOST_TYPE_INDEX_NO_BASE_CLASS)
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(BOOST_TYPE_INDEX_NO_BASE_CLASS)
102 };
103
104 struct reg_derived : reg_base {
105 BOOST_TYPE_INDEX_REGISTER_RUNTIME_CLASS((reg_base))
106 };
107
no_base()108 void no_base()
109 {
110 using namespace boost::typeindex;
111 base b;
112 base* b2 = runtime_pointer_cast<base>(&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
single_base()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>(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
multiple_base()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>(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>(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
virtual_base()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>(b);
160 baseV1* bv1 = runtime_pointer_cast<baseV1>(b);
161 baseV2* bv2 = runtime_pointer_cast<baseV2>(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
pointer_interface()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*>(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
reference_interface()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&>(b);
194 BOOST_TEST_EQ(d2.name, "single_derived");
195
196 try {
197 unrelated& u = runtime_cast<unrelated&>(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
const_pointer_interface()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*>(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
const_reference_interface()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&>(b);
225 BOOST_TEST_EQ(d2.name, "single_derived");
226
227 try {
228 unrelated const& u = runtime_cast<unrelated const&>(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
diamond_non_virtual()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*>(b1);
246 BOOST_TEST_NE(l1_b, (level1_b*)NULL);
247 BOOST_TEST_EQ(l1_b->name, "level1_b");
248 }
249
boost_shared_ptr()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>(b);
256 BOOST_TEST_NE(d2, boost::shared_ptr<single_derived>());
257 BOOST_TEST_EQ(d2->name, "single_derived");
258 }
259
std_shared_ptr()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>(b);
267 BOOST_TEST_NE(d2, std::shared_ptr<single_derived>());
268 BOOST_TEST_EQ(d2->name, "single_derived");
269 #endif
270 }
271
register_runtime_class()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>(rb);
278 BOOST_TEST_NE(prd, (reg_derived*)NULL);
279 BOOST_TEST_EQ(type_id_runtime(*prd), type_id<reg_derived>());
280 }
281
main()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