GraphLab: Distributed Graph-Parallel API  2.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
oarchive.hpp
1 /*
2  * Copyright (c) 2009 Carnegie Mellon University.
3  * All rights reserved.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing,
12  * software distributed under the License is distributed on an "AS
13  * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
14  * express or implied. See the License for the specific language
15  * governing permissions and limitations under the License.
16  *
17  * For more about this software visit:
18  *
19  * http://www.graphlab.ml.cmu.edu
20  *
21  */
22 
23 
24 // This file should not be included directly. use serialize.hpp
25 #ifndef GRAPHLAB_SERIALIZE_HPP
26 #include <graphlab/serialization/serialize.hpp>
27 
28 #else
29 
30 #ifndef GRAPHLAB_OARCHIVE_HPP
31 #define GRAPHLAB_OARCHIVE_HPP
32 
33 #include <iostream>
34 #include <string>
35 #include <graphlab/logger/assertions.hpp>
36 #include <graphlab/serialization/is_pod.hpp>
37 #include <graphlab/serialization/has_save.hpp>
38 
39 namespace graphlab {
40 
41  /**
42  * \ingroup group_serialization
43  * \brief The serialization output archive object which, provided
44  * with a reference to an ostream, will write to the ostream,
45  * providing serialization capabilities.
46  *
47  * Given a standard output stream, you can construct an oarchive
48  * object by:
49  * \code
50  * // where strm is an ostream object
51  * graphlab::oarchive oarc(strm);
52  * \endcode
53  *
54  * For instance, to serialize to a file,
55  * \code
56  * std::ofstream fout("outputfile.bin");
57  * graphlab::oarchive oarc(fout);
58  * \endcode
59  *
60  * Once the oarc object is constructed, \ref sec_serializable objects can be
61  * written to it using the << stream operator.
62  *
63  * \code
64  * oarc << a << b << c;
65  * \endcode
66  *
67  * Alternatively, data can be directly written to the stream
68  * using the oarchive::write() function.
69  *
70  * Written data can be deserialized using graphlab::iarchive.
71  * For more usage details, see \ref serialization
72  *
73  * The oarchive object should not be used once the associated stream
74  * object is closed or is destroyed.
75  *
76  * The oarc object
77  * does <b> not </b> flush the associated stream, and the user may need to
78  * manually flush the associated stream to clear any stream buffers.
79  * For instance, while the std::stringstream may be used for both output
80  * and input, it is necessary to flush the stream before all bytes written to
81  * the stringstream are available for input.
82  *
83  * To use this class, include
84  * graphlab/serialization/serialization_includes.hpp
85  */
86  class oarchive{
87  public:
88  std::ostream* out;
89  char* buf;
90  size_t off;
91  size_t len;
92  /// constructor. Takes a generic std::ostream object
93  inline oarchive(std::ostream& outstream)
94  : out(&outstream),buf(NULL),off(0),len(0) {}
95 
96  inline oarchive(void)
97  : out(NULL),buf(NULL),off(0),len(0) {}
98 
99  inline void expand_buf(size_t s) {
100  if (off + s > len) {
101  len = 2 * (s + len);
102  buf = (char*)realloc(buf, len);
103  }
104  }
105  /** Directly writes "s" bytes from the memory location
106  * pointed to by "c" into the stream.
107  */
108  inline void write(const char* c, std::streamsize s) {
109  if (out == NULL) {
110  expand_buf(s);
111  memcpy(buf + off, c, s);
112  off += s;
113  } else {
114  out->write(c, s);
115  }
116  }
117  template <typename T>
118  inline void direct_assign(const T& t) {
119  if (out == NULL) {
120  expand_buf(sizeof(T));
121  (*reinterpret_cast<T*>(buf + off)) = t;
122  off += sizeof(T);
123  }
124  else {
125  T localt = t;
126  out->write(reinterpret_cast<char*>(&localt), sizeof(T));
127  }
128  }
129 
130  inline void advance(size_t s) {
131  if (out == NULL) {
132  expand_buf(s);
133  off += s;
134  } else {
135  out->seekp(s, std::ios_base::cur);
136  }
137  }
138 
139  /// Returns true if the underlying stream is in a failure state
140  inline bool fail() {
141  return out == NULL ? false : out->fail();
142  }
143 
144  inline ~oarchive() { }
145  };
146 
147  /**
148  * \ingroup group_serialization
149  * \brief
150  * When this archive is used to serialize an object,
151  * and the object does not support serialization,
152  * failure will only occur at runtime. Otherwise equivalent to
153  * graphlab::oarchive
154  */
156  public:
157  oarchive* oarc;
158  bool mine;
159 
160  /// constructor. Takes a generic std::ostream object
161  inline oarchive_soft_fail(std::ostream& outstream)
162  : oarc(new oarchive(outstream)), mine(true) { }
163 
164  inline oarchive_soft_fail(oarchive& oarc):oarc(&oarc), mine(false) {
165  }
166 
167  inline oarchive_soft_fail(void)
168  : oarc(new oarchive) {}
169 
170  /** Directly writes "s" bytes from the memory location
171  * pointed to by "c" into the stream.
172  */
173  inline void write(const char* c, std::streamsize s) {
174  oarc->write(c, s);
175  }
176  template <typename T>
177  inline void direct_assign(const T& t) {
178  oarc->direct_assign(t);
179  }
180 
181  inline bool fail() {
182  return oarc->fail();
183  }
184 
185  inline ~oarchive_soft_fail() {
186  if (mine) delete oarc;
187  }
188  };
189 
190  namespace archive_detail {
191 
192  /// called by the regular archive The regular archive will do a hard fail
193  template <typename OutArcType, typename T>
194  struct serialize_hard_or_soft_fail {
195  inline static void exec(OutArcType& oarc, const T& t) {
196  t.save(oarc);
197  }
198  };
199 
200  /// called by the soft fail archive
201  template <typename T>
202  struct serialize_hard_or_soft_fail<oarchive_soft_fail, T> {
203  inline static void exec(oarchive_soft_fail& oarc, const T& t) {
204  // create a regular oarchive and
205  // use the save_or_fail function which will
206  // perform a soft fail
207  save_or_fail(*(oarc.oarc), t);
208  }
209  };
210 
211 
212  /**
213  Implementation of the serializer for different types.
214  This is the catch-all. If it gets here, it must be a non-POD and is a class.
215  We therefore call the .save function.
216  Here we pick between the archive types using serialize_hard_or_soft_fail
217  */
218  template <typename OutArcType, typename T, bool IsPOD>
219  struct serialize_impl {
220  static void exec(OutArcType& oarc, const T& t) {
221  serialize_hard_or_soft_fail<OutArcType, T>::exec(oarc, t);
222  }
223  };
224 
225  /** Catch if type is a POD */
226  template <typename OutArcType, typename T>
227  struct serialize_impl<OutArcType, T, true> {
228  inline static void exec(OutArcType& oarc, const T& t) {
229  oarc.direct_assign(t);
230  //oarc.write(reinterpret_cast<const char*>(&t), sizeof(T));
231  }
232  };
233 
234  /**
235  Re-dispatch if for some reasons T already has a const
236  */
237  template <typename OutArcType, typename T>
238  struct serialize_impl<OutArcType, const T, true> {
239  inline static void exec(OutArcType& oarc, const T& t) {
240  serialize_impl<OutArcType, T, true>::exec(oarc, t);
241  }
242  };
243 
244  /**
245  Re-dispatch if for some reasons T already has a const
246  */
247  template <typename OutArcType, typename T>
248  struct serialize_impl<OutArcType, const T, false> {
249  inline static void exec(OutArcType& oarc, const T& t) {
250  serialize_impl<OutArcType, T, false>::exec(oarc, t);
251  }
252  };
253  }// archive_detail
254 
255 
256  /// \cond GRAPHLAB_INTERNAL
257 
258  /**
259  Overloads the operator<< in the oarchive to
260  allow the use of the stream syntax for serialization.
261  It simply re-dispatches into the serialize_impl classes
262  */
263  template <typename T>
264  inline oarchive& operator<<(oarchive& oarc, const T& t) {
265  archive_detail::serialize_impl<oarchive,
266  T,
267  gl_is_pod<T>::value >::exec(oarc, t);
268  return oarc;
269  }
270 
271  /**
272  Overloads the operator<< in the oarchive_soft_fail to
273  allow the use of the stream syntax for serialization.
274  It simply re-dispatches into the serialize_impl classes
275  */
276  template <typename T>
277  inline oarchive_soft_fail& operator<<(oarchive_soft_fail& oarc,
278  const T& t) {
279  archive_detail::serialize_impl<oarchive_soft_fail,
280  T,
281  gl_is_pod<T>::value >::exec(oarc, t);
282  return oarc;
283  }
284 
285 
286  /**
287  Serializes an arbitrary pointer + length to an archive
288  */
289  inline oarchive& serialize(oarchive& oarc,
290  const void* str,
291  const size_t length) {
292  // save the length
293  oarc.write(reinterpret_cast<const char*>(str),
294  (std::streamsize)length);
295  assert(!oarc.fail());
296  return oarc;
297  }
298 
299 
300  /**
301  Serializes an arbitrary pointer + length to an archive
302  */
303  inline oarchive_soft_fail& serialize(oarchive_soft_fail& oarc,
304  const void* str,
305  const size_t length) {
306  // save the length
307  oarc.write(reinterpret_cast<const char*>(str),
308  (std::streamsize)length);
309  assert(!oarc.fail());
310  return oarc;
311  }
312 
313  /// \endcond GRAPHLAB_INTERNAL
314 
315 }
316  /**
317  \ingroup group_serialization
318  \brief Macro to make it easy to define out-of-place saves
319 
320  In the event that it is impractical to implement a save() and load()
321  function in the class one wnats to serialize, it is necessary to define
322  an "out of save" save and load.
323 
324  See \ref sec_serializable_out_of_place for an example
325 
326  \note important! this must be defined in the global namespace!
327  */
328 #define BEGIN_OUT_OF_PLACE_SAVE(arc, tname, tval) \
329  namespace graphlab{ namespace archive_detail { \
330  template <typename OutArcType> struct serialize_impl<OutArcType, tname, false> { \
331  static void exec(OutArcType& arc, const tname & tval) {
332 
333 #define END_OUT_OF_PLACE_SAVE() } }; } }
334 
335 
336 #endif
337 
338 #endif
339 
340 
341 
342 
343 
344 
345 
346 
347 
348