add cereal library
[platform/upstream/iotivity.git] / extlibs / cereal / cereal / include / cereal / cereal.hpp
1 /*! \file cereal.hpp
2     \brief Main cereal functionality */
3 /*
4   Copyright (c) 2014, Randolph Voorhies, Shane Grant
5   All rights reserved.
6
7   Redistribution and use in source and binary forms, with or without
8   modification, are permitted provided that the following conditions are met:
9       * Redistributions of source code must retain the above copyright
10         notice, this list of conditions and the following disclaimer.
11       * Redistributions in binary form must reproduce the above copyright
12         notice, this list of conditions and the following disclaimer in the
13         documentation and/or other materials provided with the distribution.
14       * Neither the name of cereal nor the
15         names of its contributors may be used to endorse or promote products
16         derived from this software without specific prior written permission.
17
18   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19   ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20   WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21   DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES OR SHANE GRANT BE LIABLE FOR ANY
22   DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23   (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24   LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25   ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29 #ifndef CEREAL_CEREAL_HPP_
30 #define CEREAL_CEREAL_HPP_
31
32 #include <type_traits>
33 #include <string>
34 #include <memory>
35 #include <unordered_map>
36 #include <unordered_set>
37 #include <vector>
38 #include <cstddef>
39 #include <cstdint>
40 #include <functional>
41
42 #include <cereal/details/traits.hpp>
43 #include <cereal/details/helpers.hpp>
44 #include <cereal/types/base_class.hpp>
45
46 namespace cereal
47 {
48   // ######################################################################
49   //! Creates a name value pair
50   /*! @relates NameValuePair
51       @ingroup Utility */
52   template <class T> inline
53   NameValuePair<T> make_nvp( std::string const & name, T && value )
54   {
55     return {name.c_str(), std::forward<T>(value)};
56   }
57
58   //! Creates a name value pair
59   /*! @relates NameValuePair
60       @ingroup Utility */
61   template <class T> inline
62   NameValuePair<T> make_nvp( const char * name, T && value )
63   {
64     return {name, std::forward<T>(value)};
65   }
66
67   //! Creates a name value pair for the variable T with the same name as the variable
68   /*! @relates NameValuePair
69       @ingroup Utility */
70   #define CEREAL_NVP(T) ::cereal::make_nvp(#T, T)
71
72   // ######################################################################
73   //! Convenience function to create binary data for both const and non const pointers
74   /*! @param data Pointer to beginning of the data
75       @param size The size in bytes of the data
76       @relates BinaryData
77       @ingroup Utility */
78   template <class T> inline
79   BinaryData<T> binary_data( T && data, size_t size )
80   {
81     return {std::forward<T>(data), size};
82   }
83
84   // ######################################################################
85   //! Creates a size tag from some variable.
86   /*! Will normally be used to serialize size (e.g. size()) information for
87       variable size containers.  If you have a variable sized container,
88       the very first thing it serializes should be its size, wrapped in
89       a SizeTag.
90
91       @relates SizeTag
92       @ingroup Utility */
93   template <class T>
94   SizeTag<T> make_size_tag( T && sz )
95   {
96     return {std::forward<T>(sz)};
97   }
98
99   // ######################################################################
100   //! Called before a type is serialized to set up any special archive state
101   //! for processing some type
102   /*! If designing a serializer that needs to set up any kind of special
103       state or output extra information for a type, specialize this function
104       for the archive type and the types that require the extra information.
105       @ingroup Internal */
106   template <class Archive, class T>
107   void prologue( Archive & /* archive */, T const & /* data */)
108   { }
109
110   //! Called after a type is serialized to tear down any special archive state
111   //! for processing some type
112   /*! @ingroup Internal */
113   template <class Archive, class T>
114   void epilogue( Archive & /* archive */, T const & /* data */)
115   { }
116
117   // ######################################################################
118   //! Special flags for archives
119   /*! AllowEmptyClassElision
120         This allows for empty classes to be serialized even if they do not provide
121         a serialization function.  Classes with no data members are considered to be
122         empty.  Be warned that if this is enabled and you attempt to serialize an
123         empty class with improperly formed serialize or load/save functions, no
124         static error will occur - the error will propogate silently and your
125         intended serialization functions may not be called.  You can manually
126         ensure that your classes that have custom serialization are correct
127         by using the traits is_output_serializable and is_input_serializable
128         in cereal/details/traits.hpp.
129       @ingroup Internal */
130   enum Flags { AllowEmptyClassElision = 1 };
131
132   // ######################################################################
133   //! Registers a specific Archive type with cereal
134   /*! This registration should be done once per archive.  A good place to
135       put this is immediately following the definition of your archive.
136       Archive registration is only strictly necessary if you wish to
137       support pointers to polymorphic data types.  All archives that
138       come with cereal are already registered.
139       @ingroup Internal */
140   #define CEREAL_REGISTER_ARCHIVE(Archive)                            \
141   namespace cereal { namespace detail {                               \
142   template <class T>                                                  \
143   typename polymorphic_serialization_support<Archive, T>::type        \
144   instantiate_polymorphic_binding( T*, Archive*, adl_tag );           \
145   } } // end namespaces
146
147   //! Defines a class version for some type
148   /*! Versioning information is optional and adds some small amount of
149       overhead to serialization.  This overhead will occur both in terms of
150       space in the archive (the version information for each class will be
151       stored exactly once) as well as runtime (versioned serialization functions
152       must check to see if they need to load or store version information).
153
154       Versioning is useful if you plan on fundamentally changing the way some
155       type is serialized in the future.  Versioned serialization functions
156       cannot be used to load non-versioned data.
157
158       By default, all types have an assumed version value of zero.  By
159       using this macro, you may change the version number associated with
160       some type.  cereal will then use this value as a second parameter
161       to your serialization functions.
162
163       The interface for the serialization functions is nearly identical
164       to non-versioned serialization with the addition of a second parameter,
165       const std::uint32_t version, which will be supplied with the correct
166       version number.  Serializing the version number on a save happens
167       automatically.
168
169       Versioning cannot be mixed with non-versioned serialization functions.
170       Having both types will result result in a compile time error.
171
172       Example interface for versioning on a non-member serialize function:
173
174       @code{cpp}
175       CEREAL_CLASS_VERSION( Mytype, 77 ); // register class version
176
177       template <class Archive>
178       void serialize( Archive & ar, Mytype & t, const std::uint32_t version )
179       {
180         // When performing a load, the version associated with the class
181         // is whatever it was when that data was originally serialized
182         //
183         // When we save, we'll use the version that is defined in the macro
184
185         if( version >= some_number )
186           // do this
187         else
188           // do that
189       }
190       @endcode
191
192       Interfaces for other forms of serialization functions is similar.  This
193       macro should be placed at global scope.
194       @ingroup Utility */
195   #define CEREAL_CLASS_VERSION(TYPE, VERSION_NUMBER)                             \
196   namespace cereal { namespace detail {                                          \
197     template <> struct Version<TYPE>                                             \
198     {                                                                            \
199       static const std::uint32_t version = VERSION_NUMBER;                       \
200       static Version<TYPE> registerVersion()                                     \
201       {                                                                          \
202         ::cereal::detail::StaticObject<Versions>::getInstance().mapping.emplace( \
203              std::type_index(typeid(TYPE)).hash_code(), VERSION_NUMBER );        \
204         return {};                                                               \
205       }                                                                          \
206     }; /* end Version */                                                         \
207     static const auto CEREAL_CLASS_VERSION_REGISTER##TYPE##VERSION_NUMBER =      \
208       Version<TYPE>::registerVersion();                                          \
209   } } // end namespaces
210
211   //! The base output archive class
212   /*! This is the base output archive for all output archives.  If you create
213       a custom archive class, it should derive from this, passing itself as
214       a template parameter for the ArchiveType.
215
216       The base class provides all of the functionality necessary to
217       properly forward data to the correct serialization functions.
218
219       Individual archives should use a combination of prologue and
220       epilogue functions together with specializations of serialize, save,
221       and load to alter the functionality of their serialization.
222
223       @tparam ArchiveType The archive type that derives from OutputArchive
224       @tparam Flags Flags to control advanced functionality.  See the Flags
225                     enum for more information.
226       @ingroup Internal */
227   template<class ArchiveType, std::uint32_t Flags = 0>
228   class OutputArchive : public detail::OutputArchiveBase
229   {
230     public:
231       //! Construct the output archive
232       /*! @param derived A pointer to the derived ArchiveType (pass this from the derived archive) */
233       OutputArchive(ArchiveType * const derived) : self(derived), itsCurrentPointerId(1), itsCurrentPolymorphicTypeId(1)
234       { }
235
236       //! Serializes all passed in data
237       /*! This is the primary interface for serializing data with an archive */
238       template <class ... Types> inline
239       ArchiveType & operator()( Types && ... args )
240       {
241         self->process( std::forward<Types>( args )... );
242         return *self;
243       }
244
245       /*! @name Boost Transition Layer
246           Functionality that mirrors the syntax for Boost.  This is useful if you are transitioning
247           a large project from Boost to cereal.  The preferred interface for cereal is using operator(). */
248       //! @{
249
250       //! Serializes passed in data
251       /*! This is a boost compatability layer and is not the preferred way of using
252           cereal.  If you are transitioning from boost, use this until you can
253           transition to the operator() overload */
254       template <class T> inline
255       ArchiveType & operator&( T && arg )
256       {
257         self->process( std::forward<T>( arg ) );
258         return *self;
259       }
260
261       //! Serializes passed in data
262       /*! This is a boost compatability layer and is not the preferred way of using
263           cereal.  If you are transitioning from boost, use this until you can
264           transition to the operator() overload */
265       template <class T> inline
266       ArchiveType & operator<<( T && arg )
267       {
268         self->process( std::forward<T>( arg ) );
269         return *self;
270       }
271
272       //! @}
273
274       //! Registers a shared pointer with the archive
275       /*! This function is used to track shared pointer targets to prevent
276           unnecessary saves from taking place if multiple shared pointers
277           point to the same data.
278
279           @internal
280           @param addr The address (see shared_ptr get()) pointed to by the shared pointer
281           @return A key that uniquely identifies the pointer */
282       inline std::uint32_t registerSharedPointer( void const * addr )
283       {
284         // Handle null pointers by just returning 0
285         if(addr == 0) return 0;
286
287         auto id = itsSharedPointerMap.find( addr );
288         if( id == itsSharedPointerMap.end() )
289         {
290           auto ptrId = itsCurrentPointerId++;
291           itsSharedPointerMap.insert( {addr, ptrId} );
292           return ptrId | detail::msb_32bit; // mask MSB to be 1
293         }
294         else
295           return id->second;
296       }
297
298       //! Registers a polymorphic type name with the archive
299       /*! This function is used to track polymorphic types to prevent
300           unnecessary saves of identifying strings used by the polymorphic
301           support functionality.
302
303           @internal
304           @param name The name to associate with a polymorphic type
305           @return A key that uniquely identifies the polymorphic type name */
306       inline std::uint32_t registerPolymorphicType( char const * name )
307       {
308         auto id = itsPolymorphicTypeMap.find( name );
309         if( id == itsPolymorphicTypeMap.end() )
310         {
311           auto polyId = itsCurrentPolymorphicTypeId++;
312           itsPolymorphicTypeMap.insert( {name, polyId} );
313           return polyId | detail::msb_32bit; // mask MSB to be 1
314         }
315         else
316           return id->second;
317       }
318
319     private:
320       //! Serializes data after calling prologue, then calls epilogue
321       template <class T> inline
322       void process( T && head )
323       {
324         prologue( *self, head );
325         self->processImpl( head );
326         epilogue( *self, head );
327       }
328
329       //! Unwinds to process all data
330       template <class T, class ... Other> inline
331       void process( T && head, Other && ... tail )
332       {
333         self->process( std::forward<T>( head ) );
334         self->process( std::forward<Other>( tail )... );
335       }
336
337       //! Serialization of a virtual_base_class wrapper
338       /*! \sa virtual_base_class */
339       template <class T> inline
340       ArchiveType & processImpl(virtual_base_class<T> const & b)
341       {
342         traits::detail::base_class_id id(b.base_ptr);
343         if(itsBaseClassSet.count(id) == 0)
344         {
345           itsBaseClassSet.insert(id);
346           self->processImpl( *b.base_ptr );
347         }
348         return *self;
349       }
350
351       //! Serialization of a base_class wrapper
352       /*! \sa base_class */
353       template <class T> inline
354       ArchiveType & processImpl(base_class<T> const & b)
355       {
356         self->processImpl( *b.base_ptr );
357         return *self;
358       }
359
360       //! Member serialization
361       template <class T> inline
362       typename std::enable_if<traits::has_member_serialize<T, ArchiveType>::value && !traits::has_invalid_output_versioning<T, ArchiveType>::value &&
363                               (traits::is_specialized_member_serialize<T, ArchiveType>::value || traits::is_output_serializable<T, ArchiveType>::value),
364                               ArchiveType &>::type
365       processImpl(T const & t)
366       {
367         access::member_serialize(*self, const_cast<T &>(t));
368         return *self;
369       }
370
371       //! Non member serialization
372       template <class T> inline
373       typename std::enable_if<traits::has_non_member_serialize<T, ArchiveType>::value && !traits::has_invalid_output_versioning<T, ArchiveType>::value &&
374                               (traits::is_specialized_non_member_serialize<T, ArchiveType>::value || traits::is_output_serializable<T, ArchiveType>::value),
375                               ArchiveType &>::type
376       processImpl(T const & t)
377       {
378         serialize(*self, const_cast<T &>(t));
379         return *self;
380       }
381
382       //! Member split (save)
383       template <class T> inline
384       typename std::enable_if<traits::has_member_save<T, ArchiveType>::value && !traits::has_invalid_output_versioning<T, ArchiveType>::value &&
385                               (traits::is_specialized_member_save<T, ArchiveType>::value || traits::is_output_serializable<T, ArchiveType>::value),
386                               ArchiveType &>::type
387       processImpl(T const & t)
388       {
389         access::member_save(*self, t);
390         return *self;
391       }
392
393       //! Non member split (save)
394       template <class T> inline
395       typename std::enable_if<traits::has_non_member_save<T, ArchiveType>::value && !traits::has_invalid_output_versioning<T, ArchiveType>::value &&
396                               (traits::is_specialized_non_member_save<T, ArchiveType>::value || traits::is_output_serializable<T, ArchiveType>::value),
397                               ArchiveType &>::type
398       processImpl(T const & t)
399       {
400         save(*self, t);
401         return *self;
402       }
403
404       //! Member split (save_minimal)
405       template <class T> inline
406       typename std::enable_if<traits::has_member_save_minimal<T, ArchiveType>::value && !traits::has_invalid_output_versioning<T, ArchiveType>::value &&
407                               (traits::is_specialized_member_save_minimal<T, ArchiveType>::value || traits::is_output_serializable<T, ArchiveType>::value),
408                               ArchiveType &>::type
409       processImpl(T const & t)
410       {
411         self->process( access::member_save_minimal(*self, t) );
412         return *self;
413       }
414
415       //! Non member split (save_minimal)
416       template <class T> inline
417       typename std::enable_if<traits::has_non_member_save_minimal<T, ArchiveType>::value && !traits::has_invalid_output_versioning<T, ArchiveType>::value &&
418                               (traits::is_specialized_non_member_save_minimal<T, ArchiveType>::value || traits::is_output_serializable<T, ArchiveType>::value),
419                               ArchiveType &>::type
420       processImpl(T const & t)
421       {
422         self->process( save_minimal(*self, t) );
423         return *self;
424       }
425
426       //! Empty class specialization
427       template <class T> inline
428       typename std::enable_if<(Flags & AllowEmptyClassElision) &&
429           !traits::is_specialized<T, ArchiveType>::value &&
430           !traits::is_output_serializable<T, ArchiveType>::value && std::is_empty<T>::value, ArchiveType &>::type
431       processImpl(T const &)
432       {
433         return *self;
434       }
435
436       //! No matching serialization
437       template <class T> inline
438       typename std::enable_if<traits::has_invalid_output_versioning<T, ArchiveType>::value ||
439         (!traits::is_specialized<T, ArchiveType>::value && !traits::is_output_serializable<T, ArchiveType>::value &&
440         (!(Flags & AllowEmptyClassElision) || ((Flags & AllowEmptyClassElision) && !std::is_empty<T>::value))),
441         ArchiveType &>::type
442       processImpl(T const &)
443       {
444         static_assert(traits::is_output_serializable<T, ArchiveType>::value, "Trying to serialize an unserializable type with an output archive. \n\n "
445             "Types must either have a serialize function, load/save pair, or load_minimal/save_minimal pair (you may not mix these). \n "
446             "Use specialization (see access.hpp) if you need to disambiguate between serialize vs load/save functions.  \n "
447             "In addition, you may not mix versioned with non-versioned serialization functions. \n "
448             "Serialize functions generally have the following signature: \n\n "
449             "template<class Archive> \n "
450             "  void serialize(Archive & ar) \n "
451             "  { \n "
452             "    ar( member1, member2, member3 ); \n "
453             "  } \n\n " );
454         return *self;
455       }
456
457       //! Registers a class version with the archive and serializes it if necessary
458       /*! If this is the first time this class has been serialized, we will record its
459           version number and serialize that.
460
461           @tparam T The type of the class being serialized
462           @param version The version number associated with it */
463       template <class T> inline
464       void registerClassVersion( const std::uint32_t version )
465       {
466         static const auto hash = std::type_index(typeid(T)).hash_code();
467         const auto insertResult = itsVersionedTypes.insert( hash );
468         if( insertResult.second ) // insertion took place, serialize the version number
469           process( make_nvp<ArchiveType>("cereal_class_version", version) );
470       }
471
472       //! Member serialization
473       /*! Versioning implementation */
474       template <class T> inline
475       typename std::enable_if<traits::has_member_versioned_serialize<T, ArchiveType>::value && !traits::has_invalid_output_versioning<T, ArchiveType>::value &&
476                               (traits::is_specialized_member_serialize<T, ArchiveType>::value || traits::is_output_serializable<T, ArchiveType>::value),
477                               ArchiveType &>::type
478       processImpl(T const & t)
479       {
480         registerClassVersion<T>( detail::Version<T>::version );
481         access::member_serialize(*self, const_cast<T &>(t), detail::Version<T>::version);
482         return *self;
483       }
484
485       //! Non member serialization
486       /*! Versioning implementation */
487       template <class T> inline
488       typename std::enable_if<traits::has_non_member_versioned_serialize<T, ArchiveType>::value && !traits::has_invalid_output_versioning<T, ArchiveType>::value &&
489                               (traits::is_specialized_non_member_serialize<T, ArchiveType>::value || traits::is_output_serializable<T, ArchiveType>::value),
490                               ArchiveType &>::type
491       processImpl(T const & t)
492       {
493         registerClassVersion<T>( detail::Version<T>::version );
494         serialize(*self, const_cast<T &>(t), detail::Version<T>::version);
495         return *self;
496       }
497
498       //! Member split (save)
499       /*! Versioning implementation */
500       template <class T> inline
501       typename std::enable_if<traits::has_member_versioned_save<T, ArchiveType>::value && !traits::has_invalid_output_versioning<T, ArchiveType>::value &&
502                               (traits::is_specialized_member_save<T, ArchiveType>::value || traits::is_output_serializable<T, ArchiveType>::value),
503                               ArchiveType &>::type
504       processImpl(T const & t)
505       {
506         registerClassVersion<T>( detail::Version<T>::version );
507         access::member_save(*self, t, detail::Version<T>::version);
508         return *self;
509       }
510
511       //! Non member split (save)
512       /*! Versioning implementation */
513       template <class T> inline
514       typename std::enable_if<traits::has_non_member_versioned_save<T, ArchiveType>::value && !traits::has_invalid_output_versioning<T, ArchiveType>::value &&
515                               (traits::is_specialized_non_member_save<T, ArchiveType>::value || traits::is_output_serializable<T, ArchiveType>::value),
516                               ArchiveType &>::type
517       processImpl(T const & t)
518       {
519         registerClassVersion<T>( detail::Version<T>::version );
520         save(*self, t, detail::Version<T>::version);
521         return *self;
522       }
523
524       //! Member split (save_minimal)
525       /*! Versioning implementation */
526       template <class T> inline
527       typename std::enable_if<traits::has_member_versioned_save_minimal<T, ArchiveType>::value && !traits::has_invalid_output_versioning<T, ArchiveType>::value &&
528                               (traits::is_specialized_member_save_minimal<T, ArchiveType>::value || traits::is_output_serializable<T, ArchiveType>::value),
529                               ArchiveType &>::type
530       processImpl(T const & t)
531       {
532         registerClassVersion<T>( detail::Version<T>::version );
533         self->process( access::member_save_minimal(*self, t, detail::Version<T>::version) );
534         return *self;
535       }
536
537       //! Non member split (save_minimal)
538       /*! Versioning implementation */
539       template <class T> inline
540       typename std::enable_if<traits::has_non_member_versioned_save_minimal<T, ArchiveType>::value && !traits::has_invalid_output_versioning<T, ArchiveType>::value &&
541                               (traits::is_specialized_non_member_save_minimal<T, ArchiveType>::value || traits::is_output_serializable<T, ArchiveType>::value),
542                               ArchiveType &>::type
543       processImpl(T const & t)
544       {
545         registerClassVersion<T>( detail::Version<T>::version );
546         self->process( save_minimal(*self, t, detail::Version<T>::version) );
547         return *self;
548       }
549
550     private:
551       ArchiveType * const self;
552
553       //! A set of all base classes that have been serialized
554       std::unordered_set<traits::detail::base_class_id, traits::detail::base_class_id_hash> itsBaseClassSet;
555
556       //! Maps from addresses to pointer ids
557       std::unordered_map<void const *, std::uint32_t> itsSharedPointerMap;
558
559       //! The id to be given to the next pointer
560       std::uint32_t itsCurrentPointerId;
561
562       //! Maps from polymorphic type name strings to ids
563       std::unordered_map<char const *, std::uint32_t> itsPolymorphicTypeMap;
564
565       //! The id to be given to the next polymorphic type name
566       std::uint32_t itsCurrentPolymorphicTypeId;
567
568       //! Keeps track of classes that have versioning information associated with them
569       std::unordered_set<size_type> itsVersionedTypes;
570   }; // class OutputArchive
571
572   // ######################################################################
573   //! The base input archive class
574   /*! This is the base input archive for all input archives.  If you create
575       a custom archive class, it should derive from this, passing itself as
576       a template parameter for the ArchiveType.
577
578       The base class provides all of the functionality necessary to
579       properly forward data to the correct serialization functions.
580
581       Individual archives should use a combination of prologue and
582       epilogue functions together with specializations of serialize, save,
583       and load to alter the functionality of their serialization.
584
585       @tparam ArchiveType The archive type that derives from InputArchive
586       @tparam Flags Flags to control advanced functionality.  See the Flags
587                     enum for more information.
588       @ingroup Internal */
589   template<class ArchiveType, std::uint32_t Flags = 0>
590   class InputArchive : public detail::InputArchiveBase
591   {
592     public:
593       //! Construct the output archive
594       /*! @param derived A pointer to the derived ArchiveType (pass this from the derived archive) */
595       InputArchive(ArchiveType * const derived) :
596         self(derived),
597         itsBaseClassSet(),
598         itsSharedPointerMap(),
599         itsPolymorphicTypeMap(),
600         itsVersionedTypes()
601       { }
602
603       //! Serializes all passed in data
604       /*! This is the primary interface for serializing data with an archive */
605       template <class ... Types> inline
606       ArchiveType & operator()( Types && ... args )
607       {
608         process( std::forward<Types>( args )... );
609         return *self;
610       }
611
612       /*! @name Boost Transition Layer
613           Functionality that mirrors the syntax for Boost.  This is useful if you are transitioning
614           a large project from Boost to cereal.  The preferred interface for cereal is using operator(). */
615       //! @{
616
617       //! Serializes passed in data
618       /*! This is a boost compatability layer and is not the preferred way of using
619           cereal.  If you are transitioning from boost, use this until you can
620           transition to the operator() overload */
621       template <class T> inline
622       ArchiveType & operator&( T && arg )
623       {
624         self->process( std::forward<T>( arg ) );
625         return *self;
626       }
627
628       //! Serializes passed in data
629       /*! This is a boost compatability layer and is not the preferred way of using
630           cereal.  If you are transitioning from boost, use this until you can
631           transition to the operator() overload */
632       template <class T> inline
633       ArchiveType & operator>>( T && arg )
634       {
635         self->process( std::forward<T>( arg ) );
636         return *self;
637       }
638
639       //! @}
640
641       //! Retrieves a shared pointer given a unique key for it
642       /*! This is used to retrieve a previously registered shared_ptr
643           which has already been loaded.
644
645           @param id The unique id that was serialized for the pointer
646           @return A shared pointer to the data
647           @throw Exception if the id does not exist */
648       inline std::shared_ptr<void> getSharedPointer(std::uint32_t const id)
649       {
650         if(id == 0) return std::shared_ptr<void>(nullptr);
651
652         auto iter = itsSharedPointerMap.find( id );
653         if(iter == itsSharedPointerMap.end())
654           throw Exception("Error while trying to deserialize a smart pointer. Could not find id " + std::to_string(id));
655
656         return iter->second;
657       }
658
659       //! Registers a shared pointer to its unique identifier
660       /*! After a shared pointer has been allocated for the first time, it should
661           be registered with its loaded id for future references to it.
662
663           @param id The unique identifier for the shared pointer
664           @param ptr The actual shared pointer */
665       inline void registerSharedPointer(std::uint32_t const id, std::shared_ptr<void> ptr)
666       {
667         std::uint32_t const stripped_id = id & ~detail::msb_32bit;
668         itsSharedPointerMap[stripped_id] = ptr;
669       }
670
671       //! Retrieves the string for a polymorphic type given a unique key for it
672       /*! This is used to retrieve a string previously registered during
673           a polymorphic load.
674
675           @param id The unique id that was serialized for the polymorphic type
676           @return The string identifier for the tyep */
677       inline std::string getPolymorphicName(std::uint32_t const id)
678       {
679         auto name = itsPolymorphicTypeMap.find( id );
680         if(name == itsPolymorphicTypeMap.end())
681         {
682           throw Exception("Error while trying to deserialize a polymorphic pointer. Could not find type id " + std::to_string(id));
683         }
684         return name->second;
685       }
686
687       //! Registers a polymorphic name string to its unique identifier
688       /*! After a polymorphic type has been loaded for the first time, it should
689           be registered with its loaded id for future references to it.
690
691           @param id The unique identifier for the polymorphic type
692           @param name The name associated with the tyep */
693       inline void registerPolymorphicName(std::uint32_t const id, std::string const & name)
694       {
695         std::uint32_t const stripped_id = id & ~detail::msb_32bit;
696         itsPolymorphicTypeMap.insert( {stripped_id, name} );
697       }
698
699     private:
700       //! Serializes data after calling prologue, then calls epilogue
701       template <class T> inline
702       void process( T && head )
703       {
704         prologue( *self, head );
705         self->processImpl( head );
706         epilogue( *self, head );
707       }
708
709       //! Unwinds to process all data
710       template <class T, class ... Other> inline
711       void process( T && head, Other && ... tail )
712       {
713         process( std::forward<T>( head ) );
714         process( std::forward<Other>( tail )... );
715       }
716
717       //! Serialization of a virtual_base_class wrapper
718       /*! \sa virtual_base_class */
719       template <class T> inline
720       ArchiveType & processImpl(virtual_base_class<T> & b)
721       {
722         traits::detail::base_class_id id(b.base_ptr);
723         if(itsBaseClassSet.count(id) == 0)
724         {
725           itsBaseClassSet.insert(id);
726           self->processImpl( *b.base_ptr );
727         }
728         return *self;
729       }
730
731       //! Serialization of a base_class wrapper
732       /*! \sa base_class */
733       template <class T> inline
734       ArchiveType & processImpl(base_class<T> & b)
735       {
736         self->processImpl( *b.base_ptr );
737         return *self;
738       }
739
740       //! Member serialization
741       template <class T> inline
742       typename std::enable_if<traits::has_member_serialize<T, ArchiveType>::value &&
743                               (traits::is_specialized_member_serialize<T, ArchiveType>::value || traits::is_input_serializable<T, ArchiveType>::value),
744                               ArchiveType &>::type
745       processImpl(T & t)
746       {
747         access::member_serialize(*self, t);
748         return *self;
749       }
750
751       //! Non member serialization
752       template <class T> inline
753       typename std::enable_if<traits::has_non_member_serialize<T, ArchiveType>::value &&
754                               (traits::is_specialized_non_member_serialize<T, ArchiveType>::value || traits::is_input_serializable<T, ArchiveType>::value),
755                               ArchiveType &>::type
756       processImpl(T & t)
757       {
758         serialize(*self, t);
759         return *self;
760       }
761
762       //! Member split (load)
763       template <class T> inline
764       typename std::enable_if<traits::has_member_load<T, ArchiveType>::value &&
765                               (traits::is_specialized_member_load<T, ArchiveType>::value || traits::is_input_serializable<T, ArchiveType>::value),
766                               ArchiveType &>::type
767       processImpl(T & t)
768       {
769         access::member_load(*self, t);
770         return *self;
771       }
772
773       //! Non member split (load)
774       template <class T> inline
775       typename std::enable_if<traits::has_non_member_load<T, ArchiveType>::value &&
776                               (traits::is_specialized_non_member_load<T, ArchiveType>::value || traits::is_input_serializable<T, ArchiveType>::value),
777                               ArchiveType &>::type
778       processImpl(T & t)
779       {
780         load(*self, t);
781         return *self;
782       }
783
784       //! Member split (load_minimal)
785       template <class T> inline
786       typename std::enable_if<traits::has_member_load_minimal<T, ArchiveType>::value &&
787                               (traits::is_specialized_member_load_minimal<T, ArchiveType>::value || traits::is_input_serializable<T, ArchiveType>::value),
788                               ArchiveType &>::type
789       processImpl(T & t)
790       {
791         typename traits::has_member_save_minimal<T, ArchiveType>::type value;
792         self->process( value );
793         access::member_load_minimal(*self, t, value);
794         return *self;
795       }
796
797       //! Non member split (load_minimal)
798       template <class T> inline
799       typename std::enable_if<traits::has_non_member_load_minimal<T, ArchiveType>::value &&
800                               (traits::is_specialized_non_member_load_minimal<T, ArchiveType>::value || traits::is_input_serializable<T, ArchiveType>::value),
801                               ArchiveType &>::type
802       processImpl(T & t)
803       {
804         typename traits::has_non_member_save_minimal<T, ArchiveType>::type value;
805         self->process( value );
806         load_minimal(*self, t, value);
807         return *self;
808       }
809
810       //! Empty class specialization
811       template <class T> inline
812       typename std::enable_if<(Flags & AllowEmptyClassElision) &&
813           !traits::is_specialized<T, ArchiveType>::value &&
814           !traits::is_input_serializable<T, ArchiveType>::value && std::is_empty<T>::value, ArchiveType &>::type
815       processImpl(T const &)
816       {
817         return *self;
818       }
819
820       //! No matching serialization
821       template <class T> inline
822       typename std::enable_if<!traits::is_specialized<T, ArchiveType>::value && !traits::is_input_serializable<T, ArchiveType>::value &&
823         (!(Flags & AllowEmptyClassElision) || ((Flags & AllowEmptyClassElision) && !std::is_empty<T>::value)),
824         ArchiveType &>::type
825       processImpl(T const &)
826       {
827         static_assert(traits::is_output_serializable<T, ArchiveType>::value, "Trying to serialize an unserializable type with an output archive. \n\n "
828             "Types must either have a serialize function, load/save pair, or load_minimal/save_minimal pair (you may not mix these). \n "
829             "Use specialization (see access.hpp) if you need to disambiguate between serialize vs load/save functions.  \n "
830             "In addition, you may not mix versioned with non-versioned serialization functions. \n "
831             "Serialize functions generally have the following signature: \n\n "
832             "template<class Archive> \n "
833             "  void serialize(Archive & ar) \n "
834             "  { \n "
835             "    ar( member1, member2, member3 ); \n "
836             "  } \n\n " );
837         return *self;
838       }
839
840       //! Registers a class version with the archive and serializes it if necessary
841       /*! If this is the first time this class has been serialized, we will record its
842           version number and serialize that.
843
844           @tparam T The type of the class being serialized
845           @param version The version number associated with it */
846       template <class T> inline
847       std::uint32_t loadClassVersion()
848       {
849         static const auto hash = std::type_index(typeid(T)).hash_code();
850         auto lookupResult = itsVersionedTypes.find( hash );
851
852         if( lookupResult != itsVersionedTypes.end() ) // already exists
853           return lookupResult->second;
854         else // need to load
855         {
856           std::uint32_t version;
857
858           process( make_nvp<ArchiveType>("cereal_class_version", version) );
859           itsVersionedTypes.insert( lookupResult, std::pair<std::size_t, std::uint32_t>(hash, version) );
860
861           return version;
862         }
863       }
864
865       //! Member serialization
866       /*! Versioning implementation */
867       template <class T> inline
868       typename std::enable_if<traits::has_member_versioned_serialize<T, ArchiveType>::value &&
869                               (traits::is_specialized_member_serialize<T, ArchiveType>::value || traits::is_input_serializable<T, ArchiveType>::value),
870                               ArchiveType &>::type
871       processImpl(T & t)
872       {
873         const auto version = loadClassVersion<T>();
874         access::member_serialize(*self, t, version);
875         return *self;
876       }
877
878       //! Non member serialization
879       /*! Versioning implementation */
880       template <class T> inline
881       typename std::enable_if<traits::has_non_member_versioned_serialize<T, ArchiveType>::value &&
882                               (traits::is_specialized_non_member_serialize<T, ArchiveType>::value || traits::is_input_serializable<T, ArchiveType>::value),
883                               ArchiveType &>::type
884       processImpl(T & t)
885       {
886         const auto version = loadClassVersion<T>();
887         serialize(*self, t, version);
888         return *self;
889       }
890
891       //! Member split (load)
892       /*! Versioning implementation */
893       template <class T> inline
894       typename std::enable_if<traits::has_member_versioned_load<T, ArchiveType>::value &&
895                               (traits::is_specialized_member_load<T, ArchiveType>::value || traits::is_input_serializable<T, ArchiveType>::value),
896                               ArchiveType &>::type
897       processImpl(T & t)
898       {
899         const auto version = loadClassVersion<T>();
900         access::member_load(*self, t, version);
901         return *self;
902       }
903
904       //! Non member split (load)
905       /*! Versioning implementation */
906       template <class T> inline
907       typename std::enable_if<traits::has_non_member_versioned_load<T, ArchiveType>::value &&
908                               (traits::is_specialized_non_member_load<T, ArchiveType>::value || traits::is_input_serializable<T, ArchiveType>::value),
909                               ArchiveType &>::type
910       processImpl(T & t)
911       {
912         const auto version = loadClassVersion<T>();
913         load(*self, t, version);
914         return *self;
915       }
916
917       //! Member split (load_minimal)
918       /*! Versioning implementation */
919       template <class T> inline
920       typename std::enable_if<traits::has_member_versioned_load_minimal<T, ArchiveType>::value &&
921                               (traits::is_specialized_member_load_minimal<T, ArchiveType>::value || traits::is_input_serializable<T, ArchiveType>::value),
922                               ArchiveType &>::type
923       processImpl(T & t)
924       {
925         const auto version = loadClassVersion<T>();
926         typename traits::has_member_versioned_save_minimal<T, ArchiveType>::type value;
927         self->process(value);
928         access::member_load_minimal(*self, t, value, version);
929         return *self;
930       }
931
932       //! Non member split (load_minimal)
933       /*! Versioning implementation */
934       template <class T> inline
935       typename std::enable_if<traits::has_non_member_versioned_load_minimal<T, ArchiveType>::value &&
936                               (traits::is_specialized_non_member_load_minimal<T, ArchiveType>::value || traits::is_input_serializable<T, ArchiveType>::value),
937                               ArchiveType &>::type
938       processImpl(T & t)
939       {
940         const auto version = loadClassVersion<T>();
941         typename traits::has_non_member_versioned_save_minimal<T, ArchiveType>::type value;
942         self->process(value);
943         load_minimal(*self, t, value, version);
944         return *self;
945       }
946
947     private:
948       ArchiveType * const self;
949
950       //! A set of all base classes that have been serialized
951       std::unordered_set<traits::detail::base_class_id, traits::detail::base_class_id_hash> itsBaseClassSet;
952
953       //! Maps from pointer ids to metadata
954       std::unordered_map<std::uint32_t, std::shared_ptr<void>> itsSharedPointerMap;
955
956       //! Maps from name ids to names
957       std::unordered_map<std::uint32_t, std::string> itsPolymorphicTypeMap;
958
959       //! Maps from type hash codes to version numbers
960       std::unordered_map<std::size_t, std::uint32_t> itsVersionedTypes;
961   }; // class InputArchive
962 } // namespace cereal
963
964 // This include needs to come after things such as binary_data, make_nvp, etc
965 #include <cereal/types/common.hpp>
966
967 #endif // CEREAL_CEREAL_HPP_