Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/boost_1_33_1/libs/serialization/src/void_cast.cpp @ 12

Last change on this file since 12 was 12, checked in by landauf, 18 years ago

added boost

File size: 10.0 KB
Line 
1/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
2// void_cast.cpp: implementation of run-time casting of void pointers
3
4// (C) Copyright 2002 Robert Ramey - http://www.rrsd.com .
5// Use, modification and distribution is subject to the Boost Software
6// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
7// http://www.boost.org/LICENSE_1_0.txt)
8// <gennadiy.rozental@tfn.com>
9
10//  See http://www.boost.org for updates, documentation, and revision history.
11
12#if (defined _MSC_VER) && (_MSC_VER == 1200)
13# pragma warning (disable : 4786) // too long name, harmless warning
14#endif
15
16#include <cassert>
17
18// STL
19#include <set>
20#include <functional>
21#include <algorithm>
22#include <cassert>
23
24// BOOST
25#include <boost/shared_ptr.hpp>
26#define BOOST_SERIALIZATION_SOURCE
27#include <boost/serialization/extended_type_info.hpp>
28#include <boost/serialization/void_cast.hpp>
29
30namespace boost { 
31namespace serialization {
32namespace void_cast_detail {
33
34struct void_caster_compare
35{
36    bool
37    operator()(
38        shared_ptr<const void_caster> lhs, 
39        shared_ptr<const void_caster> rhs ) const
40    {
41        if( lhs.get()->m_derived_type < rhs.get()->m_derived_type )
42            return true;
43       
44        if( rhs.get()->m_derived_type < lhs.get()->m_derived_type)
45            return false;
46       
47        if( lhs.get()->m_base_type < rhs.get()->m_base_type )
48            return true;
49
50        return false;
51    }
52};
53
54struct null_deleter
55{
56    void operator()(void const *) const
57    {}
58};
59
60// it turns out that at least one compiler (msvc 6.0) doesn't guarentee
61// to destroy static objects in exactly the reverse sequence that they
62// are constructed.  To guarentee this, use a singleton pattern
63class void_caster_registry
64{
65    typedef shared_ptr<const void_caster> value_type;
66    typedef std::set<value_type, void_caster_compare> set_type;
67    set_type m_set;
68    static void_caster_registry * m_self;
69    static void_caster_registry * 
70    self(){
71        if(NULL == m_self){
72            static void_caster_registry instance;
73            m_self = & instance;
74        }
75        return m_self;
76    }
77    void_caster_registry(){}
78public:
79    ~void_caster_registry(){
80        m_self = 0;
81    }
82    typedef set_type::iterator iterator;
83    typedef set_type::const_iterator const_iterator;
84    static iterator
85    begin() {
86        return self()->m_set.begin();
87    }
88    static iterator
89    end() {
90        return self()->m_set.end();
91    }
92    static const_iterator
93    find(void_caster * vcp){
94        return self()->m_set.find(value_type(vcp, null_deleter()));
95    }
96    static std::pair<iterator, bool> 
97    insert(const value_type & vcp){
98        return self()->m_set.insert(vcp);
99    }
100    static bool 
101    empty(){
102        if(NULL == m_self)
103            return true;
104        return m_self->m_set.empty();
105    }
106    static void 
107    purge(const extended_type_info * eti);
108};
109
110void_caster_registry * void_caster_registry::m_self = NULL;
111
112void 
113void_caster_registry::purge(const extended_type_info * eti){
114    if(NULL == m_self)
115        return;
116    if(! empty()){
117        iterator i = m_self->m_set.begin();
118        while(i != m_self->m_set.end()){
119            // note that the erase might invalidate i so save it here
120            iterator j = i++;
121            if((*j)->includes(eti))
122                m_self->m_set.erase(j);
123        }
124    }
125}
126
127BOOST_SERIALIZATION_DECL(BOOST_PP_EMPTY())
128void_caster::void_caster(
129    extended_type_info const & derived_type_,
130    extended_type_info const & base_type_
131) :
132    m_derived_type( derived_type_),
133    m_base_type(base_type_)
134{}
135
136BOOST_SERIALIZATION_DECL(BOOST_PP_EMPTY())
137void_caster::~void_caster(){}
138
139bool 
140void_caster::includes(const extended_type_info * eti) const {
141    return & m_derived_type == eti || & m_base_type == eti;
142}
143
144void BOOST_SERIALIZATION_DECL(BOOST_PP_EMPTY())
145void_caster::static_register(const void_caster * vcp) 
146{
147    void_caster_registry::insert(shared_ptr<const void_caster>(vcp, null_deleter()));
148}
149
150class void_caster_derived : public void_caster
151{
152    std::ptrdiff_t difference;
153    virtual void const*
154    upcast( void const* t ) const{
155        return static_cast<const char*> ( t ) + difference;
156    }
157    virtual void const*
158    downcast( void const* t ) const{
159        return static_cast<const char*> ( t ) - difference;
160    }
161public:
162    void_caster_derived(
163        extended_type_info const& derived_type_,
164        extended_type_info const& base_type_,
165        std::ptrdiff_t difference_
166    ) :
167        void_caster(derived_type_, base_type_),
168        difference( difference_ )
169    {}
170};
171
172// just used as a search key
173class void_caster_argument : public void_caster
174{
175    virtual void const*
176    upcast( void const* t ) const {
177        assert(false);
178        return NULL;
179    }
180    virtual void const*
181    downcast( void const* t ) const {
182        assert(false);
183        return NULL;
184    }
185public:
186    void_caster_argument(
187        extended_type_info const& derived_type_,
188        extended_type_info const& base_type_
189    ) :
190        void_caster(derived_type_, base_type_)
191    {}
192};
193
194} // namespace void_cast_detail
195
196void  BOOST_SERIALIZATION_DECL(BOOST_PP_EMPTY())
197unregister_void_casts(extended_type_info *eti)
198{
199    void_cast_detail::void_caster_registry::purge(eti);
200}
201
202// Given a void *, assume that it really points to an instance of one type
203// and alter it so that it would point to an instance of a related type.
204// Return the altered pointer. If there exists no sequence of casts that
205// can transform from_type to to_type, return a NULL. 
206
207BOOST_SERIALIZATION_DECL(void const *)
208void_upcast(
209    extended_type_info const & derived_type,
210    extended_type_info const & base_type,
211    void const * const t,
212    bool top
213){
214    // same types - trivial case
215    if (derived_type == base_type)
216        return t;
217   
218    // check to see if base/derived pair is found in the registry
219    void_cast_detail::void_caster_argument ca(derived_type, base_type );
220    void_cast_detail::void_caster_registry::const_iterator it;
221    it = void_cast_detail::void_caster_registry::find( &ca );
222   
223    const void * t_new = NULL;
224
225    // if so
226    if (it != void_cast_detail::void_caster_registry::end())
227        // we're done
228        return (*it)->upcast(t);
229
230    // try to find a chain that gives us what we want
231    for(
232        it = void_cast_detail::void_caster_registry::begin();
233        it != void_cast_detail::void_caster_registry::end();
234        ++it
235    ){
236        // if the current candidate doesn't cast to the desired target type
237        if ((*it)->m_base_type == base_type){
238            // if the current candidate casts from the desired source type
239            if ((*it)->m_derived_type == derived_type){
240                // we have a base/derived match - we're done
241                // cast to the intermediate type
242                t_new = (*it)->upcast(t);
243                break;
244            }
245            t_new = void_upcast(derived_type, (*it)->m_derived_type, t, false);
246            if (NULL != t_new){
247                t_new = (*it)->upcast(t_new);
248                assert(NULL != t_new);
249                if(top){
250                    // register the this pair so we will have to go through
251                    // keep this expensive search process more than once.
252                    void_cast_detail::void_caster * vcp = 
253                        new void_cast_detail::void_caster_derived( 
254                            derived_type,
255                            base_type,
256                            static_cast<const char*>(t_new) - static_cast<const char*>(t)
257                        );
258                    void_cast_detail::void_caster_registry::insert(
259                        shared_ptr<const void_cast_detail::void_caster>(vcp)
260                    );
261                }
262                break;
263            }
264        }
265    }
266    return t_new;
267}
268
269BOOST_SERIALIZATION_DECL(void const *)
270void_downcast(
271    const extended_type_info & derived_type,
272    const extended_type_info & base_type,
273    const void * const t,
274    bool top
275){
276    // same types - trivial case
277    if (derived_type == base_type)
278        return t;
279   
280    // check to see if base/derived pair is found in the registry
281    void_cast_detail::void_caster_argument ca(derived_type, base_type );
282    void_cast_detail::void_caster_registry::const_iterator it;
283    it = void_cast_detail::void_caster_registry::find( &ca );
284   
285    // if so
286    if (it != void_cast_detail::void_caster_registry::end())
287        // we're done
288        return (*it)->downcast(t);
289
290    const void * t_new = NULL;
291    // try to find a chain that gives us what we want
292    for(
293        it = void_cast_detail::void_caster_registry::begin();
294        it != void_cast_detail::void_caster_registry::end();
295        ++it
296    ){
297        // if the current candidate doesn't casts from the desired target type
298        if ((*it)->m_derived_type == derived_type){
299            // if the current candidate casts to the desired source type
300            if ((*it)->m_base_type == base_type){
301                // we have a base/derived match - we're done
302                // cast to the intermediate type
303                t_new = (*it)->downcast(t);
304                break;
305            }
306            t_new = void_downcast((*it)->m_base_type, base_type, t, false);
307            if (NULL != t_new){
308                t_new = (*it)->downcast(t_new);
309                assert(NULL != t_new);
310                if(top){
311                    // register the this pair so we will have to go through
312                    // keep this expensive search process more than once.
313                    void_cast_detail::void_caster * vcp = 
314                        new void_cast_detail::void_caster_derived( 
315                            derived_type,
316                            base_type,
317                            static_cast<const char*>(t) - static_cast<const char*>(t_new)
318                        );
319                    void_cast_detail::void_caster_registry::insert(
320                        shared_ptr<const void_cast_detail::void_caster>(vcp)
321                    );
322                }
323                break;
324            }
325        }
326    }
327    return t_new;
328}
329
330} // namespace serialization
331} // namespace boost
332
333// EOF
Note: See TracBrowser for help on using the repository browser.