| [ce133f] | 1 | /*
 | 
|---|
 | 2 |  * Project: MoleCuilder
 | 
|---|
 | 3 |  * Description: creates and alters molecular systems
 | 
|---|
 | 4 |  * Copyright (C)  2010 University of Bonn. All rights reserved.
 | 
|---|
 | 5 |  * Please see the LICENSE file or "Copyright notice" in builder.cpp for details.
 | 
|---|
 | 6 |  */
 | 
|---|
 | 7 | 
 | 
|---|
 | 8 | /**
 | 
|---|
 | 9 |  * \file serialization.dox
 | 
|---|
 | 10 |  *
 | 
|---|
 | 11 |  *  Here, we explain what serialization is and how it is used within MoleCuilder.
 | 
|---|
 | 12 |  *
 | 
|---|
 | 13 |  * Created on: Oct 11, 2011
 | 
|---|
 | 14 |  *    Author: heber
 | 
|---|
 | 15 |  */
 | 
|---|
| [750cff] | 16 | 
 | 
|---|
 | 17 | /** \page serialization Serialization
 | 
|---|
 | 18 |  *
 | 
|---|
| [caece4] | 19 |  *  Serialization is a mighty concept. This is only possible within an object-
 | 
|---|
| [750cff] | 20 |  *  oriented framework. The member variables of a class make up its internal
 | 
|---|
 | 21 |  *  state. By storing this state, creating another instance and restoring
 | 
|---|
 | 22 |  *  the variables to this state, we may in essence clone the instance. However,
 | 
|---|
 | 23 |  *  we obtain additional control as to the moment of restoration because the
 | 
|---|
 | 24 |  *  internal state is stored temporarily. To allow for this storage all of
 | 
|---|
| [caece4] | 25 |  *  these variables have to be \e serializable.
 | 
|---|
| [750cff] | 26 |  *
 | 
|---|
 | 27 |  *  Serialization refers to putting one after another into a writable form
 | 
|---|
 | 28 |  *  (e.g. convert to string and write into a stringstream) and eventually
 | 
|---|
 | 29 |  *  in reverse order to read them one by one from this writable form and
 | 
|---|
 | 30 |  *  cast them back into their original type.
 | 
|---|
 | 31 |  *
 | 
|---|
 | 32 |  *  Here, this is done via boost::serialization.
 | 
|---|
 | 33 |  *
 | 
|---|
 | 34 |  *  \attention The serialization headers do not mingle well with \b MemDebug.hpp.
 | 
|---|
 | 35 |  *  Hence, place them before MemDebug.hpp as they do funny stuff with the
 | 
|---|
 | 36 |  *  new() operator.
 | 
|---|
 | 37 |  *
 | 
|---|
 | 38 |  *  Serialization is so powerful because the stored state can be stored to
 | 
|---|
 | 39 |  *  disk, transfered to another thread or even to another computer. If received
 | 
|---|
 | 40 |  *  by a compatible code, the instance is recreated and computation can be
 | 
|---|
 | 41 |  *  continued elsewhere.
 | 
|---|
 | 42 |  *
 | 
|---|
 | 43 |  *  For the moment we use it for creating an undo state within the Action's.
 | 
|---|
 | 44 |  *  I.e. we store the state of all instances that are modified by an Action's
 | 
|---|
 | 45 |  *  doings and may in Action::performUndo() just re-create the unmodified
 | 
|---|
 | 46 |  *  instance by loading them from the serializing archive.
 | 
|---|
 | 47 |  *
 | 
|---|
 | 48 |  *  \section serialization-add How to make your class serializable.
 | 
|---|
 | 49 |  *
 | 
|---|
 | 50 |  *  \subsection serialization-add-simple The simple case
 | 
|---|
 | 51 |  *
 | 
|---|
 | 52 |  *  All you need to do with your newly created class foo is this:
 | 
|---|
 | 53 |  *  \code
 | 
|---|
 | 54 |  *  class foo {
 | 
|---|
 | 55 |  *  ...
 | 
|---|
 | 56 |  *  private:
 | 
|---|
 | 57 |  *    friend class boost::serialization::access;
 | 
|---|
 | 58 |  *    template<class Archive>
 | 
|---|
 | 59 |  *    void serialize(Archive & ar, const unsigned int version) const
 | 
|---|
 | 60 |  *    {
 | 
|---|
 | 61 |  *      ar & content;
 | 
|---|
 | 62 |  *    }
 | 
|---|
 | 63 |  *    ...
 | 
|---|
 | 64 |  *    double content;
 | 
|---|
 | 65 |  *  };
 | 
|---|
 | 66 |  *  \endcode
 | 
|---|
 | 67 |  *  This will implement a serialization function for both directions for the
 | 
|---|
 | 68 |  *  member variable content. I.e. we may now store a class instance as this:
 | 
|---|
 | 69 |  *  \code
 | 
|---|
 | 70 |  *  #include <boost/archive/text_oarchive.hpp>
 | 
|---|
 | 71 |  *  std::stringstream stream;
 | 
|---|
 | 72 |  *  boost::archive::text_oarchive oa(stream);
 | 
|---|
 | 73 |  *  oa << diagonal;
 | 
|---|
 | 74 |  *  \endcode
 | 
|---|
 | 75 |  *  This will store the state of the class in the stringstream \a stream.
 | 
|---|
 | 76 |  *  Getting the instance back is then as easy as
 | 
|---|
 | 77 |  *  \code
 | 
|---|
 | 78 |  *  #include <boost/archive/text_iarchive.hpp>
 | 
|---|
 | 79 |  *  boost::archive::text_iarchive ia(stream);
 | 
|---|
 | 80 |  *  RealSpaceMatrix *newm;
 | 
|---|
 | 81 |  *  ia >> newm;
 | 
|---|
 | 82 |  *  \endcode
 | 
|---|
 | 83 |  *
 | 
|---|
 | 84 |  *  \subsection serialization-add-complicated The more complicated case
 | 
|---|
 | 85 |  *
 | 
|---|
 | 86 |  *  It gets trickier when load and store need to be done differently, e.h.
 | 
|---|
 | 87 |  *  \code
 | 
|---|
 | 88 |  *  class foo {
 | 
|---|
 | 89 |  *  ...
 | 
|---|
 | 90 |  *  private:
 | 
|---|
 | 91 |  *    friend class boost::serialization::access;
 | 
|---|
 | 92 |  *    // serialization
 | 
|---|
 | 93 |  *    template<class Archive>
 | 
|---|
 | 94 |  *    void save(Archive & ar, const unsigned int version) const
 | 
|---|
 | 95 |  *    {
 | 
|---|
 | 96 |  *      ar & content;
 | 
|---|
 | 97 |  *    }
 | 
|---|
 | 98 |  *    template<class Archive>
 | 
|---|
 | 99 |  *    void load(Archive & ar, const unsigned int version)
 | 
|---|
 | 100 |  *    {
 | 
|---|
 | 101 |  *      ar & content;
 | 
|---|
 | 102 |  *      createViews();
 | 
|---|
 | 103 |  *    }
 | 
|---|
 | 104 |  *    BOOST_SERIALIZATION_SPLIT_MEMBER()
 | 
|---|
 | 105 |  *    ...
 | 
|---|
 | 106 |  *  }
 | 
|---|
 | 107 |  *  \endcode
 | 
|---|
 | 108 |  *  Here, we split serialize() function into distinct load() and save() because
 | 
|---|
 | 109 |  *  we have to call an additional function to fully re-store the instance, i.e.
 | 
|---|
 | 110 |  *  it creates some internal reference arrays (Views) in a specific manner.
 | 
|---|
 | 111 |  *
 | 
|---|
 | 112 |  *  The serialize functions can also be added externally, i.e. outside of the
 | 
|---|
 | 113 |  *  scope of the class, but can then access only public members (except we
 | 
|---|
 | 114 |  *  again make it a friend).
 | 
|---|
 | 115 |  *
 | 
|---|
| [caece4] | 116 |  *  \subsection serialization-add-complicated The more complicated case
 | 
|---|
 | 117 |  *
 | 
|---|
 | 118 |  *  Noted the additional \a version parameter up there in the serialize functions'
 | 
|---|
 | 119 |  *  signature? When classes change, we might still want to be able to parse in
 | 
|---|
 | 120 |  *  older states. As as state is always written to a default constructed object.
 | 
|---|
 | 121 |  *  this is possible. You can check the version variable like this to make your
 | 
|---|
 | 122 |  *  function compatible with older functions.
 | 
|---|
 | 123 |  *
 | 
|---|
 | 124 |  *  \code
 | 
|---|
 | 125 |  *    void serialize(Archive & ar, const unsigned int version) const
 | 
|---|
 | 126 |  *    {
 | 
|---|
 | 127 |  *      ar & content;
 | 
|---|
 | 128 |  *      if (version > 0)
 | 
|---|
 | 129 |  *        are & newcontent;
 | 
|---|
 | 130 |  *    }
 | 
|---|
 | 131 |  *    ...
 | 
|---|
 | 132 |  *    double newcontent;
 | 
|---|
 | 133 |  *  };
 | 
|---|
 | 134 |  *  \endcode
 | 
|---|
 | 135 |  *
 | 
|---|
 | 136 |  *  The version itself is set as follows,
 | 
|---|
 | 137 |  *  \code
 | 
|---|
 | 138 |  *    BOOST_CLASS_VERSION(foo, 1)
 | 
|---|
 | 139 |  *  \endcode
 | 
|---|
 | 140 |  *  where you give the name of your class and the version.
 | 
|---|
 | 141 |  *
 | 
|---|
| [bc3411] | 142 |  *  \subsection serialization-important notes Some important notes
 | 
|---|
 | 143 |  *
 | 
|---|
 | 144 |  *  There are a few things that one needs to be aware of: Otherwise easily
 | 
|---|
 | 145 |  *  a stupid mistake is introduced that is trivial once understand but hard
 | 
|---|
 | 146 |  *  to find otherwise. This is especially so because compiler errors with
 | 
|---|
| [caece4] | 147 |  *  respect to the serialization part are always lengthy (whole page) and
 | 
|---|
| [bc3411] | 148 |  *  very hard to read:
 | 
|---|
 | 149 |  *  \li Always obtain the same type from an archive that you put into it!
 | 
|---|
 | 150 |  *    If it's been an instance, get an instance, not a ref(&) or a pointer(*)
 | 
|---|
 | 151 |  *    and also the other way round.
 | 
|---|
 | 152 |  *  \li boost::serialization always uses the default constructor of your class
 | 
|---|
 | 153 |  *    that is afterwards filled with state information stored. If your default
 | 
|---|
 | 154 |  *    constructor is unusable, something goes wrong here. There are two ways
 | 
|---|
 | 155 |  *    out:
 | 
|---|
 | 156 |  *    -# Write a private default constructor. Also you might have to split
 | 
|---|
 | 157 |  *      serialize() into load() and save() and do some additional stuff in
 | 
|---|
 | 158 |  *      load().
 | 
|---|
 | 159 |  *    -# one can write save_construct_data() and load_construct_data() directly
 | 
|---|
 | 160 |  *      as is explained in the boost::serialization documentation on
 | 
|---|
 | 161 |  *      constructors (as of 1.47).
 | 
|---|
 | 162 |  *  \li Const members are a problem as they can only be written during the
 | 
|---|
 | 163 |  *    constructor and as always the default cstor is used ... however, wiggle
 | 
|---|
 | 164 |  *    around by casting it to non-const, e.g.
 | 
|---|
 | 165 |  *    \code
 | 
|---|
 | 166 |  *    const foo foo_instance;
 | 
|---|
 | 167 |  *    ...
 | 
|---|
 | 168 |  *    const_cast<foo &>(foo_instance);
 | 
|---|
 | 169 |  *    \endcode
 | 
|---|
 | 170 |  *    Alternatively, you could place const variables in an extra class (and
 | 
|---|
 | 171 |  *    non-const there), make them available only via a getter. Hence, they
 | 
|---|
 | 172 |  *    would still be const in your main class but could be serialized without
 | 
|---|
 | 173 |  *    any trouble.
 | 
|---|
 | 174 |  *  \li When you want to serialize a derived class, also the base class state
 | 
|---|
 | 175 |  *    has to be serialized, this is done via
 | 
|---|
 | 176 |  *    \code
 | 
|---|
 | 177 |  *    boost::serialization::base_object<base type>(*this);
 | 
|---|
 | 178 |  *    \endcode
 | 
|---|
| [caece4] | 179 |  *  \li When you have code in header and implementation module, boost might get
 | 
|---|
 | 180 |       confused, use \code BOOST_CLASS_EXPORT_KEY(foo) \endcode and
 | 
|---|
 | 181 |           \code BOOST_CLASS_EXPORT_IMPLEMENT(foo) \encode for this.
 | 
|---|
 | 182 |  *  \li The only other issues encountered so far is that a class needs to get
 | 
|---|
 | 183 |  *    instantiated. Otherwise its (templated) serialization code is not present.
 | 
|---|
 | 184 |  *    There are ..._EXPORT keywords in boost::serialization for this. Similarly
 | 
|---|
 | 185 |  *    required when just the base class is created/instantiated but you also need
 | 
|---|
 | 186 |  *    derived classes.
 | 
|---|
 | 187 |  *  \li The boost::serialization documentation is in general quite helpful. Use
 | 
|---|
 | 188 |  *    above mentioned keywords to look for more information.
 | 
|---|
| [bc3411] | 189 |  *
 | 
|---|
 | 190 |  * 
 | 
|---|
| [caece4] | 191 |  * \date 2014-03-10
 | 
|---|
| [750cff] | 192 |  */
 | 
|---|