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