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 with array length first.
85 /// - serializeListBegin()/serializeListEnd(): begin/end serialization for
86 /// an ordered sequence of values.
87 /// - serializeUniformArray(): complete serialization of an ordered
88 /// sequence of POD type values.
89 ///
90 
91 
92 #include "UT_Array.h"
93 #include "UT_IStream.h"
94 #include "UT_OStream.h"
95 #include "UT_String.h"
96 #include "UT_StringHolder.h"
97 #include "UT_Tuple.h"
98 #include "UT_TupleUtil.h"
99 #include "UT_ValArray.h"
100 #include "UT_WorkBuffer.h"
101 #include <SYS/SYS_Types.h>
102 
103 #include <tuple>
104 #include <type_traits>
105 #include <utility>
106 
107 #include <stddef.h>
108 #include <string.h>
109 
110 
111 /// Default function for non-instrusive serialization of classes.
112 /// Specialize this when you can perform the same code using the archiver for
113 /// serialization. If it isn't specialized, then it will call the intrusive
114 /// version, which you must supply.
115 template <typename ARCHIVER_T, typename OBJ_T>
116 bool
117 UTserialize(ARCHIVER_T &archiver, OBJ_T &obj)
118 {
119  return obj.serialize(archiver);
120 }
121 
122 /// Specialize UTserializeSave/UTserializeLoad for serialization when
123 /// saving/loading needs to be different. By default, they just forward to the
124 /// regular UTserialize() method.
125 // @{
126 template <typename ARCHIVER_T, typename OBJ_T>
127 bool
128 UTserializeSave(ARCHIVER_T &archiver, OBJ_T &obj)
129 {
130  if (!UTserialize(archiver, obj))
131  return false;
132  return true;
133 }
134 template <typename ARCHIVER_T, typename OBJ_T>
135 bool
136 UTserializeLoad(ARCHIVER_T &archiver, OBJ_T &obj)
137 {
138  if (!UTserialize(archiver, obj))
139  return false;
140  return true;
141 }
142 // @}
143 
144 /// Alternatively, specialize these template structs when saving/loading need
145 /// to be different. By default, they just forward to the functional forms.
146 /// This form exists to make the templating easier for arrays.
147 // @{
148 template <typename OBJ_T>
150 {
151  template <typename ARCHIVER_T>
152  static bool invoke(ARCHIVER_T &archiver, OBJ_T &obj)
153  {
154  return UTserializeSave(archiver, obj);
155  }
156 };
157 template <typename OBJ_T>
159 {
160  template <typename ARCHIVER_T>
161  static bool invoke(ARCHIVER_T &archiver, OBJ_T &obj)
162  {
163  return UTserializeLoad(archiver, obj);
164  }
165 };
166 // @}
167 
168 // Generic serializables for basic types
169 #define UT_DECLARE_SERIALIZABLE(OBJ_T) \
170  template <typename ARCHIVER_T> \
171  bool UTserialize(ARCHIVER_T &archiver, OBJ_T &obj) \
172  { \
173  return archiver.serializeValue(obj); \
174  } \
175  /**/
184 #undef UT_DECLARE_SERIALIZABLE
185 
186 // UT_String and UT_WorkBuffer serializables
187 template <typename ARCHIVER_T>
188 bool
189 UTserializeSave(ARCHIVER_T &archiver, UT_String &str)
190 {
191  return archiver.serializeStringValue(str);
192 }
193 template <typename ARCHIVER_T>
194 bool
195 UTserializeLoad(ARCHIVER_T &archiver, UT_String &str)
196 {
198  if (!archiver.serializeStringValue(buf))
199  return false;
200  str.harden(buf.buffer());
201  return true;
202 }
203 template <typename ARCHIVER_T>
204 bool
205 UTserializeSave(ARCHIVER_T &archiver, UT_WorkBuffer &str)
206 {
207  return archiver.serializeStringValue(str.buffer());
208 };
209 template <typename ARCHIVER_T>
210 bool
211 UTserializeLoad(ARCHIVER_T &archiver, UT_WorkBuffer &str)
212 {
213  return archiver.serializeStringValue(str);
214 }
215 template <typename ARCHIVER_T>
216 bool
217 UTserializeSave(ARCHIVER_T &archiver, UT_StringHolder &str)
218 {
219  return archiver.serializeStringValue(str.c_str());
220 }
221 template <typename ARCHIVER_T>
222 bool
223 UTserializeLoad(ARCHIVER_T &archiver, UT_StringHolder &str)
224 {
226  if (!archiver.serializeStringValue(buf))
227  return false;
228  str = buf.buffer();
229  return true;
230 }
231 
232 
233 /// Array<T> serializable. This saves out an ordered sequence of type T's as
234 /// opposed to unordered maps. By design, we impose a schema where such arrays
235 /// always include the array length as the first element.
236 /// @{
237 template <typename T, template <typename> class ARRAY>
239 {
240  template <typename ARCHIVER_T>
241  static bool invoke(ARCHIVER_T &archiver, ARRAY<T> &vec)
242  {
243  if (!archiver.serializeArrayBegin(vec.entries()))
244  return false;
245  if (!archiver.serializeArray(vec.array(), vec.entries()))
246  return false;
247  if (!archiver.serializeArrayEnd())
248  return false;
249  return true;
250  }
251 };
252 template <typename T, template <typename> class ARRAY>
254 {
255  template <typename ARCHIVER_T>
256  static bool invoke(ARCHIVER_T &archiver, ARRAY<T> &vec)
257  {
258  int64 count;
259  if (!archiver.serializeArrayBegin(count))
260  return false;
261  vec.setSize(count);
262  if (!archiver.serializeArray(vec.array(), vec.entries()))
263  return false;
264  if (!archiver.serializeArrayEnd())
265  return false;
266  return true;
267  }
268 };
269 #define UT_DECLARE_ARRAY_SERIALIZABLE(ARRAY_T) \
270  template <typename T> \
271  struct UT_SaveSerializable< ARRAY_T<T> > \
272  : public UT_ArraySaveSerializable<T, ARRAY_T> { }; \
273  template <typename T> \
274  struct UT_LoadSerializable< ARRAY_T<T> > \
275  : public UT_ArrayLoadSerializable<T, ARRAY_T> { }; \
276  /**/
279 #undef UT_DECLARE_ARRAY_SERIALIZABLE
280 /// @}
281 
282 
283 /// std::pair serializable. This saves out the types as list of two items.
284 /// @{
285 template <typename V1, typename V2, template <typename, typename> class PairT>
287 {
288  template <typename ARCHIVER_T>
289  static bool invoke(ARCHIVER_T &archiver, PairT<V1,V2> &val)
290  {
291  if (!archiver.serializeListBegin())
292  return false;
293  if (!archiver.serializeValue(val.first))
294  return false;
295  if (!archiver.serializeValue(val.second))
296  return false;
297  if (!archiver.serializeListEnd())
298  return false;
299  return true;
300  }
301 };
302 #define UT_DECLARE_PAIR_SERIALIZABLE(PAIR_T) \
303  template <typename V1, typename V2> \
304  struct UT_SaveSerializable< PAIR_T<V1,V2> > \
305  : public UT_PairSerializable<V1, V2, PAIR_T> { }; \
306  template <typename V1, typename V2> \
307  struct UT_LoadSerializable< PAIR_T<V1,V2> > \
308  : public UT_PairSerializable<V1, V2, PAIR_T> { }; \
309  /**/
311 #undef UT_DECLARE_PAIR_SERIALIZABLE
312 /// @}
313 
314 
315 /// StringMap<T> serializable
316 /// @{
317 template <
318  typename V,
319  template <typename> class StringMapT
320 >
322 {
323  template <typename ARCHIVER_T>
324  static bool invoke(ARCHIVER_T &archiver, StringMapT<V> &map)
325  {
326  if (!archiver.serializeMapBegin())
327  return false;
328  for (auto &[key, val] : map)
329  {
330  if (!archiver.serializeKey(key))
331  return false;
332  if (!UT_SaveSerializable<V>::invoke(archiver, val))
333  return false;
334  }
335  if (!archiver.serializeMapEnd())
336  return false;
337  return true;
338  }
339 };
340 
341 template <
342  typename V,
343  template <typename> class StringMapT
344 >
346 {
347  template <typename ARCHIVER_T>
348  static bool invoke(ARCHIVER_T &archiver, StringMapT<V> &map)
349  {
350  UT_WorkBuffer key;
351 
352  if (!archiver.serializeMapBegin())
353  return false;
354 
355  while (!archiver.serializeMapEnd())
356  {
357  if (!archiver.serializeKey(key))
358  return false;
359  V val;
360  if (!UT_LoadSerializable<V>::invoke(archiver, val))
361  return false;
362  map[UT_StringHolder(std::move(key))] = std::move(val);
363  }
364  return true;
365  }
366 };
367 #define UT_DECLARE_STRINGMAP_SERIALIZABLE(MAP_T) \
368  template <typename V> \
369  struct UT_SaveSerializable< MAP_T<V> > \
370  : public UT_StringMapSaveSerializable<V, MAP_T> { }; \
371  template <typename V> \
372  struct UT_LoadSerializable< MAP_T<V> > \
373  : public UT_StringMapLoadSerializable<V, MAP_T> { }; \
374  /**/
375  template <typename T> class UT_StringMap;
376  template <typename T> class UT_ArrayStringMap;
379 #undef UT_DECLARE_ARRAY_SERIALIZABLE
380 /// @}
381 
382 
383 /// Base class for archivers.
384 // @{
385 template <typename ARCHIVER_T>
387 {
388 private:
389  class SaveKeyValue
390  {
391  public:
392  SaveKeyValue(ARCHIVER_T &archiver)
393  : myArchiver(archiver)
394  {
395  }
396 
397  template <typename PAIR_T>
398  bool operator()(const PAIR_T &p)
399  {
400  using namespace std;
401  typedef typename tuple_element<1,PAIR_T>::type ref_type;
402  typedef typename decay<ref_type>::type obj_type;
403 
404  if (!myArchiver.serializeKey(get<0>(p)))
405  return true;
406  if (!UT_SaveSerializable<obj_type>::invoke(myArchiver, get<1>(p)))
407  return true;
408  // return false to continue saving
409  return false;
410  }
411 
412  private:
413  ARCHIVER_T & myArchiver;
414  };
415 
416 public:
417  constexpr bool isLoading() const { return false; }
418  constexpr bool isSaving() const { return true; }
419 
420  template <typename T>
422  {
423  ARCHIVER_T *subclass = static_cast<ARCHIVER_T *>(this);
424  for (int64 i = 0; i < count; i++)
425  {
426  if (!UT_SaveSerializable<T>::invoke(*subclass, vec[i]))
427  return false;
428  }
429  return true;
430  }
431 
432  /// Called by user serialize() methods.
433  /// @param pair_seq A sequence of <key_type, value_type &> sequences
434  /// where key_type is const char *.
435  /// @note key literals should be in all LOWERCASE
436  template <typename SEQ_T>
437  bool operator()(const SEQ_T &pair_seq, bool /*case_sensitive*/=false)
438  {
439  ARCHIVER_T *subclass = static_cast<ARCHIVER_T *>(this);
440  if (!subclass->serializeMapBegin())
441  return false;
442  SaveKeyValue saver(*subclass);
443  if (UTtupleAnyOf(pair_seq, saver))
444  return false;
445  if (!subclass->serializeMapEnd())
446  return false;
447  return true;
448  }
449 
450 };
451 
452 template <typename ARCHIVER_T>
454 {
455 private:
456  class LoadKeyValue
457  {
458  public:
459  LoadKeyValue(ARCHIVER_T &archiver, const char *key, bool &ok)
460  : myArchiver(archiver)
461  , myKey(key)
462  , myOk(ok)
463  {
464  }
465 
466  // Return true when we've found the key we want and loaded it.
467  template <typename PAIR_T>
468  bool operator()(const PAIR_T &p) const
469  {
470  using namespace std;
471  typedef typename tuple_element<1,PAIR_T>::type ref_type;
472  typedef typename decay<ref_type>::type obj_type;
473 
474  if (::strcmp(myKey, get<0>(p)) != 0)
475  return false;
476  myOk = UT_LoadSerializable<obj_type>::invoke(myArchiver, get<1>(p));
477  return true; // quit looping
478  }
479 
480  bool ok() const
481  {
482  return myOk;
483  }
484 
485  private:
486  ARCHIVER_T & myArchiver;
487  const char * myKey;
488  bool & myOk;
489  };
490 
491 public:
492 
493  constexpr bool isLoading() const { return true; }
494  constexpr bool isSaving() const { return false; }
495 
496  template <typename T>
498  {
499  ARCHIVER_T *subclass = static_cast<ARCHIVER_T *>(this);
500  for (int64 i = 0; i < count; i++)
501  {
502  if (!UT_LoadSerializable<T>::invoke(*subclass, vec[i]))
503  return false;
504  }
505  return true;
506  }
507 
508  /// Called by user serialize() methods to serialize a map.
509  /// @param pair_seq A sequence of <key_type, value_type &> sequences where
510  /// key_type is const char *.
511  /// @param case_sensitive Default is to ignore case when matching keys.
512  /// Specify true to do case sensitive matches.
513  /// @note key literals should in all LOWERCASE for case_sensitve=false.
514  template <typename SEQ_T>
515  bool operator()(const SEQ_T &pair_seq, bool case_sensitive=false)
516  {
517  UT_WorkBuffer key;
518  ARCHIVER_T * subclass = static_cast<ARCHIVER_T *>(this);
519  bool ok = true;
520 
521  if (!subclass->serializeMapBegin())
522  return false;
523 
524  while (!subclass->serializeMapEnd())
525  {
526  if (!subclass->serializeKey(key))
527  return false;
528  if (!case_sensitive)
529  key.lower();
530  LoadKeyValue loader(*subclass, key.buffer(), ok);
531  (void)UTtupleAnyOf(pair_seq, loader);
532  if (!loader.ok())
533  return false;
534  }
535 
536  return true; // quit looping
537  }
538 
539 };
540 // @{
541 
542 
543 /// Manipulators for streaming archivers
544 // @{
545 template <typename OBJ_T, typename ARCHIVER_T>
547 {
548 public:
550  : myObj(obj)
551  {
552  }
554  {
555  typename ARCHIVER_T::Output archiver(out);
556  if (!UT_SaveSerializable<OBJ_T>::invoke(archiver, myObj))
557  out.setstate(std::ios::failbit);
558  return out;
559  }
560 private:
561  OBJ_T & myObj;
562 };
563 template <typename OBJ_T, typename ARCHIVER_T>
565 {
566 public:
568  : myObj(obj)
569  {
570  }
572  {
573  typename ARCHIVER_T::Input archiver(in);
574  if (!UT_LoadSerializable<OBJ_T>::invoke(archiver, myObj))
575  in.setError(true);
576  return in;
577  }
578 private:
579  OBJ_T & myObj;
580 };
581 // @}
582 
583 /// UT_OStream manipulator << overload
584 template <typename OBJ_T, typename ARCHIVER_T>
585 UT_OStream &
586 operator<<(UT_OStream &out, UT_SaveArchiverManip<OBJ_T,ARCHIVER_T> manip)
587 {
588  return manip(out);
589 }
590 /// UT_IStream manipulator >> overload
591 template <typename OBJ_T, typename ARCHIVER_T>
592 UT_IStream &
594 {
595  return manip(in);
596 }
597 
598 #endif // __UT_SERIALIZATION_H_INCLUDED__
type
Definition: core.h:556
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: glcorearb.h:2540
int int32
Definition: SYS_Types.h:39
void
Definition: png.h:1083
static bool invoke(ARCHIVER_T &archiver, OBJ_T &obj)
bool operator()(const SEQ_T &pair_seq, bool=false)
constexpr bool isLoading() const
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)
constexpr auto in(type t, int set) -> bool
Definition: core.h:611
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
static bool invoke(ARCHIVER_T &archiver, StringMapT< V > &map)
Base class for archivers.
constexpr bool isSaving() const
static bool invoke(ARCHIVER_T &archiver, StringMapT< V > &map)
static bool invoke(ARCHIVER_T &archiver, ARRAY< T > &vec)
void harden()
Take shallow copy and make it deep.
Definition: UT_String.h:222
#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
constexpr bool isLoading() const
static bool invoke(ARCHIVER_T &archiver, ARRAY< T > &vec)
constexpr 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
GLuint GLfloat * val
Definition: glcorearb.h:1608
static bool invoke(ARCHIVER_T &archiver, OBJ_T &obj)
static bool invoke(ARCHIVER_T &archiver, PairT< V1, V2 > &val)
#define UT_DECLARE_PAIR_SERIALIZABLE(PAIR_T)
#define UT_DECLARE_STRINGMAP_SERIALIZABLE(MAP_T)
Manipulators for streaming archivers.
UT_IStream & operator()(UT_IStream &in)
bool UTserializeLoad(ARCHIVER_T &archiver, OBJ_T &obj)
bool operator()(const SEQ_T &pair_seq, bool case_sensitive=false)
void lower()
Convert string to lower case.
GLint GLsizei count
Definition: glcorearb.h:405
void setstate(std::ios::iostate state)
Definition: UT_OStream.h:95