Ticket #3604: void_cast.hpp

File void_cast.hpp, 8.6 KB (added by Robert Ramey, 13 years ago)
Line 
1#ifndef BOOST_SERIALIZATION_VOID_CAST_HPP
2#define BOOST_SERIALIZATION_VOID_CAST_HPP
3
4// MS compatible compilers support #pragma once
5#if defined(_MSC_VER) && (_MSC_VER >= 1020)
6# pragma once
7#endif
8
9/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
10// void_cast.hpp: interface for run-time casting of void pointers.
11
12// (C) Copyright 2002-2009 Robert Ramey - http://www.rrsd.com .
13// Use, modification and distribution is subject to the Boost Software
14// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
15// http://www.boost.org/LICENSE_1_0.txt)
16// gennadiy.rozental@tfn.com
17
18// See http://www.boost.org for updates, documentation, and revision history.
19
20#include <cstddef> // for ptrdiff_t
21#include <boost/noncopyable.hpp>
22
23#include <boost/serialization/config.hpp>
24#include <boost/serialization/smart_cast.hpp>
25#include <boost/serialization/singleton.hpp>
26#include <boost/serialization/force_include.hpp>
27#include <boost/serialization/type_info_implementation.hpp>
28#include <boost/serialization/extended_type_info.hpp>
29#include <boost/type_traits/is_virtual_base_of.hpp>
30#include <boost/serialization/void_cast_fwd.hpp>
31
32#include <boost/config/abi_prefix.hpp> // must be the last header
33
34#ifdef BOOST_MSVC
35# pragma warning(push)
36# pragma warning(disable : 4251 4231 4660 4275)
37#endif
38
39namespace boost {
40namespace serialization {
41
42class extended_type_info;
43
44// Given a void *, assume that it really points to an instance of one type
45// and alter it so that it would point to an instance of a related type.
46// Return the altered pointer. If there exists no sequence of casts that
47// can transform from_type to to_type, return a NULL.
48
49BOOST_SERIALIZATION_DECL(void const *)
50void_upcast(
51 extended_type_info const & derived,
52 extended_type_info const & base,
53 void const * const t
54);
55
56inline void *
57void_upcast(
58 extended_type_info const & derived,
59 extended_type_info const & base,
60 void * const t
61){
62 return const_cast<void*>(void_upcast(
63 derived,
64 base,
65 const_cast<void const *>(t)
66 ));
67}
68
69BOOST_SERIALIZATION_DECL(void const *)
70void_downcast(
71 extended_type_info const & derived,
72 extended_type_info const & base,
73 void const * const t
74);
75
76inline void *
77void_downcast(
78 extended_type_info const & derived,
79 extended_type_info const & base,
80 void * const t
81){
82 return const_cast<void*>(void_downcast(
83 derived,
84 base,
85 const_cast<void const *>(t)
86 ));
87}
88
89namespace void_cast_detail {
90
91class BOOST_SERIALIZATION_DECL(BOOST_PP_EMPTY()) void_caster :
92 private boost::noncopyable
93{
94 friend
95 BOOST_SERIALIZATION_DECL(void const *)
96 boost::serialization::void_upcast(
97 extended_type_info const & derived,
98 extended_type_info const & base,
99 void const * const
100 );
101 friend
102 BOOST_SERIALIZATION_DECL(void const *)
103 boost::serialization::void_downcast(
104 extended_type_info const & derived,
105 extended_type_info const & base,
106 void const * const
107 );
108protected:
109 void recursive_register(bool includes_virtual_base = false) const;
110 void recursive_unregister() const;
111 virtual bool has_virtual_base() const = 0;
112public:
113 // Data members
114 const extended_type_info * m_derived;
115 const extended_type_info * m_base;
116 /*const*/ std::ptrdiff_t m_difference;
117 void_caster const * const m_parent;
118
119 // note that void_casters are keyed on value of
120 // member extended type info records - NOT their
121 // addresses. This is necessary in order for the
122 // void cast operations to work across dll and exe
123 // module boundries.
124 bool operator<(const void_caster & rhs) const;
125
126 const void_caster & operator*(){
127 return *this;
128 }
129 // each derived class must re-implement these;
130 virtual void const * upcast(void const * const t) const = 0;
131 virtual void const * downcast(void const * const t) const = 0;
132 // Constructor
133 void_caster(
134 extended_type_info const * derived,
135 extended_type_info const * base,
136 std::ptrdiff_t difference = 0,
137 void_caster const * const parent = 0
138 ) :
139 m_derived(derived),
140 m_base(base),
141 m_difference(difference),
142 m_parent(parent)
143 {}
144 virtual ~void_caster(){}
145};
146
147#ifdef BOOST_MSVC
148# pragma warning(push)
149# pragma warning(disable : 4251 4231 4660 4275 4511 4512)
150#endif
151
152template <class Derived, class Base>
153class void_caster_primitive :
154 public void_caster
155{
156 virtual void const * downcast(void const * const t) const {
157 const Derived * d =
158 boost::serialization::smart_cast<const Derived *, const Base *>(
159 static_cast<const Base *>(t)
160 );
161 return d;
162 }
163 virtual void const * upcast(void const * const t) const {
164 const Base * b =
165 boost::serialization::smart_cast<const Base *, const Derived *>(
166 static_cast<const Derived *>(t)
167 );
168 return b;
169 }
170 virtual bool has_virtual_base() const {
171 return false;
172 }
173public:
174 void_caster_primitive();
175 virtual ~void_caster_primitive();
176};
177
178template <class Derived, class Base>
179void_caster_primitive<Derived, Base>::void_caster_primitive() :
180 void_caster(
181 & type_info_implementation<Derived>::type::get_const_instance(),
182 & type_info_implementation<Base>::type::get_const_instance(),
183 // note:I wanted to display from 0 here, but at least one compiler
184 // treated 0 by not shifting it at all.
185 reinterpret_cast<std::ptrdiff_t>(
186 static_cast<Derived *>(
187 reinterpret_cast<Base *>(1)
188 )
189 ) - 1
190 )
191{
192 recursive_register();
193}
194
195template <class Derived, class Base>
196void_caster_primitive<Derived, Base>::~void_caster_primitive(){
197 recursive_unregister();
198}
199
200template <class Derived, class Base>
201class void_caster_virtual_base :
202 public void_caster
203{
204 virtual bool has_virtual_base() const {
205 return true;
206 }
207public:
208 virtual void const * downcast(void const * const t) const {
209 const Derived * d =
210 dynamic_cast<const Derived *>(
211 static_cast<const Base *>(t)
212 );
213 return d;
214 }
215 virtual void const * upcast(void const * const t) const {
216 const Base * b =
217 dynamic_cast<const Base *>(
218 static_cast<const Derived *>(t)
219 );
220 return b;
221 }
222 void_caster_virtual_base();
223 virtual ~void_caster_virtual_base();
224};
225
226#ifdef BOOST_MSVC
227#pragma warning(pop)
228#endif
229
230template <class Derived, class Base>
231void_caster_virtual_base<Derived,Base>::void_caster_virtual_base() :
232 void_caster(
233 & (type_info_implementation<Derived>::type::get_const_instance()),
234 & (type_info_implementation<Base>::type::get_const_instance())
235 )
236{
237 recursive_register(true);
238}
239
240template <class Derived, class Base>
241void_caster_virtual_base<Derived,Base>::~void_caster_virtual_base(){
242 recursive_unregister();
243}
244
245template <class Derived, class Base>
246struct void_caster_base :
247 public void_caster
248{
249 typedef
250 BOOST_DEDUCED_TYPENAME mpl::eval_if<boost::is_virtual_base_of<Base,Derived>,
251 mpl::identity<
252 void_cast_detail::void_caster_virtual_base<Derived, Base>
253 >
254 ,// else
255 mpl::identity<
256 void_cast_detail::void_caster_primitive<Derived, Base>
257 >
258 >::type type;
259};
260
261} // void_cast_detail
262
263template<class Derived, class Base>
264BOOST_DLLEXPORT
265inline const void_cast_detail::void_caster & void_cast_register(
266 Derived const * /* dnull = NULL */,
267 Base const * /* bnull = NULL */
268){
269 typedef
270 BOOST_DEDUCED_TYPENAME mpl::eval_if<boost::is_virtual_base_of<Base,Derived>,
271 mpl::identity<
272 void_cast_detail::void_caster_virtual_base<Derived, Base>
273 >
274 ,// else
275 mpl::identity<
276 void_cast_detail::void_caster_primitive<Derived, Base>
277 >
278 >::type typex;
279 return singleton<typex>::get_const_instance();
280}
281
282template<class Derived, class Base>
283class void_caster :
284 public void_cast_detail::void_caster_base<Derived, Base>::type
285{
286};
287
288} // namespace serialization
289} // namespace boost
290
291#ifdef BOOST_MSVC
292# pragma warning(pop)
293#endif
294
295#include <boost/config/abi_suffix.hpp> // pops abi_suffix.hpp pragmas
296
297#endif // BOOST_SERIALIZATION_VOID_CAST_HPP