HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
UT_Serialization.h
Go to the documentation of this file.
1 /*
2  * PROPRIETARY INFORMATION. This software is proprietary to
3  * Side Effects Software Inc., and is not to be reproduced,
4  * transmitted, or disclosed in any way without written permission.
5  *
6  * NAME: UT_Serialization.h (UT Library, C++)
7  *
8  * COMMENTS: Generic class serialization
9  *
10  */
11 
12 #ifndef __UT_SERIALIZATION_H_INCLUDED__
13 #define __UT_SERIALIZATION_H_INCLUDED__
14 
15 /// @file
16 /// Generic class serialization support
17 ///
18 /// Support structure for generic class serialization.If you just want to
19 /// save/load to/from classes that already have serialize() methods, then see
20 /// UT_JSONArchive.h.
21 ///
22 /// To add support for serializing your data, you have two choices for
23 /// implementation:
24 ///
25 /// -# Implement instrusive serialize() class methods. eg.
26 /// @code
27 /// template <typename ARCHIVER_T>
28 /// bool LIB_MyClass::serialize(ARCHIVER_T &archiver)
29 /// {
30 /// using namespace std;
31 ///
32 /// // serialize an unordered map of key value pairs
33 /// if (!archiver(make_tuple(
34 /// make_tuple("key1", myValue),
35 /// make_tuple("key2", mySpecificRefArray)
36 /// /* ... etc ... */
37 /// )))
38 /// return false;
39 /// }
40 /// @endcode
41 /// @note You can just declare the template function in your header and
42 /// only implement it in the .C file if you're always going to
43 /// load/save within your class.
44 ///
45 /// -# Partially specialize UTserialize() to serialize your data. eg.
46 /// @code
47 /// template <typename ARCHIVER_T>
48 /// bool
49 /// UTserialize(ARCHIVER_T &archiver, LIB_MyClass &obj)
50 /// {
51 /// using namespace std;
52 ///
53 /// // serialize an unordered map of key value pairs
54 /// if (!archiver(make_tuple(
55 /// make_tuple("key1", myValue),
56 /// make_tuple("key2", mySpecificRefArray)
57 /// /* ... etc ... */
58 /// )))
59 /// return false;
60 /// }
61 /// @endcode
62 ///
63 /// To implement serialization for custom types that need different handling
64 /// between saving and loading, you specialize UTserializeSave/UTserializeLoad
65 /// instead. For member serialize() methods, you can also call
66 /// archiver.isLoading() or archiver.isSaving().
67 ///
68 /// To create a new archive type for serialization to a specific format,
69 /// see UT_JSONArchive.h as an example. There are some requirements:
70 /// - Create an archive class like UT_JSONArchive. This provides a partially
71 /// specialized class of UT_ArchiveManip<T,Archiver>.
72 /// - Your Archiver class should have two nested classes within it:
73 /// - class Input : public UT_LoadArchiver<Input>
74 /// - class Output : public UT_SaveArchiver<Output>
75 /// - In turn, your Input/Output archiver classes need the following methods:
76 /// - serializeValue<T>(): serialize a value of a POD type T.
77 /// - serializeStringValue(): serialize a C string
78 /// - serializeMapBegin()/serializeMapEnd(): begin/end serialization for an
79 /// unordered collection of key value pairs. As an archiver implementer,
80 /// you're free to ignore the unordered requirement if you want but the
81 /// client serialize code is already setup to support it.
82 /// bool serializeKey(UT_WorkBuffer &key)
83 /// - serializeArrayBegin()/serializeArrayEnd(): begin/end serialization for
84 /// an ordered sequence of values.
85 /// - serializeUniformArray(): complete serialization of an ordered
86 /// sequence of POD type values.
87 ///
88 
89 
90 #include "UT_IStream.h"
91 #include "UT_OStream.h"
92 #include "UT_Array.h"
93 #include "UT_String.h"
94 #include "UT_StringHolder.h"
95 #include "UT_TupleUtil.h"
96 #include "UT_ValArray.h"
97 #include "UT_WorkBuffer.h"
98 #include <SYS/SYS_Types.h>
99 
100 #include <tuple>
101 #include <type_traits>
102 #include <utility>
103 
104 #include <stddef.h>
105 #include <string.h>
106 
107 
108 /// Default function for non-instrusive serialization of classes.
109 /// Specialize this when you can perform the same code using the archiver for
110 /// serialization. If it isn't specialized, then it will call the intrusive
111 /// version, which you must supply.
112 template <typename ARCHIVER_T, typename OBJ_T>
113 bool
114 UTserialize(ARCHIVER_T &archiver, OBJ_T &obj)
115 {
116  return obj.serialize(archiver);
117 }
118 
119 /// Specialize UTserializeSave/UTserializeLoad for serialization when
120 /// saving/loading needs to be different. By default, they just forward to the
121 /// regular UTserialize() method.
122 // @{
123 template <typename ARCHIVER_T, typename OBJ_T>
124 bool
125 UTserializeSave(ARCHIVER_T &archiver, OBJ_T &obj)
126 {
127  if (!UTserialize(archiver, obj))
128  return false;
129  return true;
130 }
131 template <typename ARCHIVER_T, typename OBJ_T>
132 bool
133 UTserializeLoad(ARCHIVER_T &archiver, OBJ_T &obj)
134 {
135  if (!UTserialize(archiver, obj))
136  return false;
137  return true;
138 }
139 // @}
140 
141 /// Alternatively, specialize these template structs when saving/loading need
142 /// to be different. By default, they just forward to the functional forms.
143 /// This form exists to make the templating easier for arrays.
144 // @{
145 template <typename OBJ_T>
147 {
148  template <typename ARCHIVER_T>
149  static bool invoke(ARCHIVER_T &archiver, OBJ_T &obj)
150  {
151  return UTserializeSave(archiver, obj);
152  }
153 };
154 template <typename OBJ_T>
156 {
157  template <typename ARCHIVER_T>
158  static bool invoke(ARCHIVER_T &archiver, OBJ_T &obj)
159  {
160  return UTserializeLoad(archiver, obj);
161  }
162 };
163 // @}
164 
165 // Generic serializables for basic types
166 #define UT_DECLARE_SERIALIZABLE(OBJ_T) \
167  template <typename ARCHIVER_T> \
168  bool UTserialize(ARCHIVER_T &archiver, OBJ_T &obj) \
169  { \
170  return archiver.serializeValue(obj); \
171  } \
172  /**/
181 #undef UT_DECLARE_SERIALIZABLE
182 
183 // UT_String and UT_WorkBuffer serializables
184 template <typename ARCHIVER_T>
185 bool
186 UTserializeSave(ARCHIVER_T &archiver, UT_String &str)
187 {
188  return archiver.serializeStringValue(str);
189 }
190 template <typename ARCHIVER_T>
191 bool
192 UTserializeLoad(ARCHIVER_T &archiver, UT_String &str)
193 {
195  if (!archiver.serializeStringValue(buf))
196  return false;
197  str.harden(buf.buffer());
198  return true;
199 }
200 template <typename ARCHIVER_T>
201 bool
202 UTserializeSave(ARCHIVER_T &archiver, UT_WorkBuffer &str)
203 {
204  return archiver.serializeStringValue(str.buffer());
205 };
206 template <typename ARCHIVER_T>
207 bool
208 UTserializeLoad(ARCHIVER_T &archiver, UT_WorkBuffer &str)
209 {
210  return archiver.serializeStringValue(str);
211 }
212 template <typename ARCHIVER_T>
213 bool
214 UTserializeSave(ARCHIVER_T &archiver, UT_StringHolder &str)
215 {
216  return archiver.serializeStringValue(str.c_str());
217 }
218 template <typename ARCHIVER_T>
219 bool
220 UTserializeLoad(ARCHIVER_T &archiver, UT_StringHolder &str)
221 {
223  if (!archiver.serializeStringValue(buf))
224  return false;
225  str = buf.buffer();
226  return true;
227 }
228 
229 
230 /// Array<T> serializable. This saves out an ordered sequence of type T's as
231 /// opposed to unordered maps. By design, we impose a schema where such arrays
232 /// always include the array length as the first element.
233 template <typename T, template <typename> class ARRAY>
235 {
236  template <typename ARCHIVER_T>
237  static bool invoke(ARCHIVER_T &archiver, ARRAY<T> &vec)
238  {
239  if (!archiver.serializeArrayBegin(vec.entries()))
240  return false;
241  if (!archiver.serializeArray(vec.array(), vec.entries()))
242  return false;
243  if (!archiver.serializeArrayEnd())
244  return false;
245  return true;
246  }
247 };
248 template <typename T, template <typename> class ARRAY>
250 {
251  template <typename ARCHIVER_T>
252  static bool invoke(ARCHIVER_T &archiver, ARRAY<T> &vec)
253  {
254  int64 count;
255  if (!archiver.serializeArrayBegin(count))
256  return false;
257  vec.setSize(count);
258  if (!archiver.serializeArray(vec.array(), vec.entries()))
259  return false;
260  if (!archiver.serializeArrayEnd())
261  return false;
262  return true;
263  }
264 };
265 #define UT_DECLARE_ARRAY_SERIALIZABLE(ARRAY_T) \
266  template <typename T> \
267  struct UT_SaveSerializable< ARRAY_T<T> > \
268  : public UT_ArraySaveSerializable<T, ARRAY_T> { }; \
269  template <typename T> \
270  struct UT_LoadSerializable< ARRAY_T<T> > \
271  : public UT_ArrayLoadSerializable<T, ARRAY_T> { }; \
272  /**/
275 #undef UT_DECLARE_ARRAY_SERIALIZABLE
276 
277 /// Base class for archivers.
278 // @{
279 template <typename ARCHIVER_T>
281 {
282 private:
283  class SaveKeyValue
284  {
285  public:
286  SaveKeyValue(ARCHIVER_T &archiver)
287  : myArchiver(archiver)
288  {
289  }
290 
291  template <typename PAIR_T>
292  bool operator()(const PAIR_T &p)
293  {
294  using namespace std;
295  typedef typename tuple_element<1,PAIR_T>::type ref_type;
296  typedef typename decay<ref_type>::type obj_type;
297 
298  if (!myArchiver.serializeKey(get<0>(p)))
299  return true;
300  if (!UT_SaveSerializable<obj_type>::invoke(myArchiver, get<1>(p)))
301  return true;
302  // return false to continue saving
303  return false;
304  }
305 
306  private:
307  ARCHIVER_T & myArchiver;
308  };
309 
310 public:
311  bool isLoading() const { return false; }
312  bool isSaving() const { return true; }
313 
314  template <typename T>
316  {
317  ARCHIVER_T *subclass = static_cast<ARCHIVER_T *>(this);
318  for (int64 i = 0; i < count; i++)
319  {
320  if (!UT_SaveSerializable<T>::invoke(*subclass, vec[i]))
321  return false;
322  }
323  return true;
324  }
325 
326  /// Called by user serialize() methods.
327  /// @param pair_seq A sequence of <key_type, value_type &> sequences
328  /// where key_type is const char *.
329  /// @note key literals should in all LOWERCASE
330  template <typename SEQ_T>
331  bool operator()(const SEQ_T &pair_seq)
332  {
333  ARCHIVER_T *subclass = static_cast<ARCHIVER_T *>(this);
334  if (!subclass->serializeMapBegin())
335  return false;
336  SaveKeyValue saver(*subclass);
337  if (UTtupleAnyOf(pair_seq, saver))
338  return false;
339  if (!subclass->serializeMapEnd())
340  return false;
341  return true;
342  }
343 
344 };
345 
346 template <typename ARCHIVER_T>
348 {
349 private:
350  class LoadKeyValue
351  {
352  public:
353  LoadKeyValue(ARCHIVER_T &archiver, const char *key, bool &ok)
354  : myArchiver(archiver)
355  , myKey(key)
356  , myOk(ok)
357  {
358  }
359 
360  // Return true when we've found the key we want and loaded it.
361  template <typename PAIR_T>
362  bool operator()(const PAIR_T &p) const
363  {
364  using namespace std;
365  typedef typename tuple_element<1,PAIR_T>::type ref_type;
366  typedef typename decay<ref_type>::type obj_type;
367 
368  if (::strcmp(myKey, get<0>(p)) != 0)
369  return false;
370  myOk = UT_LoadSerializable<obj_type>::invoke(myArchiver, get<1>(p));
371  return true; // quit looping
372  }
373 
374  bool ok() const
375  {
376  return myOk;
377  }
378 
379  private:
380  ARCHIVER_T & myArchiver;
381  const char * myKey;
382  bool & myOk;
383  };
384 
385 public:
386 
387  bool isLoading() const { return true; }
388  bool isSaving() const { return false; }
389 
390  template <typename T>
392  {
393  ARCHIVER_T *subclass = static_cast<ARCHIVER_T *>(this);
394  for (int64 i = 0; i < count; i++)
395  {
396  if (!UT_LoadSerializable<T>::invoke(*subclass, vec[i]))
397  return false;
398  }
399  return true;
400  }
401 
402  /// Called by user serialize() methods to serialize a map.
403  /// @param pair_seq A sequence of <key_type, value_type &> sequences where
404  /// key_type is const char *.
405  /// @note key literals should in all LOWERCASE
406  template <typename SEQ_T>
407  bool operator()(const SEQ_T &pair_seq)
408  {
409  UT_WorkBuffer key;
410  ARCHIVER_T * subclass = static_cast<ARCHIVER_T *>(this);
411  bool ok = true;
412  bool keep_going;
413 
414  for (keep_going = subclass->serializeMapBegin();
415  keep_going;
416  keep_going = !subclass->serializeMapEnd())
417  {
418  if (!subclass->serializeKey(key))
419  return false;
420  LoadKeyValue loader(*subclass, key.buffer(), ok);
421  (void) UTtupleAnyOf(pair_seq, loader);
422  if (!loader.ok())
423  return false;
424  }
425  return true; // quit looping
426  }
427 
428 };
429 // @{
430 
431 
432 /// Manipulators for streaming archivers
433 // @{
434 template <typename OBJ_T, typename ARCHIVER_T>
436 {
437 public:
439  : myObj(obj)
440  {
441  }
443  {
444  typename ARCHIVER_T::Output archiver(out);
445  if (!UT_SaveSerializable<OBJ_T>::invoke(archiver, myObj))
446  out.setstate(std::ios::failbit);
447  return out;
448  }
449 private:
450  OBJ_T & myObj;
451 };
452 template <typename OBJ_T, typename ARCHIVER_T>
454 {
455 public:
457  : myObj(obj)
458  {
459  }
461  {
462  typename ARCHIVER_T::Input archiver(in);
463  if (!UT_LoadSerializable<OBJ_T>::invoke(archiver, myObj))
464  in.setError(true);
465  return in;
466  }
467 private:
468  OBJ_T & myObj;
469 };
470 // @}
471 
472 /// UT_OStream manipulator << overload
473 template <typename OBJ_T, typename ARCHIVER_T>
474 UT_OStream &
475 operator<<(UT_OStream &out, UT_SaveArchiverManip<OBJ_T,ARCHIVER_T> manip)
476 {
477  return manip(out);
478 }
479 /// UT_IStream manipulator >> overload
480 template <typename OBJ_T, typename ARCHIVER_T>
481 UT_IStream &
483 {
484  return manip(in);
485 }
486 
487 #endif // __UT_SERIALIZATION_H_INCLUDED__
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: glcorearb.h:2540
int int32
Definition: SYS_Types.h:39
bool operator()(const SEQ_T &pair_seq)
void
Definition: png.h:1083
bool operator()(const SEQ_T &pair_seq)
static bool invoke(ARCHIVER_T &archiver, OBJ_T &obj)
SYS_FORCE_INLINE const char * buffer() const
float fpreal32
Definition: SYS_Types.h:200
bool serializeArray(T *vec, int64 count)
bool serializeArray(T *vec, int64 count)
UT_IStream & operator>>(UT_IStream &in, UT_LoadArchiverManip< OBJ_T, ARCHIVER_T > manip)
UT_IStream manipulator >> overload.
bool UTtupleAnyOf(T &&tuple, F &&f)
Definition: UT_TupleUtil.h:82
double fpreal64
Definition: SYS_Types.h:201
bool isSaving() const
Base class for archivers.
bool isLoading() const
static bool invoke(ARCHIVER_T &archiver, ARRAY< T > &vec)
void harden()
Take shallow copy and make it deep.
Definition: UT_String.h:215
#define UT_DECLARE_ARRAY_SERIALIZABLE(ARRAY_T)
long long int64
Definition: SYS_Types.h:116
SYS_FORCE_INLINE const char * c_str() const
#define UT_DECLARE_SERIALIZABLE(OBJ_T)
UT_LoadArchiverManip(OBJ_T &obj)
signed char int8
Definition: SYS_Types.h:35
UT_OStream & operator()(UT_OStream &out)
void setError(bool is_error)
Definition: UT_IStream.h:152
static bool invoke(ARCHIVER_T &archiver, ARRAY< T > &vec)
bool isLoading() const
bool isSaving() const
bool UTserializeSave(ARCHIVER_T &archiver, OBJ_T &obj)
bool UTserialize(ARCHIVER_T &archiver, OBJ_T &obj)
UT_SaveArchiverManip(OBJ_T &obj)
short int16
Definition: SYS_Types.h:37
static bool invoke(ARCHIVER_T &archiver, OBJ_T &obj)
Manipulators for streaming archivers.
UT_IStream & operator()(UT_IStream &in)
bool UTserializeLoad(ARCHIVER_T &archiver, OBJ_T &obj)
type
Definition: core.h:1059
GLint GLsizei count
Definition: glcorearb.h:405
void setstate(std::ios::iostate state)
Definition: UT_OStream.h:95