cereal
A C++11 library for serialization
 All Classes Files Functions Variables Typedefs Enumerations Groups
polymorphic_impl.hpp
1 /*
2  Copyright (c) 2013, Randolph Voorhies, Shane Grant
3  All rights reserved.
4 
5  Redistribution and use in source and binary forms, with or without
6  modification, are permitted provided that the following conditions are met:
7  * Redistributions of source code must retain the above copyright
8  notice, this list of conditions and the following disclaimer.
9  * Redistributions in binary form must reproduce the above copyright
10  notice, this list of conditions and the following disclaimer in the
11  documentation and/or other materials provided with the distribution.
12  * Neither the name of cereal nor the
13  names of its contributors may be used to endorse or promote products
14  derived from this software without specific prior written permission.
15 
16  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19  DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
20  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27 
28 /* This code is heavily inspired by the boost serialization implementation by the following authors
29 
30  (C) Copyright 2002 Robert Ramey - http://www.rrsd.com .
31  Use, modification and distribution is subject to the Boost Software
32  License, Version 1.0. (See http://www.boost.org/LICENSE_1_0.txt)
33 
34  See http://www.boost.org for updates, documentation, and revision history.
35 
36  (C) Copyright 2006 David Abrahams - http://www.boost.org.
37 
38  See /boost/serialization/export.hpp and /boost/archive/detail/register_archive.hpp for their
39  implementation.
40 */
41 #ifndef CEREAL_DETAILS_POLYMORPHIC_IMPL_HPP_
42 #define CEREAL_DETAILS_POLYMORPHIC_IMPL_HPP_
43 
44 #include <cereal/details/static_object.hpp>
45 #include <cereal/types/memory.hpp>
46 #include <cereal/types/string.hpp>
47 #include <typeindex>
48 #include <map>
49 
51 
55 #define CEREAL_BIND_TO_ARCHIVES(T) \
56  namespace cereal { \
57  namespace detail { \
58  template<> \
59  struct init_binding<T> { \
60  static bind_to_archives<T> const & b; \
61  }; \
62  bind_to_archives<T> const & init_binding<T>::b = \
63  ::cereal::detail::StaticObject< \
64  bind_to_archives<T > \
65  >::getInstance().bind(); \
66  }} // end namespaces
67 
68 namespace cereal
69 {
70  namespace detail
71  {
73  template <class T>
74  struct binding_name {};
75 
77 
81  template <class Archive>
83  {
85 
89  typedef std::function<void(void*, void const *)> Serializer;
90 
92  struct Serializers
93  {
95  unique_ptr;
96  };
97 
99  std::map<std::type_index, Serializers> map;
100  };
101 
103 
107  template <class Archive>
109  {
111 
116  typedef std::function<void(void*, std::shared_ptr<void> & )> SharedSerializer;
118  typedef std::function<void(void*, std::unique_ptr<void> & )> UniqueSerializer;
119 
121  struct Serializers
122  {
125  };
126 
128  std::map<std::string, Serializers> map;
129  };
130 
132  template<class T> struct EmptyDeleter { void operator()(T *) const {} };
133 
134  // forward decls for archives from cereal.hpp
135  struct InputArchiveBase;
136  struct OutputArchiveBase;
137 
139 
143  template <class Archive, class T> struct InputBindingCreator
144  {
147  {
148  typename InputBindingMap<Archive>::Serializers serializers;
149 
150  serializers.shared_ptr =
151  [](void * arptr, std::shared_ptr<void> & dptr)
152  {
153  Archive & ar = *static_cast<Archive*>(arptr);
154  std::shared_ptr<T> ptr;
155 
156  ar( ::cereal::memory_detail::make_ptr_wrapper(ptr) );
157 
158  dptr = ptr;
159  };
160 
161  serializers.unique_ptr =
162  [](void * arptr, std::unique_ptr<void> & dptr)
163  {
164  Archive & ar = *static_cast<Archive*>(arptr);
165  std::unique_ptr<T> ptr;
166 
167  ar( ::cereal::memory_detail::make_ptr_wrapper(ptr) );
168 
169  dptr.reset(ptr.release());
170  };
171 
172  StaticObject<InputBindingMap<Archive>>::getInstance().map.insert( { std::string(binding_name<T>::name()), serializers } );
173  }
174  };
175 
177 
181  template <class Archive, class T> struct OutputBindingCreator
182  {
184  static void writeMetadata(Archive & ar)
185  {
186  // Register the polymorphic type name with the archive, and get the id
187  char const * name = binding_name<T>::name();
188  std::uint32_t id = ar.registerPolymorphicType(name);
189 
190  // Serialize the id
191  ar( _CEREAL_NVP("polymorphic_id", id) );
192 
193  // If the msb of the id is 1, then the type name is new, and we should serialize it
194  if( id & detail::msb_32bit )
195  {
196  std::string namestring(name);
197  ar( _CEREAL_NVP("polymorphic_name", namestring) );
198  }
199  }
200 
203  {
204  typename OutputBindingMap<Archive>::Serializers serializers;
205 
206  serializers.shared_ptr =
207  [](void * arptr, void const * dptr)
208  {
209  Archive & ar = *static_cast<Archive*>(arptr);
210 
211  writeMetadata(ar);
212 
213  std::shared_ptr<T const> const ptr(static_cast<T const *>(dptr), EmptyDeleter<T const>());
214 
215  ar( _CEREAL_NVP("ptr_wrapper", memory_detail::make_ptr_wrapper(ptr)) );
216  };
217 
218  serializers.unique_ptr =
219  [](void * arptr, void const * dptr)
220  {
221  Archive & ar = *static_cast<Archive*>(arptr);
222 
223  writeMetadata(ar);
224 
225  std::unique_ptr<T const, EmptyDeleter<T const>> const ptr(static_cast<T const *>(dptr));
226 
227  ar( _CEREAL_NVP("ptr_wrapper", memory_detail::make_ptr_wrapper(ptr)) );
228  };
229 
230  StaticObject<OutputBindingMap<Archive>>::getInstance().map.insert( {std::type_index(typeid(T)), serializers} );
231  }
232  };
233 
236  struct adl_tag {};
237 
239  template <class Archive, class T>
241  {
242  static const InputBindingCreator<Archive, T> &
243  load(std::true_type)
244  {
246  }
247 
248  static const OutputBindingCreator<Archive, T> &
249  save(std::true_type)
250  {
252  }
253 
254  inline static void load(std::false_type) {}
255  inline static void save(std::false_type) {}
256  };
257 
259  template <void(*)()>
261 
267  template <class Archive, class T>
269  {
272  static void instantiate();
275  };
276 
277  // instantiate implementation
278  template <class Archive, class T>
280  {
281  create_bindings<Archive,T>::save( std::is_base_of<detail::OutputArchiveBase, Archive>() );
282 
283  create_bindings<Archive,T>::load( std::is_base_of<detail::InputArchiveBase, Archive>() );
284  }
285 
287 
291  template <class T>
293  {
295  void bind(std::false_type) const
296  {
297  instantiate_polymorphic_binding( (T*)0, 0, adl_tag{} );
298  }
299 
301  void bind(std::true_type) const
302  { }
303 
305 
307  bind_to_archives const & bind() const
308  {
309  bind( std::is_abstract<T>() );
310  return *this;
311  }
312  };
313 
315  template <class T>
316  struct init_binding;
317 
319 
330  template <class T>
331  void instantiate_polymorphic_binding( T*, int, adl_tag ) {};
332  } // namespace detail
333 } // namespace cereal
334 
335 #endif // CEREAL_DETAILS_POLYMORPHIC_IMPL_HPP_