1<!doctype HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> 2<html> 3<!-- 4(C) Copyright 2002-10 Robert Ramey - http://www.rrsd.com . 5Use, modification and distribution is subject to the Boost Software 6License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at 7http://www.boost.org/LICENSE_1_0.txt) 8--> 9<head> 10<meta http-equiv="Content-Type" content="text/html; UTF-8"> 11<link rel="stylesheet" type="text/css" href="../../../boost.css"> 12<link rel="stylesheet" type="text/css" href="style.css"> 13<title>Serialization - More on Archives</title> 14</head> 15<body link="#0000ff" vlink="#800080"> 16<table border="0" cellpadding="7" cellspacing="0" width="100%" summary="header"> 17 <tr> 18 <td valign="top" width="300"> 19 <h3><a href="../../../index.htm"><img height="86" width="277" alt="C++ Boost" src="../../../boost.png" border="0"></a></h3> 20 </td> 21 <td valign="top"> 22 <h1 align="center">Serialization</h1> 23 <h2 align="center">Archive Class Reference</h2> 24 </td> 25 </tr> 26</table> 27<hr> 28<dl class="page-index"> 29 <dt><a href="#trivial">Trivial Archive</a> 30 <dt><a href="#implementation">More Useful Archive Classes</a> 31 <dt><a href="#usage">Usage</a> 32 <dt><a href="#testing">Testing</a> 33 <dt><a href="#polymorphic">Polymorphic Archives</a> 34</dl> 35 36<h3><a name="trivial">Trivial Archive</a></h3> 37The <a href="archives.html"><strong>Archive</strong></a> concept specifies the functions that a 38class must implement in order to be used to serialize 39<a href="serialization.html"><strong>Serializable</strong></a> types. 40 41Our discussion will focus on archives used for saving as the hierarchy is exactly analogous 42for archives used for loading data. 43 44<h4>Minimum Requirments</h4> 45 46The simplest class which will model the <a href="archives.html"><strong>Archive</strong></a> concept specifies the functions that a 47class will look like: 48 49<pre><code> 50#include <cstddef> // std::size_t 51////////////////////////////////////////////////////////////// 52// class trivial_oarchive 53class trivial_oarchive { 54public: 55 ////////////////////////////////////////////////////////// 56 // public interface used by programs that use the 57 // serialization library 58 typedef boost::mpl::bool_<true> is_saving; 59 typedef boost::mpl::bool_<false> is_loading; 60 template<class T> void register_type(){} 61 template<class T> trivial_oarchive & operator<<(const T & t){ 62 return *this; 63 } 64 template<class T> trivial_oarchive & operator&(const T & t){ 65 return *this << t; 66 } 67 void save_binary(void *address, std::size_t count){}; 68}; 69</code></pre> 70The simplest possible input archive class is analogous to the above. 71In the following discussion, only output archives will be addressed. 72Input archives are exactly symmetrical to output archives. 73<p> 74This archive will compile and execute with any types which implement the 75<a href="serialization.html"><strong>Serializable</strong></a> concept. 76For an example see 77<a href="../example/demo_trivial_archive.cpp" target="demo_trivial_archive"> 78<code style="white-space: normal">demo_trivial_archive.cpp</code></a>. 79Of course this program won't produce any output as it is. But it provides 80the starting point for a simple class which can be used to log formatted 81output. See the implementation of a <a href="simple_log.html">simple 82log archive</a> to how this has been done. 83 84<h3><a name="implementation">More Useful Archive Classes</a></h3> 85The above example is fine as far as it goes. But it doesn't implement 86useful features such as serialization of pointers, class versioning 87and others. This library implements a family of full featured archive 88classes appropriate for a variety of purposes. 89 90<p> 91Our archives have been factored into a tree of classes in order to minimize 92repetition of code. This is shown in the accompanying 93<a target="class_diagram" href="class_diagram.html">class diagram</a>. 94 95Any class which fulfills the following requirements will fit into 96this hierarchy and implement all the features we require. Deriving from 97the base class <a href="../../../boost/archive/detail/common_oarchive.hpp" target="common_oarchive_hpp"> 98common_oarchive.hpp</a> provides all features we desire which 99are missing from trivial_oarchive above. 100 101<pre><code> 102<a href="../../../boost/archive/detail/common_oarchive.hpp" target="common_oarchive_hpp"> 103#include <cstddef> // std::size_t 104#include <boost/archive/detail/common_oarchive.hpp> 105</a> 106///////////////////////////////////////////////////////////////////////// 107// class complete_oarchive 108class complete_oarchive : 109 public boost::archive::detail::common_oarchive<complete_oarchive> 110{ 111 // permit serialization system privileged access to permit 112 // implementation of inline templates for maximum speed. 113 friend class boost::archive::save_access; 114 115 // member template for saving primitive types. 116 // Specialize for any types/templates that require special treatment 117 template<class T> 118 void save(T & t); 119 120public: 121 ////////////////////////////////////////////////////////// 122 // public interface used by programs that use the 123 // serialization library 124 125 // archives are expected to support this function 126 void save_binary(void *address, std::size_t count); 127}; 128</code></pre> 129 130Given a suitable definitions of <code style="white-space: normal">save</code> 131and <code style="white-space: normal">save_binary</code>, 132any program using serialization with a conforming C++ compiler should compile 133and run with this archive class. 134 135<h4>Optional Overrides</h4> 136 137The <code style="white-space: normal">detail::common_oarchive</code> class contains 138a number of functions that are used by various parts of the serialization library 139to help render the archive in a particular form. 140 141<dl> 142 143<dt><h4><code>void save_start(char const *)</code></h4></dt> 144<dd> 145<strong>Default</strong>:Does nothing.<br> 146<strong>Purpose</strong>:To inject/retrieve an object name into the archive. Used 147by XML archive to inject "<name>" before data. 148</dd> 149<p> 150 151<dt><h4><code>void save_end(char const *)</code></h4></dt> 152<dd> 153<strong>Default</strong>:Does nothing.<br> 154<strong>Purpose</strong>:To inject/retrieve an object name into the archive. Used 155by XML archive to inject "</name>" after data. 156<dd> 157</dd> 158<p> 159<dt><h4><code>void end_preamble()</code></h4></dt> 160<dd> 161<strong>Default</strong>:Does nothing.<br> 162<strong>Purpose</strong>:Called <strong>each time</strong> user data is saved. 163It's not called when archive bookkeeping data is saved. This is used by XML archives 164to determine when to inject a ">" character at the end of an XML header. XML output archives 165keep their own internal flag indicating that data being written is header data. This 166internal flag is reset when an object start tag is written. When 167<code style="white-space: normal">void end_preamble()</code> is invoked and this internal flag is set 168a ">" character is appended to the output and the internal flag is reset. The default 169implementation for <code style="white-space: normal">void end_preamble()</code> is a no-op thereby permitting it 170to be optimised away for archive classes that don't use it. 171</dd> 172<p> 173<dt><h4><code> 174template<class T> 175void save_override(T & t, int); 176</code></h4></dt> 177<dd> 178<strong>Default</strong>:Invokes <code style="white-space: normal">archive::save(Archive & ar, t)</code><br> 179This is the main entry into the serialization library.<br> 180<strong>Purpose</strong>:This can be specialized in cases where the data is to be written 181to the archive in some special way. For example, XML archives implement special handling for 182name-value pairs by overriding this function template for name-value pairs. 183This replaces the default name-value pair handling, which is just to throw away the name, 184with one appropriate for XML which writes out the start of an XML tag with the correct object name. 185</dd> 186 187</dl> 188 189<h4>Types used by the serialization library</h4> 190The serialization library injects bookkeeping data into the serialization archive. 191This data includes things like object ids, version numbers, class names etc. Each 192of these objects is included in a wrapper so that the archive class can override the 193implementation of <code style="white-space: normal">void save_override(T & t, int);</code>. 194For example, in the XML archive, the override for this type renders an object_id equal to 23 as 195"object_id=_23". The following table lists the types defined in the 196<code style="white-space: normal">boost::archive namespace</code> 197used internally by the serialization library: 198<p> 199<table border> 200<tr><th align=left>type</th><th align=left><code style="white-space: normal">default<br>serialized as</code></th> 201<tr><td><code style="white-space: normal">version_type</code></td><td><code style="white-space: normal">unsigned int</code></td> 202<tr><td><code style="white-space: normal">object_id_type</code></td><td><code style="white-space: normal">unsigned int</code></td> 203<tr><td><code style="white-space: normal">object_id_reference_type</code></td><td><code style="white-space: normal">unsigned int</code></td> 204<tr><td><code style="white-space: normal">class_id_type</code></td><td><code style="white-space: normal">int</code></td> 205<tr><td><code style="white-space: normal">class_id_optional_type</code></td><td><code style="white-space: normal">nothing</code></td> 206<tr><td><code style="white-space: normal">class_id_reference_type</code></td><td><code style="white-space: normal">int</code></td> 207<tr><td><code style="white-space: normal">tracking_type</code></td><td><code style="white-space: normal">bool</code></td> 208<tr><td><code style="white-space: normal">classname_type</code></td><td><code style="white-space: normal">string</code></td> 209</table> 210<p> 211All of these are associated with a default serialization defined in terms of primitive types 212so it isn't a requirement to define <code style="white-space: normal">save_override</code> 213for these types. 214<p> 215These are defined in 216<a href="../../../boost/archive/basic_archive.hpp" target="basic_archive_hpp"><code style="white-space: normal">basic_archive.hpp</code></a>. 217All of these types have been assigned an 218<a target="detail" href="traits.html#level">implementation level</a> of 219<code style="white-space: normal">primitive</code> and are convertible to types such as int, unsigned int, etc. 220so that they have default implementations. This is illustrated by 221<a href="../../../boost/archive/basic_text_iarchive.hpp" target="basic_text_iarchive_hpp"><code style="white-space: normal">basic_text_iarchive.hpp</code></a>. 222which relies upon the default. However, in some cases, overrides will have to be 223explicitly provided for these types. For an example see 224<a href="../../../boost/archive/basic_xml_iarchive.hpp" target="basic_xml_iarchive_hpp"><code style="white-space: normal">basic_xml_iarchive.hpp</code></a>. 225<p> 226In real practice, we probably won't be quite done. 227One or more of the following issues may need to be addressed: 228<ul> 229 <li>Even if we are using a conforming compiler, we might want our new archive class 230 to be portable to non-conforming compilers. 231 <li>Our archive format might require extra information inserted into it. For 232 example, XML archives need <name ... >...</name> surrounding 233 all data objects. 234 <li>Addressing any of the above may generate more issues to be addressed. 235 <li>The archives included with the library are all templates which use a 236 <code style="white-space: normal">stream</code> or 237 <code style="white-space: normal">streambuf</code> 238 as a template parameter rather than simple classes. 239 Combined with the above, even more issues arise with non-conforming compilers. 240</ul> 241The attached <a target="class_diagram" href="class_diagram.html">class diagram</a> 242shows the relationships between classes used to implement the serialization library. 243<p> 244A close examination of the archives included with the library illustrate 245what it takes to make a portable archive that covers all data types. 246<h3><a name="usage">Usage</a></h3> 247The newly created archive will usually be stored in its own header module. All 248that is necessary is to include the header and construct an instance of the new archive. 249EXCEPT for one special case. 250<ul> 251 <li>Instances of a derived class are serialized through a base class pointer. 252 <li>Such instances are not "registered" neither implicitly nor explicitly. That 253 is, the macro <code style="white-space: normal">BOOT_CLASS_EXPORT</code> is used 254 to instantiate the serialization code for the included archives. 255</ul> 256 257To make this work, the following should be included after the archive 258class definition. 259<pre><code> 260BOOST_SERIALIZATION_REGISTER_ARCHIVE(Archive) 261</code></pre> 262Failure to do this will not inhibit the program from compiling, linking 263and executing properly - except in one case. If an instance of a derived 264class is serialized through a pointer to its base class, the program 265will throw an 266<a href="exceptions.html#unregistered_class"><code style="white-space: normal">unregistered_class</code></a> 267exception. 268<p> 269 270<h4><a name="testing">Testing</h4> 271Exhaustive testing of the library requires testing the different aspects of object 272serialization with each archive. There are 46 different tests that can run with any archive. 273There are 5 "standard archives" included with the system. 274(3 in systems that don't support wide charactor i/o). 275<p> 276In addition, there are 28 other tests which aren't related to any particular archive class. 277<p> 278The default <code style="white-space: normal">bjam</code> testing setup will run all 279the above described tests. This will result in as many as 46 archive tests * 5 280standard archives + 28 general tests = 258 tests. Note that a complete test of the 281library would include DLL vs static library, release vs debug so the actual total 282would be closer to 1032 tests. 283<p> 284For each archive there is a header file in the test directory similar to the one below. 285The name of this archive is passed to the test program by setting the 286environmental variable <code style="white-space: normal">BOOST_ARCHIVE_TEST</code> 287to the name of the header. Here is the header file 288<code style="white-space: normal">test_archive.hpp</code> . Test header files for 289other archives are similar. 290<pre><code> 291// text_archive test header 292// include output archive header 293#include <boost/archive/text_oarchive.hpp> 294// set name of test output archive 295typedef boost::archive::text_oarchive test_oarchive; 296// set name of test output stream 297typedef std::ofstream test_ostream; 298 299// repeat the above for input archive 300#include <boost/archive/text_iarchive.hpp> 301typedef boost::archive::text_iarchive test_iarchive; 302typedef std::ifstream test_istream; 303 304// define open mode for streams 305// binary archives should use std::ios_base::binary 306#define TEST_STREAM_FLAGS (std::ios_base::openmode)0 307</code></pre> 308 309To test a new archive, for example, portable binary archives, with the gcc compiler, 310make a header file <code style="white-space: normal">portable_binary_archive.hpp</code> 311and invoke <code style="white-space: normal">bjam</code> with 312<pre><code> 313-sBOOST_ARCHIVE_LIST=portable_binary_archive.hpp 314</code></pre> 315This process in encapsulated in the shell or cmd script 316<code style="white-space: normal">library_test</code> whose command line is 317<pre><code> 318library_test --toolset=gcc -sBOOST_ARCHIVE_LIST=portable_binary_archive.hpp 319</code></pre> 320<h3><a name="polymorphic">Polymorphic Archives</a></h3> 321 322<h4>Motivation</h4> 323 324All archives described so far are implemented as templates. Code to save and load 325data to archives is regenerated for each combination of archive class and data type. 326Under these cirumstances, a good optimizing compiler that can expand 327<code>inline</code> functions to enough depth will generate fast code. 328However: 329<ul> 330<li>Much inline code may be replicated. 331<li>If there are several archive classes, code will be regenerated for each archive class. 332<li>If serialization code is placed in a library, that library must be rebuilt 333each time a new archive class is created. 334<li>If serialization code is placed in a DLL, 335 <ul> 336 <li>The DLL will contain versions of code for each known archive type. 337 This would result in loading of DLLs which contain 338 much code that is not used - basically defeating one of the main motivations 339 for choosing to use a DLL in the first place. 340 <li>If a new archive is created and an application shipped, all DLLs have to be 341 rebuilt, and reshipped along with the application which uses the new archive. Thus 342 the other main motivation for using a DLL is defeated. 343 </ul> 344</ul> 345 346<h4>Implementation</h4> 347The solution is the pair <code>polymorphic_oarchive</code> 348and <code>polymorphic_iarchive</code>. They present a common interface of virtual 349functions - no templates - that is equivalent to the standard templated one. 350 351This is shown in the accompanying 352<a target="class_diagram" href="class_diagram.html">class diagram</a> 353<p> 354The accompanying demo program in files 355 356<a target=demo_polymorphic_cp href="../example/demo_polymorphic.cpp"><code style="white-space: normal">demo_polymorphic.cpp</code></a>, 357<a target=demo_polymorphic_A_hpp href="../example/demo_polymorphic_A.hpp"><code style="white-space: normal">demo_polymorphic_A.hpp</code></a>, and 358<a target=demo_polymorphic_A_cpp href="../example/demo_polymorphic_A.cpp"><code style="white-space: normal">demo_polymorphic_A</code></a> 359show how polymorphic archives are to be used. Note the following: 360<ul> 361 <li><a target=demo_polymorphic_A_hpp href="../example/demo_polymorphic_A.hpp"><code style="white-space: normal">demo_polymorphic_A.hpp</code></a> and 362<a target=demo_polymorphic_A_cpp href="../example/demo_polymorphic_A.cpp"><code style="white-space: normal">demo_polymorphic_A.cpp</code></a> 363contain no templates and no reference to any specific archive implementation. That is, they will 364only have to be compiled once for all archive implementations. This even applies to archives classes 365created in the future. 366 <li>The main program <a target=demo_polymorphic_cp href="../example/demo_polymorphic.cpp"><code style="white-space: normal">demo_polymorphic.cpp</code></a> 367specifies a specific archive implementation. 368</ul> 369As can be seen in the 370<a target="class_diagram" href="class_diagram.html">class diagram</a> 371and the header files, this implementation is just a composition of the polymorphic 372interface and the standard template driven implementation. This composition is 373accomplished by the templates 374<a target=polymorphic_iarchive_route_hpp href="../../../boost/archive/detail/polymorphic_iarchive_route.hpp"><code style="white-space: normal">polymorphic_iarchive_route.hpp</code></a> 375and 376<a target=polymorphic_oarchive_route_hpp href="../../../boost/archive/detail/polymorphic_oarchive_route.hpp"><code style="white-space: normal">polymorphic_oarchive_route.hpp</code></a> 377which redirect calls to the polymorphic archives to the specific archive. 378As these contain no code specific to the particular implementation archive, they can be used to create 379a polymorphic archive implementation from any functioning templated archive implementation. 380<p> 381As a convenience, small header files have been included which contain 382a <code style="white-space: normal">typedef</code> for a polymorphic implementation for each corresponding 383templated one. For example, the headers 384<a target=polymorphic_text_iarchive_hpp href="../../../boost/archive/polymorphic_text_iarchive.hpp"><code style="white-space: normal">polymorphic_text_iarchive.hpp</code></a> 385and 386<a target=polymorphic_text_oarchive_hpp href="../../../boost/archive/polymorphic_text_oarchive.hpp"><code style="white-space: normal">polymorphic_text_oarchive.hpp</code></a>. 387contain the <code style="white-space: normal">typedef</code> for the polymorphic implementation 388of the standard text archive classes 389<a target=text_iarchive_hpp href="../../../boost/archive/text_iarchive.hpp"><code style="white-space: normal">text_iarchive.hpp</code></a> 390and 391<a target=text_oarchive_hpp href="../../../boost/archive/text_oarchive.hpp"><code style="white-space: normal">text_oarchive.hpp</code></a> 392respectively. All included polymorphic archives use the same naming scheme. 393 394<h4>Usage</h4> 395Polymorphic archives address the issues raised above regarding templated implementation. 396That is, there is no replicated code, and no recompilation for new archives. This will 397result in smaller executables for program which use more than one type of archive, and 398smaller DLLS. There is a penalty for calling archive functions through a virtual function 399dispatch table and there is no possibility for a compiler to <code style="white-space: normal">inline</code> 400archive functions. This will result in a detectable degradation in performance for 401saving and loading archives. 402<p> 403Note that the concept of polymophic archives is fundamentally incompatible with the 404serialization of new types that are marked "primitive" by the user with: 405<pre><code> 406BOOST_CLASS_IMPLEMENTATION(my_primitive_type, boost::serialization::primitive_type) 407</code></pre> 408 409Code to implement serialization for these types is instantiated "on the fly" in the user's program. 410But this conflicts with the whole purpose of the polymorphic archive. An attempt to 411serialize such a primitive type will result in a compilation error since the common polymorhic 412interface is static and cannot instantiate code for a new type. 413 414<p> 415The main utility of polymorphic archives will be to permit the building of class DLLs that will 416include serialization code for all present and future archives with no redundant code. 417<hr> 418<p><i>© Copyright <a href="http://www.rrsd.com">Robert Ramey</a> 2002-2004. 419Distributed under the Boost Software License, Version 1.0. (See 420accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 421</i></p> 422</body> 423</html> 424