Turi Create  4.0
iarchive.hpp
1 /* Copyright © 2017 Apple Inc. All rights reserved.
2  *
3  * Use of this source code is governed by a BSD-3-clause license that can
4  * be found in the LICENSE.txt file or at https://opensource.org/licenses/BSD-3-Clause
5  */
6 #ifndef TURI_SERIALIZE_HPP
7 #include <core/storage/serialization/serialize.hpp>
8 
9 #else
10 
11 
12 #ifndef TURI_IARCHIVE_HPP
13 #define TURI_IARCHIVE_HPP
14 
15 #include <iostream>
16 #include <core/logging/assertions.hpp>
17 #include <core/storage/serialization/is_pod.hpp>
18 #include <core/storage/serialization/has_load.hpp>
19 #include <core/storage/serialization/dir_archive.hpp>
20 namespace turi {
21 
22  /**
23  * \ingroup group_serialization
24  * \brief The serialization input archive object which, provided
25  * with a reference to an istream, will read from the istream,
26  * providing deserialization capabilities.
27  *
28  * Given a source of serialized bytes (written by an turi::oarchive),
29  * in the form of a standard input stream, you can construct an iarchive
30  * object by:
31  * \code
32  * // where strm is an istream object
33  * turi::iarchive iarc(strm);
34  * \endcode
35  *
36  * For instance, to deserialize from a file,
37  * \code
38  * std::ifstream fin("inputfile.bin");
39  * turi::iarchive iarc(fin);
40  * \endcode
41  *
42  * Once the iarc object is constructed, \ref sec_serializable
43  * objects can be read from it using the >> stream operator.
44  *
45  * \code
46  * iarc >> a >> b >> c;
47  * \endcode
48  *
49  * Alternatively, data can be directly read from the stream using
50  * the iarchive::read() and iarchive::read_char() functions.
51  *
52  * For more usage details, see \ref serialization
53  *
54  * The iarchive object should not be used once the associated stream
55  * object is closed or is destroyed.
56  *
57  * To use this class, include
58  * core/storage/serialization/serialization_includes.hpp
59  */
60  class iarchive {
61  public:
62  std::istream* in = NULL;
63  dir_archive* dir = NULL;
64  const char* buf = NULL;
65  size_t off = 0;
66  size_t len = 0;
67 
68 
69  /**
70  * Constructs an iarchive object.
71  * Takes a reference to a generic std::istream object and associates
72  * the archive with it. Reads from the archive will read from the
73  * assiciated input stream.
74  */
75  inline iarchive(std::istream& instream)
76  : in(&instream) { }
77 
78  inline iarchive(const char* buf, size_t len)
79  : buf(buf), off(0), len(len) { }
80 
81 
82  inline iarchive(dir_archive& dirarc)
83  : in(dirarc.get_input_stream()),dir(&dirarc) {}
84 
85  ~iarchive() {}
86 
87  /// Directly reads a single character from the input stream
88  inline char read_char() {
89  char c;
90  if (buf) {
91  c = buf[off];
92  ++off;
93  } else {
94  in->get(c);
95  }
96  return c;
97  }
98 
99  /**
100  * Directly reads a sequence of "len" bytes from the
101  * input stream into the location pointed to by "c"
102  */
103  inline void read(char* c, size_t l) {
104  if (buf) {
105  memcpy(c, buf + off, l);
106  off += l;
107  } else {
108  in->read(c, l);
109  }
110  }
111 
112 
113  /**
114  * Directly reads a sequence of "len" bytes from the
115  * input stream into the location pointed to by "c"
116  */
117  template <typename T>
118  inline void read_into(T& c) {
119  if (buf) {
120  memcpy(&c, buf + off, sizeof(T));
121  off += sizeof(T);
122  } else {
123  in->read(reinterpret_cast<char*>(&c), sizeof(T));
124  }
125  }
126 
127  /// Returns true if the underlying stream is in a failure state
128  inline bool fail() {
129  return in == NULL ? off > len : in->fail();
130  }
131 
132  std::string get_prefix() {
133  ASSERT_NE(dir, NULL);
134  return dir->get_next_read_prefix();
135  }
136  };
137 
138 
139  /**
140  * \ingroup group_serialization
141  * \brief
142  * When this archive is used to deserialize an object,
143  * and the object does not support serialization,
144  * failure will only occur at runtime. Otherwise equivalent to
145  * turi::iarchive.
146  */
148  public:
149 
150  iarchive *iarc;
151  bool mine;
152 
153  /// Directly reads a single character from the input stream
154  inline char read_char() {
155  return iarc->read_char();
156  }
157 
158  /**
159  * Directly reads a sequence of "len" bytes from the
160  * input stream into the location pointed to by "c"
161  */
162  inline void read(char* c, size_t len) {
163  iarc->read(c, len);
164  }
165 
166  /**
167  * Directly reads a sequence of "len" bytes from the
168  * input stream into the location pointed to by "c"
169  */
170  template <typename T>
171  inline void read_into(T& c) {
172  iarc->read_into(c);
173  }
174 
175 
176  /// Returns true if the underlying stream is in a failure state
177  inline bool fail() {
178  return iarc->fail();
179  }
180 
181 
182  std::string get_prefix() {
183  return iarc->get_prefix();
184  }
185 
186  /**
187  * Constructs an iarchive_soft_fail object.
188  * Takes a reference to a generic std::istream object and associates
189  * the archive with it. Reads from the archive will read from the
190  * assiciated input stream.
191  */
192  inline iarchive_soft_fail(std::istream &instream)
193  : iarc(new iarchive(instream)), mine(true) {}
194 
195  /**
196  * Constructs an iarchive_soft_fail object from an iarchive.
197  * Both will share the same input stream
198  */
200  : iarc(&iarc), mine(false) {}
201 
202  inline ~iarchive_soft_fail() { if (mine) delete iarc; }
203  };
204 
205 
206  namespace archive_detail {
207 
208  /// called by the regular archive The regular archive will do a hard fail
209  template <typename InArcType, typename T>
210  struct deserialize_hard_or_soft_fail {
211  inline static void exec(InArcType& iarc, T& t) {
212  t.load(iarc);
213  }
214  };
215 
216  /// called by the soft fail archive
217  template <typename T>
218  struct deserialize_hard_or_soft_fail<iarchive_soft_fail, T> {
219  inline static void exec(iarchive_soft_fail& iarc, T& t) {
220  load_or_fail(*(iarc.iarc), t);
221  }
222  };
223 
224 
225  /**
226  Implementation of the deserializer for different types. This is the
227  catch-all. If it gets here, it must be a non-POD and is a class. We
228  therefore call the .save function. Here we pick between the archive
229  types using serialize_hard_or_soft_fail
230  */
231  template <typename InArcType, typename T, bool IsPOD, typename Enable = void>
232  struct deserialize_impl {
233  inline static void exec(InArcType& iarc, T& t) {
234  deserialize_hard_or_soft_fail<InArcType, T>::exec(iarc, t);
235  }
236  };
237 
238  // catch if type is a POD
239  template <typename InArcType, typename T>
240  struct deserialize_impl<InArcType, T, true>{
241  inline static void exec(InArcType& iarc, T &t) {
242  iarc.read_into(t);
243  }
244  };
245 
246  } //namespace archive_detail
247 
248  /// \cond TURI_INTERNAL
249 
250  /**
251  Allows Use of the "stream" syntax for serialization
252  */
253  template <typename T>
254  inline iarchive& operator>>(iarchive& iarc, T &t) {
255  archive_detail::deserialize_impl<iarchive,
256  T,
257  gl_is_pod<T>::value >::exec(iarc, t);
258  return iarc;
259  }
260 
261 
262 
263  /**
264  Allows Use of the "stream" syntax for serialization
265  */
266  template <typename T>
267  inline iarchive_soft_fail& operator>>(iarchive_soft_fail& iarc, T &t) {
268  archive_detail::deserialize_impl<iarchive_soft_fail,
269  T,
270  gl_is_pod<T>::value >::exec(iarc, t);
271  return iarc;
272  }
273 
274 
275  /**
276  deserializes an arbitrary pointer + length from an archive
277  */
278  inline iarchive& deserialize(iarchive& iarc,
279  void* str,
280  const size_t length) {
281  iarc.read(reinterpret_cast<char*>(str), (std::streamsize)length);
282  assert(!iarc.fail());
283  return iarc;
284  }
285 
286 
287 
288  /**
289  deserializes an arbitrary pointer + length from an archive
290  */
291  inline iarchive_soft_fail& deserialize(iarchive_soft_fail& iarc,
292  void* str,
293  const size_t length) {
294  iarc.read(reinterpret_cast<char*>(str), (std::streamsize)length);
295  assert(!iarc.fail());
296  return iarc;
297  }
298 
299  /// \endcond TURI_INTERNAL
300 
301  /**
302  \ingroup group_serialization
303 
304  \brief Macro to make it easy to define out-of-place loads
305 
306  In the event that it is impractical to implement a save() and load()
307  function in the class one wnats to serialize, it is necessary to define
308  an "out of save" save and load.
309 
310  See \ref sec_serializable_out_of_place for an example
311 
312  \note important! this must be defined in the global namespace!
313  */
314 #define BEGIN_OUT_OF_PLACE_LOAD(arc, tname, tval) \
315  namespace turi{ namespace archive_detail { \
316  template <typename InArcType> \
317  struct deserialize_impl<InArcType, tname, false>{ \
318  static void exec(InArcType& arc, tname & tval) {
319 
320 #define END_OUT_OF_PLACE_LOAD() } }; } }
321 
322 
323 
324 
325 } // namespace turi
326 
327 
328 #endif
329 
330 #endif
iarchive_soft_fail(iarchive &iarc)
Definition: iarchive.hpp:199
The serialization input archive object which, provided with a reference to an istream, will read from the istream, providing deserialization capabilities.
Definition: iarchive.hpp:60
general_ifstream * get_input_stream()
bool fail()
Returns true if the underlying stream is in a failure state.
Definition: iarchive.hpp:177
iarchive_soft_fail(std::istream &instream)
Definition: iarchive.hpp:192
void read_into(T &c)
Definition: iarchive.hpp:118
void read(char *c, size_t len)
Definition: iarchive.hpp:162
char read_char()
Directly reads a single character from the input stream.
Definition: iarchive.hpp:154
iarchive(std::istream &instream)
Definition: iarchive.hpp:75
std::string get_next_read_prefix()
bool fail()
Returns true if the underlying stream is in a failure state.
Definition: iarchive.hpp:128
void read(char *c, size_t l)
Definition: iarchive.hpp:103
char read_char()
Directly reads a single character from the input stream.
Definition: iarchive.hpp:88
Tests if T is a POD type.
Definition: is_pod.hpp:28
When this archive is used to deserialize an object, and the object does not support serialization...
Definition: iarchive.hpp:147