oarchive.hpp

00001 /*
00002 This file is part of GraphLab.
00003 
00004 GraphLab is free software: you can redistribute it and/or modify
00005 it under the terms of the GNU Lesser General Public License as 
00006 published by the Free Software Foundation, either version 3 of 
00007 the License, or (at your option) any later version.
00008 
00009 GraphLab is distributed in the hope that it will be useful,
00010 but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 GNU Lesser General Public License for more details.
00013 
00014 You should have received a copy of the GNU Lesser General Public 
00015 License along with GraphLab.  If not, see <http://www.gnu.org/licenses/>.
00016 */
00017 
00018 // This file should not be included directly. use serialize.hpp
00019 #ifndef GRAPHLAB_SERIALIZE_HPP
00020 #include <graphlab/serialization/serialize.hpp>
00021 
00022 #else
00023 
00024 #ifndef GRAPHLAB_OARCHIVE_HPP
00025 #define GRAPHLAB_OARCHIVE_HPP
00026 
00027 #include <iostream>
00028 #include <string>
00029 #include <graphlab/logger/assertions.hpp>
00030 #include <graphlab/serialization/is_pod.hpp>
00031 #include <graphlab/serialization/has_save.hpp>
00032 
00033 namespace graphlab {
00034 
00035 
00036   /**
00037    *  The output archive object.
00038    *  It is just a simple wrapper around a ostream. 
00039    */
00040   class oarchive{
00041   public:
00042     std::ostream* o;
00043     /// constructor. Takes a generic std::ostream object
00044     oarchive(std::ostream& os)
00045       : o(&os) {}
00046 
00047     ~oarchive() { }
00048   };
00049 
00050 /**
00051    * An alternate output archive object. 
00052    * When this object is used to serialize an object,
00053    * and the object does not support serialization,
00054    * failure will only occur at runtime.
00055    * \see oarchive
00056    */
00057   class oarchive_soft_fail{
00058   public:
00059     std::ostream* o;
00060 
00061     oarchive_soft_fail(std::ostream& os)
00062       : o(&os) {}
00063 
00064     oarchive_soft_fail(oarchive &oarc):o(oarc.o) {}
00065   
00066     ~oarchive_soft_fail() { }
00067   };
00068 
00069   namespace archive_detail {
00070 
00071     /// called by the regular archive The regular archive will do a hard fail
00072     template <typename ArcType, typename T>
00073     struct serialize_hard_or_soft_fail {
00074       static void exec(ArcType &o, const T& t) {
00075         t.save(o);
00076       }
00077     };
00078 
00079     /// called by the soft fail archive 
00080     template <typename T>
00081     struct serialize_hard_or_soft_fail<oarchive_soft_fail, T> {
00082       static void exec(oarchive_soft_fail &o, const T& t) {
00083         oarchive oarc(*(o.o));
00084         save_or_fail(oarc, t);
00085       }
00086     };
00087 
00088 
00089     /**
00090        Implementation of the serializer for different types.
00091        This is the catch-all. If it gets here, it must be a non-POD and is a class.
00092        We therefore call the .save function.
00093        Here we pick between the archive types using serialize_hard_or_soft_fail
00094     */
00095     template <typename ArcType, typename T, bool IsPOD>
00096     struct serialize_impl {
00097       static void exec(ArcType &o, const T& t) {
00098         serialize_hard_or_soft_fail<ArcType, T>::exec(o, t);
00099       }
00100     };
00101 
00102     /** Catch if type is a POD */
00103     template <typename ArcType, typename T>
00104     struct serialize_impl<ArcType, T, true> {
00105       static void exec(ArcType &a, const T& t) {
00106         a.o->write(reinterpret_cast<const char*>(&t), sizeof(T));
00107       }
00108     };
00109 
00110     /**
00111        Re-dispatch if for some reasons T already has a const
00112     */
00113     template <typename ArcType, typename T, bool IsPOD>
00114     struct serialize_impl<ArcType, const T, IsPOD> {
00115       static void exec(ArcType &o, const T& t) {
00116         serialize_impl<ArcType, T, IsPOD>::exec(o, t);
00117       }
00118     };
00119   }// archive_detail
00120 
00121 
00122   /**
00123      Allows Use of the "stream" syntax for serialization 
00124   */
00125   template <typename T>
00126   oarchive& operator<<(oarchive& a, const T& i) {
00127     archive_detail::serialize_impl<oarchive, T, gl_is_pod<T>::value >::exec(a, i);
00128     return a;
00129   }
00130 
00131   template <typename T>
00132   oarchive_soft_fail& operator<<(oarchive_soft_fail& a, const T& i) {
00133     archive_detail::serialize_impl<oarchive_soft_fail, T, gl_is_pod<T>::value >::exec(a, i);
00134     return a;
00135   }
00136 
00137 
00138   /**
00139      Serializes an arbitrary pointer + length to an archive 
00140   */
00141   inline oarchive& serialize(oarchive& a, const void* i,const size_t length) {
00142     // save the length
00143     operator<<(a,length);
00144     a.o->write(reinterpret_cast<const char*>(i), (std::streamsize)length);
00145     assert(!a.o->fail());
00146     return a;
00147   }
00148 
00149 
00150   /**
00151      Serializes an arbitrary pointer + length to an archive 
00152   */
00153   inline oarchive_soft_fail& serialize(oarchive_soft_fail& a, const void* i,const size_t length) {
00154     // save the length
00155     operator<<(a,length);
00156     a.o->write(reinterpret_cast<const char*>(i), (std::streamsize)length);
00157     assert(!a.o->fail());
00158     return a;
00159   }
00160 
00161 
00162 }
00163 
00164 /**
00165    Macro to make it easy to define out-of-place saves (and loads)
00166    to define an "out of place" save
00167    OUT_OF_PLACE_SAVE(arc, typename, tval) 
00168    arc << tval;    // do whatever serialization stuff you need here
00169    END_OUT_OF_PLACE_SAVE()
00170 
00171    \note important! this must be defined in the global namespace!
00172    See unsupported_serialize for an example
00173 */
00174 #define BEGIN_OUT_OF_PLACE_SAVE(arc, tname, tval)                       \
00175   namespace graphlab{ namespace archive_detail {                        \
00176   template <typename ArcType> struct serialize_impl<ArcType, tname, false> { \
00177   static void exec(ArcType& arc, const tname & tval) {
00178 
00179 #define END_OUT_OF_PLACE_SAVE() } }; } }
00180 
00181 
00182 #endif  
00183 
00184 #endif
00185 
00186 
00187 
00188 
00189 
00190 
00191 
00192 
00193 
00194