Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

added boost

File size: 13.9 KB
Line 
1/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
2// basic_oarchive.cpp:
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
9//  See http://www.boost.org for updates, documentation, and revision history.
10
11#include <boost/config.hpp> // msvc 6.0 needs this for warning suppression
12
13#include <cassert>
14#include <set>
15
16#include <boost/limits.hpp>
17#include <boost/state_saver.hpp>
18#include <boost/throw_exception.hpp>
19
20// including this here to work around an ICC in intel 7.0
21// normally this would be part of basic_oarchive.hpp below.
22#define BOOST_ARCHIVE_SOURCE
23#include <boost/archive/basic_archive.hpp>
24
25#include <boost/archive/detail/basic_oserializer.hpp>
26#include <boost/archive/detail/basic_pointer_oserializer.hpp>
27#include <boost/archive/detail/basic_oarchive.hpp>
28#include <boost/archive/detail/basic_archive_impl.hpp>
29#include <boost/archive/archive_exception.hpp>
30
31#ifdef BOOST_MSVC
32#  pragma warning(push)
33#  pragma warning(disable : 4251 4231 4660 4275)
34#endif
35
36using namespace boost::serialization;
37
38namespace boost {
39namespace serialization {
40    class extended_type_info;
41}
42namespace archive {
43namespace detail {
44
45class basic_oserializer;
46class basic_pointer_oserializer;
47
48class basic_oarchive_impl :
49    public basic_archive_impl
50{
51    friend class basic_oarchive;
52
53    unsigned int m_flags;
54
55    //////////////////////////////////////////////////////////////////////
56    // information about each serialized object saved
57    // keyed on address, class_id
58    struct aobject
59    {
60        const void * address;
61        class_id_type class_id;
62        object_id_type object_id;
63
64        bool operator<(const aobject &rhs) const
65        {
66            assert(NULL != address);
67            assert(NULL != rhs.address);
68            if( address < rhs.address )
69                return true;
70            if( address > rhs.address )
71                return false;
72            return class_id < rhs.class_id;
73        }
74        aobject & operator=(const aobject & rhs)
75        {
76            address = rhs.address;
77            class_id = rhs.class_id;
78            object_id = rhs.object_id;
79            return *this;
80        }
81        aobject(
82            const void *a,
83            class_id_type class_id_,
84            object_id_type object_id_
85        ) :
86            address(a),
87            class_id(class_id_),
88            object_id(object_id_)
89        {}
90        aobject() : address(NULL){}
91    };
92    // keyed on class_id, address
93    typedef std::set<aobject> object_set_type;
94    object_set_type object_set;
95
96    //////////////////////////////////////////////////////////////////////
97    // information about each serialized class saved
98    // keyed on type_info
99    struct cobject_type
100    {
101        const basic_oserializer * bos_ptr;
102        const class_id_type class_id;
103        bool initialized;
104        cobject_type(
105            std::size_t class_id_,
106            const basic_oserializer & bos_
107        ) :
108            bos_ptr(& bos_),
109            class_id(class_id_),
110            initialized(false)
111        {}
112        cobject_type(const basic_oserializer & bos_)
113            : bos_ptr(& bos_)
114        {}
115        cobject_type(
116            const cobject_type & rhs
117        ) :
118            bos_ptr(rhs.bos_ptr),
119            class_id(rhs.class_id),
120            initialized(rhs.initialized)
121        {}
122        // the following cannot be defined because of the const
123        // member.  This will generate a link error if an attempt
124        // is made to assign.  This should never be necessary
125        // use this only for lookup argument
126        cobject_type & operator=(const cobject_type &rhs);
127        bool operator<(const cobject_type &rhs) const {
128            return *bos_ptr < *(rhs.bos_ptr);
129        }
130    };
131    // keyed on type_info
132    typedef std::set<cobject_type> cobject_info_set_type;
133    cobject_info_set_type cobject_info_set;
134
135    // list of objects initially stored as pointers - used to detect errors
136    // keyed on object id
137    std::set<object_id_type> stored_pointers;
138
139    // address of the most recent object serialized as a poiner
140    // whose data itself is now pending serialization
141    const void * pending_object;
142    const basic_oserializer * pending_bos;
143
144    basic_oarchive_impl(unsigned int flags) :
145        m_flags(flags),
146        pending_object(NULL),
147        pending_bos(NULL)
148    {}
149
150    const cobject_type &
151    find(const basic_oserializer & bos);
152    const basic_oserializer * 
153    find(const serialization::extended_type_info &ti) const;
154
155//public:
156    const cobject_type &
157    register_type(const basic_oserializer & bos);
158    void save_object(
159        basic_oarchive & ar,
160        const void *t,
161        const basic_oserializer & bos
162    );
163    void save_pointer(
164        basic_oarchive & ar,
165        const void * t, 
166        const basic_pointer_oserializer * bpos
167    );
168};
169
170//////////////////////////////////////////////////////////////////////
171// implementation of basic_oarchive implementation functions
172
173// given a type_info - find its bos
174// return NULL if not found
175inline const basic_oserializer *
176basic_oarchive_impl::find(const serialization::extended_type_info & ti) const {
177    class bosarg : public basic_oserializer
178    {
179       bool class_info() const {
180            assert(false); 
181            return false;
182        }
183        // returns true if objects should be tracked
184        bool tracking(const unsigned int) const {
185            assert(false);
186            return false;
187        }
188        // returns class version
189        unsigned int version() const {
190            assert(false);
191            return 0;
192        }
193        // returns true if this class is polymorphic
194        bool is_polymorphic() const{
195            assert(false);
196            return false;
197        }
198        void save_object_data(     
199            basic_oarchive & ar, const void * x
200        ) const {
201            assert(false);
202        }
203    public:
204        bosarg(const serialization::extended_type_info & eti) :
205          boost::archive::detail::basic_oserializer(eti)
206        {}
207    };
208    bosarg bos(ti);
209    cobject_info_set_type::const_iterator cit
210        = cobject_info_set.find(cobject_type(bos));
211    // it should already have been "registered" - see below
212    if(cit == cobject_info_set.end()){
213        // if an entry is not found in the table it is because a pointer
214        // of a derived class has been serialized through its base class
215        // but the derived class hasn't been "registered"
216        return NULL;
217    }
218    // return pointer to the real class
219    return cit->bos_ptr;
220}
221
222inline const basic_oarchive_impl::cobject_type &
223basic_oarchive_impl::find(const basic_oserializer & bos)
224{
225    std::pair<cobject_info_set_type::iterator, bool> cresult = 
226        cobject_info_set.insert(cobject_type(cobject_info_set.size(), bos));
227    return *(cresult.first);
228}
229
230inline const basic_oarchive_impl::cobject_type &
231basic_oarchive_impl::register_type(
232    const basic_oserializer & bos
233){
234    cobject_type co(cobject_info_set.size(), bos);
235    std::pair<cobject_info_set_type::const_iterator, bool>
236        result = cobject_info_set.insert(co);
237    return *(result.first);
238}
239
240inline void
241basic_oarchive_impl::save_object(
242    basic_oarchive & ar,
243    const void *t,
244    const basic_oserializer & bos
245){
246    // if its been serialized through a pointer and the preamble's been done
247    if(t == pending_object && pending_bos == & bos){
248        // just save the object data
249        ar.end_preamble();
250        (bos.save_object_data)(ar, t);
251        return;
252    }
253
254    // get class information for this object
255    const cobject_type & co = register_type(bos);
256    if(bos.class_info()){
257        if( ! co.initialized){
258            ar.vsave(class_id_optional_type(co.class_id));
259            ar.vsave(tracking_type(bos.tracking(m_flags)));
260            ar.vsave(version_type(bos.version()));
261            (const_cast<cobject_type &>(co)).initialized = true;
262        }
263    }
264
265    // we're not tracking this type of object
266    if(! bos.tracking(m_flags)){
267        // just windup the preamble - no object id to write
268        ar.end_preamble();
269        // and save the data
270        (bos.save_object_data)(ar, t);
271        return;
272    }
273
274    // look for an existing object id
275    object_id_type oid(object_set.size());
276    // lookup to see if this object has already been written to the archive
277    basic_oarchive_impl::aobject ao(t, co.class_id, oid);
278    std::pair<basic_oarchive_impl::object_set_type::const_iterator, bool>
279        aresult = object_set.insert(ao);
280    oid = aresult.first->object_id;
281
282    // if its a new object
283    if(aresult.second){
284        // write out the object id
285        ar.vsave(oid);
286        ar.end_preamble();
287        // and data
288        (bos.save_object_data)(ar, t);
289        return;
290    }
291
292    // check that it wasn't originally stored through a pointer
293    if(stored_pointers.end() != stored_pointers.find(oid)){
294        // this has to be a user error.  loading such an archive
295        // would create duplicate objects
296        boost::throw_exception(
297            archive_exception(archive_exception::pointer_conflict)
298        );
299    }
300    // just save the object id
301    ar.vsave(object_reference_type(oid));
302    ar.end_preamble();
303    return;
304}
305
306// save a pointer to an object instance
307inline void
308basic_oarchive_impl::save_pointer(
309    basic_oarchive & ar,
310    const void * t, 
311    const basic_pointer_oserializer * bpos_ptr
312){
313    const basic_oserializer & bos = bpos_ptr->get_basic_serializer();
314    std::size_t original_count = cobject_info_set.size();
315    const cobject_type & co = register_type(bos);
316    if(! co.initialized){
317        ar.vsave(co.class_id);
318        // if its a previously unregistered class
319        if((cobject_info_set.size() > original_count)){
320            if(bos.is_polymorphic()){
321                const serialization::extended_type_info *eti = & bos.get_eti();
322                const char * key = NULL;
323                if(NULL != eti)
324                    key = eti->get_key();
325                if(NULL != key){
326                    // the following is required by IBM C++ compiler which
327                    // makes a copy when passing a non-const to a const.  This
328                    // is permitted by the standard but rarely seen in practice
329                    const class_name_type cn(key);
330                    // write out the external class identifier
331                    ar.vsave(cn);
332                }
333                else
334                    // without an external class name
335                    // we won't be able to de-serialize it so bail now
336                    boost::throw_exception(
337                        archive_exception(archive_exception::unregistered_class)
338                    );
339            }
340        }
341        if(bos.class_info()){
342            ar.vsave(tracking_type(bos.tracking(m_flags)));
343            ar.vsave(version_type(bos.version()));
344        }
345        (const_cast<cobject_type &>(co)).initialized = true;
346    }
347    else{
348        ar.vsave(class_id_reference_type(co.class_id));
349    }
350
351    // if we're not tracking
352    if(! bos.tracking(m_flags)){
353        // just save the data itself
354        ar.end_preamble();
355        state_saver<const void *> x(pending_object);
356        state_saver<const basic_oserializer *> y(pending_bos);
357        pending_object = t;
358        pending_bos = & bpos_ptr->get_basic_serializer();
359        bpos_ptr->save_object_ptr(ar, t);
360        return;
361    }
362
363    object_id_type oid(object_set.size());
364    // lookup to see if this object has already been written to the archive
365    basic_oarchive_impl::aobject ao(t, co.class_id, oid);
366    std::pair<basic_oarchive_impl::object_set_type::const_iterator, bool>
367        aresult = object_set.insert(ao);
368    oid = aresult.first->object_id;
369    // if the saved object already exists
370    if(! aresult.second){
371        // append the object id to he preamble
372        ar.vsave(object_reference_type(oid));
373        // and windup.
374        ar.end_preamble();
375        return;
376    }
377
378    // append id of this object to preamble
379    ar.vsave(oid);
380    ar.end_preamble();
381
382    // and save the object itself
383    state_saver<const void *> x(pending_object);
384    state_saver<const basic_oserializer *> y(pending_bos);
385    pending_object = t;
386    pending_bos = & bpos_ptr->get_basic_serializer();
387    bpos_ptr->save_object_ptr(ar, t);
388    // add to the set of object initially stored through pointers
389    stored_pointers.insert(oid);
390}
391
392//////////////////////////////////////////////////////////////////////
393// implementation of basic_oarchive functions
394
395BOOST_ARCHIVE_DECL(BOOST_PP_EMPTY()) 
396basic_oarchive::basic_oarchive(unsigned int flags)
397    : pimpl(new basic_oarchive_impl(flags))
398{}
399
400BOOST_ARCHIVE_DECL(BOOST_PP_EMPTY()) 
401basic_oarchive::~basic_oarchive()
402{
403    delete pimpl;
404}
405
406BOOST_ARCHIVE_DECL(void) 
407basic_oarchive::save_object(
408    const void *x, 
409    const basic_oserializer & bos
410){
411    pimpl->save_object(*this, x, bos);
412}
413
414BOOST_ARCHIVE_DECL(void) 
415basic_oarchive::save_pointer(
416    const void * t, 
417    const basic_pointer_oserializer * bpos_ptr
418){
419    pimpl->save_pointer(*this, t, bpos_ptr);
420}
421
422BOOST_ARCHIVE_DECL(void) 
423basic_oarchive::register_basic_serializer(const basic_oserializer & bos){
424    pimpl->register_type(bos);
425}
426
427BOOST_ARCHIVE_DECL(void) 
428basic_oarchive::lookup_basic_helper(
429    const boost::serialization::extended_type_info * const eti,
430    shared_ptr<void> & sph
431){
432    pimpl->lookup_helper(eti, sph);
433}
434
435BOOST_ARCHIVE_DECL(void) 
436basic_oarchive::insert_basic_helper(
437    const boost::serialization::extended_type_info * const eti,
438    shared_ptr<void> & sph
439){
440    pimpl->insert_helper(eti, sph);
441}
442
443BOOST_ARCHIVE_DECL(unsigned int)
444basic_oarchive::get_library_version() const{
445    return ARCHIVE_VERSION();
446}
447
448BOOST_ARCHIVE_DECL(unsigned int)
449basic_oarchive::get_flags() const{
450    return pimpl->m_flags;
451}
452
453BOOST_ARCHIVE_DECL(void) 
454basic_oarchive::end_preamble(){
455}
456
457} // namespace detail
458} // namespace archive
459} // namespace boost
460
461#ifdef BOOST_MSVC
462#pragma warning(pop)
463#endif
Note: See TracBrowser for help on using the repository browser.