|
SerializationArchive Class Reference |
#include <cstddef> // std::size_t
//////////////////////////////////////////////////////////////
// class trivial_oarchive
class trivial_oarchive {
public:
//////////////////////////////////////////////////////////
// public interface used by programs that use the
// serialization library
typedef boost::mpl::bool_<true> is_saving;
typedef boost::mpl::bool_<false> is_loading;
template<class T> void register_type(){}
template<class T> trivial_oarchive & operator<<(const T & t){
return *this;
}
template<class T> trivial_oarchive & operator&(const T & t){
return *this << t;
}
void save_binary(void *address, std::size_t count){};
};
The simplest possible input archive class is analogous to the above.
In the following discussion, only output archives will be addressed.
Input archives are exactly symmetrical to output archives.
This archive will compile and execute with any types which implement the
Serializable concept.
For an example see
demo_trivial_archive.cpp
.
Of course this program won't produce any output as it is. But it provides
the starting point for a simple class which can be used to log formatted
output. See the implementation of a simple
log archive to how this has been done.
Our archives have been factored into a tree of classes in order to minimize repetition of code. This is shown in the accompanying class diagram. Any class which fulfills the following requirements will fit into this hierarchy and implement all the features we require. Deriving from the base class common_oarchive.hpp provides all features we desire which are missing from trivial_oarchive above.
#include <cstddef> // std::size_t
#include <boost/archive/detail/common_oarchive.hpp>
/////////////////////////////////////////////////////////////////////////
// class complete_oarchive
class complete_oarchive :
public boost::archive::detail::common_oarchive<complete_oarchive>
{
// permit serialization system privileged access to permit
// implementation of inline templates for maximum speed.
friend class boost::archive::save_access;
// member template for saving primitive types.
// Specialize for any types/templates that require special treatment
template<class T>
void save(T & t);
public:
//////////////////////////////////////////////////////////
// public interface used by programs that use the
// serialization library
// archives are expected to support this function
void save_binary(void *address, std::size_t count);
};
Given a suitable definitions of save
and save_binary
,
any program using serialization with a conforming C++ compiler should compile
and run with this archive class.
detail::common_oarchive
class contains
a number of functions that are used by various parts of the serialization library
to help render the archive in a particular form.
void save_start(char const *)
void save_end(char const *)
void end_preamble()
void end_preamble()
is invoked and this internal flag is set
a ">" character is appended to the output and the internal flag is reset. The default
implementation for void end_preamble()
is a no-op thereby permitting it
to be optimised away for archive classes that don't use it.
template<class T>
void save_override(T & t, int);
archive::save(Archive & ar, t)
The second argument must be part of the function signature even though it is not used. Its purpose is to be sure that code is portable to compilers which fail to correctly implement partial function template ordering. For more information see this.
void save_override(T & t, int);
.
For example, in the XML archive, the override for this type renders an object_id equal to 23 as
"object_id=_23". The following table lists the types defined in the
boost::archive namespace
used internally by the serialization library:
type | default |
---|---|
version_type | unsigned int |
object_id_type | unsigned int |
object_id_reference_type | unsigned int |
class_id_type | int |
class_id_optional_type | nothing |
class_id_reference_type | int |
tracking_type | bool |
classname_type | string |
All of these are associated with a default serialization defined in terms of primitive types
so it isn't a requirement to define save_override
for these types.
These are defined in
basic_archive.hpp
.
All of these types have been assigned an
implementation level of
primitive
and are convertible to types such as int, unsigned int, etc.
so that they have default implementations. This is illustrated by
basic_text_iarchive.hpp
.
which relies upon the default. However, in some cases, overrides will have to be
explicitly provided for these types. For an example see
basic_xml_iarchive.hpp
.
In real practice, we probably won't be quite done. One or more of the following issues may need to be addressed:
stream
or
streambuf
as a template parameter rather than simple classes.
Combined with the above, even more issues arise with non-conforming compilers.
A close examination of the archives included with the library illustrate what it takes to make a portable archive that covers all data types.
BOOT_CLASS_EXPORT
is used
to instantiate the serialization code for the included archives.
BOOST_SERIALIZATION_REGISTER_ARCHIVE(Archive)
Failure to do this will not inhibit the program from compiling, linking
and executing properly - except in one case. If an instance of a derived
class is serialized through a pointer to its base class, the program
will throw an
unregistered_class
exception.
In addition, there are 28 other tests which aren't related to any particular archive class.
The default bjam
testing setup will run all
the above described tests. This will result in as many as 46 archive tests * 5
standard archives + 28 general tests = 258 tests. Note that a complete test of the
library would include DLL vs static library, release vs debug so the actual total
would be closer to 1032 tests.
For each archive there is a header file in the test directory similar to the one below.
The name of this archive is passed to the test program by setting the
environmental variable BOOST_ARCHIVE_TEST
to the name of the header. Here is the header file
test_archive.hpp
. Test header files for
other archives are similar.
// text_archive test header
// include output archive header
#include <boost/archive/text_oarchive.hpp>
// set name of test output archive
typedef boost::archive::text_oarchive test_oarchive;
// set name of test output stream
typedef std::ofstream test_ostream;
// repeat the above for input archive
#include <boost/archive/text_iarchive.hpp>
typedef boost::archive::text_iarchive test_iarchive;
typedef std::ifstream test_istream;
// define open mode for streams
// binary archives should use std::ios_base::binary
#define TEST_STREAM_FLAGS (std::ios_base::openmode)0
To test a new archive, for example, portable binary archives, with the gcc compiler,
make a header file portable_binary_archive.hpp
and invoke bjam
with
-sBOOST_ARCHIVE_LIST=portable_binary_archive.hpp
This process in encapsulated in the shell or cmd script
library_test
whose command line is
library_test --toolset=gcc -sBOOST_ARCHIVE_LIST=portable_binary_archive.hpp
inline
functions to enough depth will generate fast code.
However:
polymorphic_oarchive
and polymorphic_iarchive
. They present a common interface of virtual
functions - no templates - that is equivalent to the standard templated one.
This is shown in the accompanying
class diagram
The accompanying demo program in files
demo_polymorphic.cpp
,
demo_polymorphic_A.hpp
, and
demo_polymorphic_A
show how polymorphic archives are to be used. Note the following:
demo_polymorphic_A.hpp
and
demo_polymorphic_A.cpp
contain no templates and no reference to any specific archive implementation. That is, they will
only have to be compiled once for all archive implementations. This even applies to archives classes
created in the future.
demo_polymorphic.cpp
specifies a specific archive implementation.
polymorphic_iarchive_route.hpp
and
polymorphic_oarchive_route.hpp
which redirect calls to the polymorphic archives to the specific archive.
As these contain no code specific to the particular implementation archive, they can be used to create
a polymorphic archive implementation from any functioning templated archive implementation.
As a convenience, small header files have been included which contain
a typedef
for a polymorphic implementation for each corresponding
templated one. For example, the headers
polymorphic_text_iarchive.hpp
and
polymorphic_text_oarchive.hpp
.
contain the typedef
for the polymorphic implementation
of the standard text archive classes
text_iarchive.hpp
and
text_oarchive.hpp
respectively. All included polymorphic archives use the same naming scheme.
inline
archive functions. This will result in a detectable degradation in performance for
saving and loading archives.
Note that the concept of polymophic archives is fundamentally incompatible with the serialization of new types that are marked "primitive" by the user with:
BOOST_CLASS_IMPLEMENTATION(my_primitive_type, boost::serialization::primitive_type)
Code to implement serialization for these types is instantiated "on the fly" in the user's program.
But this conflicts with the whole purpose of the polymorphic archive. An attempt to
serialize such a primitive type will result in a compilation error since the common polymorhic
interface is static and cannot instantiate code for a new type.
The main utility of polymorphic archives will be to permit the building of class DLLs that will include serialization code for all present and future archives with no redundant code.
© Copyright Robert Ramey 2002-2004. Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)