Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

added boost

File size: 18.3 KB
Line 
1/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
2// basic_archive.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 to suppress warnings
12
13#include <cassert>
14#include <set>
15#include <list>
16#include <vector>
17#include <cstddef> // size_t
18
19#include <boost/config.hpp>
20#if defined(BOOST_NO_STDC_NAMESPACE)
21namespace std{ 
22    using ::size_t; 
23} // namespace std
24#endif
25
26#define BOOST_ARCHIVE_SOURCE
27#include <boost/archive/detail/auto_link_archive.hpp>
28
29#include <boost/limits.hpp>
30#include <boost/state_saver.hpp>
31#include <boost/throw_exception.hpp>
32
33#include <boost/archive/detail/basic_iserializer.hpp>
34#include <boost/archive/detail/basic_pointer_iserializer.hpp>
35#include <boost/archive/detail/basic_iarchive.hpp>
36#include <boost/archive/detail/basic_archive_impl.hpp>
37#include <boost/archive/archive_exception.hpp>
38
39#include <boost/serialization/tracking.hpp>
40#include <boost/serialization/extended_type_info.hpp>
41
42using namespace boost::serialization;
43
44namespace boost {
45namespace archive {
46namespace detail {
47
48class basic_iserializer;
49class basic_pointer_iserializer;
50
51class basic_iarchive_impl :
52    public basic_archive_impl
53{
54    friend class basic_iarchive;
55
56    version_type m_archive_library_version;
57    unsigned int m_flags;
58
59    //////////////////////////////////////////////////////////////////////
60    // information about each serialized object loaded
61    // indexed on object_id
62    struct aobject
63    {
64        void * address;
65        class_id_type class_id;
66        aobject(
67            void *a,
68            class_id_type class_id_
69        ) :
70            address(a),
71            class_id(class_id_)
72        {}
73        aobject() : address(NULL), class_id(-2) {}
74    };
75    typedef std::vector<aobject> object_id_vector_type;
76    object_id_vector_type object_id_vector;
77
78    //////////////////////////////////////////////////////////////////////
79    // used to implement the reset_object_address operation.
80    // list of objects which might be moved. We use a vector for implemenation
81    // in the hope the the truncation operation will be faster than either
82    // with a list or stack adaptor
83    object_id_type moveable_objects_start;
84    object_id_type moveable_objects_end;
85    object_id_type moveable_objects_recent;
86
87    void reset_object_address(
88        const void * new_address, 
89        const void *old_address
90    );
91
92    //////////////////////////////////////////////////////////////////////
93    // used by load object to look up class id given basic_serializer
94    struct cobject_type
95    {
96        const basic_iserializer * bis;
97        const class_id_type class_id;
98        cobject_type(
99            class_id_type class_id_,
100            const basic_iserializer & bis_
101        ) : 
102            bis(& bis_),
103            class_id(class_id_)
104        {}
105        cobject_type(const cobject_type & rhs) : 
106            bis(rhs.bis),
107            class_id(rhs.class_id)
108        {}
109        // the following cannot be defined because of the const
110        // member.  This will generate a link error if an attempt
111        // is made to assign.  This should never be necessary
112        cobject_type & operator=(const cobject_type & rhs);
113        bool operator<(const cobject_type &rhs) const
114        {
115            return *bis < *(rhs.bis);
116        }
117    };
118    typedef std::set<cobject_type> cobject_info_set_type;
119    cobject_info_set_type cobject_info_set;
120
121    //////////////////////////////////////////////////////////////////////
122    // information about each serialized class indexed on class_id
123    class cobject_id 
124    {
125    public:
126        cobject_id & operator=(const cobject_id & rhs){
127            bis_ptr = rhs.bis_ptr;
128            bpis_ptr = rhs.bpis_ptr;
129            file_version = rhs.file_version;
130            tracking_level = rhs.tracking_level;
131            initialized = rhs.initialized;
132            return *this;
133        }
134        const basic_iserializer * bis_ptr;
135        const basic_pointer_iserializer * bpis_ptr;
136        version_type file_version;
137        tracking_type tracking_level;
138        bool initialized;
139
140        cobject_id(const basic_iserializer & bis_) :
141            bis_ptr(& bis_),
142            bpis_ptr(NULL),
143            file_version(0),
144            tracking_level(track_never),
145            initialized(false)
146        {}
147        cobject_id(const cobject_id &rhs): 
148            bis_ptr(rhs.bis_ptr),
149            bpis_ptr(rhs.bpis_ptr),
150            file_version(rhs.file_version),
151            tracking_level(rhs.tracking_level),
152            initialized(rhs.initialized)
153        {}
154    };
155    typedef std::vector<cobject_id> cobject_id_vector_type;
156    cobject_id_vector_type cobject_id_vector;
157
158    //////////////////////////////////////////////////////////////////////
159    // list of objects created by de-serialization.  Used to implement
160    // clean up after exceptions.
161    class created_pointer_type
162    {
163    public:
164        created_pointer_type(
165            class_id_type class_id_,
166            void * address_
167        ) :
168            class_id(class_id_),
169            address(address_)
170        {}
171        created_pointer_type(const created_pointer_type &rhs) :
172            class_id(rhs.class_id),
173            address(rhs.address)
174        {}
175        created_pointer_type & operator=(const created_pointer_type &){
176            assert(false);
177            return *this;
178        }
179        void * get_address() const {
180            return address;
181        }
182        // object to which this item refers
183        const class_id_type class_id;
184    private:
185        void * address;
186    };
187
188    std::list<created_pointer_type> created_pointers;
189
190    //////////////////////////////////////////////////////////////////////
191    // address of the most recent object serialized as a poiner
192    // whose data itself is now pending serialization
193    void * pending_object;
194    const basic_iserializer * pending_bis;
195    version_type pending_version;
196
197    basic_iarchive_impl(unsigned int flags) :
198        m_archive_library_version(ARCHIVE_VERSION()),
199        m_flags(flags),
200        moveable_objects_start(0),
201        moveable_objects_end(0),
202        pending_object(NULL),
203        pending_bis(NULL),
204        pending_version(0)
205    {}
206    ~basic_iarchive_impl(){}
207    void set_library_version(unsigned int archive_library_version){
208        m_archive_library_version = archive_library_version;
209    }
210    bool
211    track(
212        basic_iarchive & ar,
213        void * & t
214    );
215    void
216    load_preamble(
217        basic_iarchive & ar,
218        cobject_id & co
219    );
220    class_id_type register_type(
221        const basic_iserializer & bis
222    );
223
224    // redirect through virtual functions to load functions for this archive
225    template<class T>
226    void load(basic_iarchive & ar, T & t){
227        ar.vload(t);
228    }
229
230//public:
231    void
232    next_object_pointer(void * t){
233        pending_object = t;
234    }
235    void delete_created_pointers();
236    class_id_type register_type(
237        const basic_pointer_iserializer & bpis
238    );
239    void load_object(
240        basic_iarchive & ar,
241        void * t,
242        const basic_iserializer & bis
243    );
244    const basic_pointer_iserializer * load_pointer(
245        basic_iarchive & ar,
246        void * & t, 
247        const basic_pointer_iserializer * bpis,
248        const basic_pointer_iserializer * (*finder)(
249            const boost::serialization::extended_type_info & type
250        )
251    );
252};
253
254inline void 
255basic_iarchive_impl::reset_object_address(
256    const void * new_address, 
257    const void *old_address
258){
259    object_id_type i;
260    // this code handles a couple of situations.
261    // a) where reset_object_address is applied to an untracked object.
262    //    In such a case the call is really superfluous and its really an
263    //    an error.  But we don't have access to the types here so we can't
264    //    know that.  However, this code will effectively turn this situation
265    //    into a no-op and every thing will work fine - albeat with a small
266    //    execution time penalty.
267    // b) where the call to reset_object_address doesn't immediatly follow
268    //    the << operator to which it corresponds.  This would be a bad idea
269    //    but the code may work anyway.  Naturally, a bad practice on the part
270    //    of the programmer but we can't detect it - as above.  So maybe we
271    //    can save a few more people from themselves as above.
272    for(i = moveable_objects_recent; i < moveable_objects_end; ++i){
273        if(old_address == object_id_vector[i].address)
274            break;
275    }
276    for(; i < moveable_objects_end; ++i){
277
278        // calculate displacement from this level
279        // warning - pointer arithmetic on void * is in herently non-portable
280        // but expected to work on all platforms in current usage
281        if(object_id_vector[i].address > old_address){
282            std::size_t member_displacement
283                = reinterpret_cast<std::size_t>(object_id_vector[i].address) 
284                - reinterpret_cast<std::size_t>(old_address);
285            object_id_vector[i].address = reinterpret_cast<void *>(
286                reinterpret_cast<std::size_t>(new_address) + member_displacement
287            );
288        }
289        else{
290            std::size_t member_displacement
291                = reinterpret_cast<std::size_t>(old_address)
292                - reinterpret_cast<std::size_t>(object_id_vector[i].address); 
293            object_id_vector[i].address = reinterpret_cast<void *>(
294                reinterpret_cast<std::size_t>(new_address) - member_displacement
295            );
296       }
297        ++i;
298    }
299}
300
301inline void 
302basic_iarchive_impl::delete_created_pointers()
303{
304    while(created_pointers.size() > 0){
305        const created_pointer_type & cp = created_pointers.front();
306
307        // figure out the class of the object to be deleted
308        // note: extra line used to evade borland issue
309        const int id = cp.class_id;
310        const cobject_id & co = cobject_id_vector[id];
311        // with the appropriate input serializer,
312        // delete the indicated object
313        co.bis_ptr->destroy(cp.get_address());
314        created_pointers.pop_front();
315    }
316}
317
318inline class_id_type
319basic_iarchive_impl::register_type(
320    const basic_iserializer & bis
321){
322    class_id_type id(static_cast<int>(cobject_info_set.size()));
323    cobject_type co(id, bis);
324    std::pair<cobject_info_set_type::const_iterator, bool>
325        result = cobject_info_set.insert(co);
326
327    if(result.second){
328        cobject_id_vector.push_back(cobject_id(bis));
329        assert(cobject_info_set.size() == cobject_id_vector.size());
330    }
331    id = result.first->class_id;
332    // borland complains without this minor hack
333    const int tid = id;
334    cobject_id & coid = cobject_id_vector[tid];
335    coid.bpis_ptr = bis.get_bpis_ptr();
336    return id;
337}
338
339void
340basic_iarchive_impl::load_preamble(
341    basic_iarchive & ar,
342    cobject_id & co
343){
344    if(! co.initialized){
345        if(co.bis_ptr->class_info()){
346            class_id_optional_type cid;
347            load(ar, cid);    // to be thrown away
348            load(ar, co.tracking_level);
349            load(ar, co.file_version);
350        }
351        else{
352            // override tracking with indicator from class information
353            co.tracking_level = co.bis_ptr->tracking(m_flags);
354            co.file_version = version_type(
355                co.bis_ptr->version()
356            );
357        }
358        co.initialized = true;
359    }
360}
361
362bool
363basic_iarchive_impl::track(
364    basic_iarchive & ar,
365    void * & t
366){
367    object_id_type oid;
368    load(ar, oid);
369
370    // if its a reference to a old object
371    if(object_id_type(object_id_vector.size()) > oid){
372        // we're done
373        t = object_id_vector[oid].address;
374        return false;
375    }
376    return true;
377}
378
379inline void
380basic_iarchive_impl::load_object(
381    basic_iarchive & ar,
382    void * t,
383    const basic_iserializer & bis
384){
385    // if its been serialized through a pointer and the preamble's been done
386    if(t == pending_object && & bis == pending_bis){
387        // read data
388        (bis.load_object_data)(ar, t, pending_version);
389        return;
390    }
391
392    const class_id_type cid = register_type(bis);
393    // note: extra line used to evade borland issue
394    const int id = cid;
395    cobject_id & co = cobject_id_vector[id];
396
397    load_preamble(ar, co);
398
399    // save the current move stack position in case we want to truncate it
400    boost::state_saver<object_id_type> w(moveable_objects_start);
401
402    // note: extra line used to evade borland issue
403    const bool tracking = co.tracking_level;
404
405    object_id_type this_id;
406    moveable_objects_start =
407    this_id = object_id_vector.size();
408
409    // if we tracked this object when the archive was saved
410    if(tracking){ 
411        // if it was already read
412        if(!track(ar, t))
413            // we're done
414            return;
415        // add a new enty into the tracking list
416        object_id_vector.push_back(aobject(t, cid));
417        // and add an entry for this object
418        moveable_objects_end = object_id_vector.size();
419    }
420    // read data
421    (bis.load_object_data)(ar, t, co.file_version);
422    moveable_objects_recent = this_id;
423}
424
425inline const basic_pointer_iserializer *
426basic_iarchive_impl::load_pointer(
427    basic_iarchive &ar,
428    void * & t,
429    const basic_pointer_iserializer * bpis_ptr,
430    const basic_pointer_iserializer * (*finder)(
431        const boost::serialization::extended_type_info & type_
432    )
433){
434    class_id_type cid;
435    load(ar, cid);
436
437    if(NULL_POINTER_TAG == cid){
438        t = NULL;
439        return bpis_ptr;
440    }
441
442    // if its a new class type - i.e. never been registered
443    if(class_id_type(cobject_info_set.size()) <= cid){
444        // if its either abstract
445        if(NULL == bpis_ptr
446        // or polymorphic
447        || bpis_ptr->get_basic_serializer().is_polymorphic()){
448            // is must have been exported
449            char key[BOOST_SERIALIZATION_MAX_KEY_SIZE];
450            class_name_type class_name(key);
451            load(ar, class_name);
452            // if it has a class name
453            const serialization::extended_type_info *eti = NULL;
454            if(0 != key[0])
455                eti = serialization::extended_type_info::find(key);
456            if(NULL == eti)
457                boost::throw_exception(
458                    archive_exception(archive_exception::unregistered_class)
459                );
460            bpis_ptr = (*finder)(*eti);
461        }
462        assert(NULL != bpis_ptr);
463        class_id_type new_cid = register_type(bpis_ptr->get_basic_serializer());
464        int i = cid;
465        cobject_id_vector[i].bpis_ptr = bpis_ptr;
466        assert(new_cid == cid);
467    }
468    int i = cid;
469    cobject_id & co = cobject_id_vector[i];
470    bpis_ptr = co.bpis_ptr;
471
472    load_preamble(ar, co);
473
474    // extra line to evade borland issue
475    const bool tracking = co.tracking_level;
476    // if we're tracking and the pointer has already been read
477    if(tracking && ! track(ar, t))
478        // we're done
479        return bpis_ptr;
480
481    // save state
482    state_saver<object_id_type> w(moveable_objects_start);
483
484    if(! tracking){
485        bpis_ptr->load_object_ptr(ar, t, co.file_version);
486    }
487    else{
488        state_saver<void *> x(pending_object);
489        state_saver<const basic_iserializer *> y(pending_bis);
490        state_saver<version_type> z(pending_version);
491
492        pending_bis = & bpis_ptr->get_basic_serializer();
493        pending_version = co.file_version;
494
495        // predict next object id to be created
496        const unsigned int ui = object_id_vector.size();
497
498        state_saver<object_id_type> w(moveable_objects_end);
499
500        // because the following operation could move the items
501        // don't use co after this
502        // add to list of serialized objects so that we can properly handle
503        // cyclic strucures
504        object_id_vector.push_back(aobject(t, cid));
505
506        bpis_ptr->load_object_ptr(
507            ar, 
508            object_id_vector[ui].address, 
509            co.file_version
510        );
511        t = object_id_vector[ui].address;
512        assert(NULL != t);
513
514        // and add to list of created pointers
515        created_pointers.push_back(created_pointer_type(cid, t));
516    }
517
518    return bpis_ptr;
519}
520
521//////////////////////////////////////////////////////////////////////
522// implementation of basic_iarchive functions
523
524BOOST_ARCHIVE_DECL(void)
525basic_iarchive::next_object_pointer(void *t){
526    pimpl->next_object_pointer(t);
527}
528
529BOOST_ARCHIVE_DECL(BOOST_PP_EMPTY())
530basic_iarchive::basic_iarchive(unsigned int flags) : 
531    pimpl(new basic_iarchive_impl(flags))
532{}
533
534BOOST_ARCHIVE_DECL(BOOST_PP_EMPTY())
535basic_iarchive::~basic_iarchive()
536{
537    delete pimpl;
538}
539
540BOOST_ARCHIVE_DECL(void)
541basic_iarchive::set_library_version(unsigned int archive_library_version){
542    pimpl->set_library_version(archive_library_version);
543}
544
545BOOST_ARCHIVE_DECL(void)
546basic_iarchive::reset_object_address(
547    const void * new_address, 
548    const void * old_address
549){
550    pimpl->reset_object_address(new_address, old_address);
551}
552
553BOOST_ARCHIVE_DECL(void)
554basic_iarchive::load_object(
555    void *t, 
556    const basic_iserializer & bis
557){
558    pimpl->load_object(*this, t, bis);
559}
560
561// load a pointer object
562BOOST_ARCHIVE_DECL(const basic_pointer_iserializer *)
563basic_iarchive::load_pointer(
564    void * &t, 
565    const basic_pointer_iserializer * bpis_ptr,
566    const basic_pointer_iserializer * (*finder)(
567        const boost::serialization::extended_type_info & type_
568    )
569){
570    return pimpl->load_pointer(*this, t, bpis_ptr, finder);
571}
572
573BOOST_ARCHIVE_DECL(void)
574basic_iarchive::register_basic_serializer(const basic_iserializer & bis){
575    pimpl->register_type(bis);
576}
577
578BOOST_ARCHIVE_DECL(void)
579basic_iarchive::lookup_basic_helper(
580    const boost::serialization::extended_type_info * const eti,
581    shared_ptr<void> & sph
582){
583    pimpl->lookup_helper(eti, sph);
584}
585
586BOOST_ARCHIVE_DECL(void)
587basic_iarchive::insert_basic_helper(
588    const boost::serialization::extended_type_info * const eti,
589    shared_ptr<void> & sph
590){
591    pimpl->insert_helper(eti, sph);
592}
593
594BOOST_ARCHIVE_DECL(void)
595basic_iarchive::delete_created_pointers()
596{
597    pimpl->delete_created_pointers();
598}
599
600BOOST_ARCHIVE_DECL(unsigned int) 
601basic_iarchive::get_library_version() const{
602    return pimpl->m_archive_library_version;
603}
604
605BOOST_ARCHIVE_DECL(unsigned int) 
606basic_iarchive::get_flags() const{
607    return pimpl->m_flags;
608}
609
610} // namespace detail
611} // namespace archive
612} // namespace boost
Note: See TracBrowser for help on using the repository browser.