NDDEM
memory.hpp
Go to the documentation of this file.
1 
4 /*
5  Copyright (c) 2014, Randolph Voorhies, Shane Grant
6  All rights reserved.
7 
8  Redistribution and use in source and binary forms, with or without
9  modification, are permitted provided that the following conditions are met:
10  * Redistributions of source code must retain the above copyright
11  notice, this list of conditions and the following disclaimer.
12  * Redistributions in binary form must reproduce the above copyright
13  notice, this list of conditions and the following disclaimer in the
14  documentation and/or other materials provided with the distribution.
15  * Neither the name of the copyright holder nor the
16  names of its contributors may be used to endorse or promote products
17  derived from this software without specific prior written permission.
18 
19  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
23  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30 #ifndef CEREAL_TYPES_SHARED_PTR_HPP_
31 #define CEREAL_TYPES_SHARED_PTR_HPP_
32 
33 #include "cereal/cereal.hpp"
34 #include <memory>
35 #include <cstring>
36 
37 namespace cereal
38 {
39  namespace memory_detail
40  {
42 
44  template<class T>
45  struct PtrWrapper
46  {
47  PtrWrapper(T && p) : ptr(std::forward<T>(p)) {}
48  T & ptr;
49 
50  PtrWrapper( PtrWrapper const & ) = default;
51  PtrWrapper & operator=( PtrWrapper const & ) = delete;
52  };
53 
55 
56  template<class T> inline
58  {
59  return {std::forward<T>(t)};
60  }
61 
63 
66  template <class Archive, class T>
68  {
70  construct( ptr )
71  { }
72 
74  template <class F>
75  LoadAndConstructLoadWrapper( T * ptr, F && sharedFromThisFunc ) :
76  construct( ptr, sharedFromThisFunc )
77  { }
78 
79  inline void CEREAL_SERIALIZE_FUNCTION_NAME( Archive & ar )
80  {
82  }
83 
85  };
86 
89 
131  template <class T>
133  {
134  // typedefs for parent type and storage type
136  using ParentType = std::enable_shared_from_this<BaseType>;
137  using StorageType = typename std::aligned_storage<sizeof(ParentType), CEREAL_ALIGNOF(ParentType)>::type;
138 
139  public:
141 
142  inline EnableSharedStateHelper( T * ptr ) :
143  itsPtr( static_cast<ParentType *>( ptr ) ),
144  itsState(),
145  itsRestored( false )
146  {
147  std::memcpy( &itsState, itsPtr, sizeof(ParentType) );
148  }
149 
151  inline void restore()
152  {
153  if( !itsRestored )
154  {
155  // void * cast needed when type has no trivial copy-assignment
156  std::memcpy( static_cast<void *>(itsPtr), &itsState, sizeof(ParentType) );
157  itsRestored = true;
158  }
159  }
160 
163  {
164  restore();
165  }
166 
167  private:
171  }; // end EnableSharedStateHelper
172 
175 
178  template <class Archive, class T> inline
179  void loadAndConstructSharedPtr( Archive & ar, T * ptr, std::true_type /* has_shared_from_this */ )
180  {
182  memory_detail::LoadAndConstructLoadWrapper<Archive, T> loadWrapper( ptr, [&](){ state.restore(); } );
183 
184  // let the user perform their initialization, shared state will be restored as soon as construct()
185  // is called
186  ar( CEREAL_NVP_("data", loadWrapper) );
187  }
188 
191 
197  template <class Archive, class T> inline
198  void loadAndConstructSharedPtr( Archive & ar, T * ptr, std::false_type /* has_shared_from_this */ )
199  {
201  ar( CEREAL_NVP_("data", loadWrapper) );
202  }
203  } // end namespace memory_detail
204 
206  template <class Archive, class T> inline
208  CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::shared_ptr<T> const & ptr )
209  {
210  ar( CEREAL_NVP_("ptr_wrapper", memory_detail::make_ptr_wrapper( ptr )) );
211  }
212 
214  template <class Archive, class T> inline
216  CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::shared_ptr<T> & ptr )
217  {
218  ar( CEREAL_NVP_("ptr_wrapper", memory_detail::make_ptr_wrapper( ptr )) );
219  }
220 
222  template <class Archive, class T> inline
224  CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::weak_ptr<T> const & ptr )
225  {
226  auto const sptr = ptr.lock();
227  ar( CEREAL_NVP_("ptr_wrapper", memory_detail::make_ptr_wrapper( sptr )) );
228  }
229 
231  template <class Archive, class T> inline
233  CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::weak_ptr<T> & ptr )
234  {
235  std::shared_ptr<T> sptr;
236  ar( CEREAL_NVP_("ptr_wrapper", memory_detail::make_ptr_wrapper( sptr )) );
237  ptr = sptr;
238  }
239 
241  template <class Archive, class T, class D> inline
243  CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::unique_ptr<T, D> const & ptr )
244  {
245  ar( CEREAL_NVP_("ptr_wrapper", memory_detail::make_ptr_wrapper( ptr )) );
246  }
247 
249  template <class Archive, class T, class D> inline
251  CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::unique_ptr<T, D> & ptr )
252  {
253  ar( CEREAL_NVP_("ptr_wrapper", memory_detail::make_ptr_wrapper( ptr )) );
254  }
255 
256  // ######################################################################
257  // Pointer wrapper implementations follow below
258 
260 
261  template <class Archive, class T> inline
262  void CEREAL_SAVE_FUNCTION_NAME( Archive & ar, memory_detail::PtrWrapper<std::shared_ptr<T> const &> const & wrapper )
263  {
264  auto & ptr = wrapper.ptr;
265 
266  uint32_t id = ar.registerSharedPointer( ptr );
267  ar( CEREAL_NVP_("id", id) );
268 
269  if( id & detail::msb_32bit )
270  {
271  ar( CEREAL_NVP_("data", *ptr) );
272  }
273  }
274 
276 
277  template <class Archive, class T> inline
279  CEREAL_LOAD_FUNCTION_NAME( Archive & ar, memory_detail::PtrWrapper<std::shared_ptr<T> &> & wrapper )
280  {
281  uint32_t id;
282 
283  ar( CEREAL_NVP_("id", id) );
284 
285  if( id & detail::msb_32bit )
286  {
287  // Storage type for the pointer - since we can't default construct this type,
288  // we'll allocate it using std::aligned_storage and use a custom deleter
289  using AlignedStorage = typename std::aligned_storage<sizeof(T), CEREAL_ALIGNOF(T)>::type;
290 
291  // Valid flag - set to true once construction finishes
292  // This prevents us from calling the destructor on
293  // uninitialized data.
294  auto valid = std::make_shared<bool>( false );
295 
296  // Allocate our storage, which we will treat as
297  // uninitialized until initialized with placement new
298  using NonConstT = typename std::remove_const<T>::type;
299  std::shared_ptr<NonConstT> ptr(reinterpret_cast<NonConstT *>(new AlignedStorage()),
300  [=]( NonConstT * t )
301  {
302  if( *valid )
303  t->~T();
304 
305  delete reinterpret_cast<AlignedStorage*>( t );
306  } );
307 
308  // Register the pointer
309  ar.registerSharedPointer( id, ptr );
310 
311  // Perform the actual loading and allocation
313 
314  // Mark pointer as valid (initialized)
315  *valid = true;
316  wrapper.ptr = std::move(ptr);
317  }
318  else
319  wrapper.ptr = std::static_pointer_cast<T>(ar.getSharedPointer(id));
320  }
321 
323 
324  template <class Archive, class T> inline
326  CEREAL_LOAD_FUNCTION_NAME( Archive & ar, memory_detail::PtrWrapper<std::shared_ptr<T> &> & wrapper )
327  {
328  uint32_t id;
329 
330  ar( CEREAL_NVP_("id", id) );
331 
332  if( id & detail::msb_32bit )
333  {
334  using NonConstT = typename std::remove_const<T>::type;
335  std::shared_ptr<NonConstT> ptr( detail::Construct<NonConstT, Archive>::load_andor_construct() );
336  ar.registerSharedPointer( id, ptr );
337  ar( CEREAL_NVP_("data", *ptr) );
338  wrapper.ptr = std::move(ptr);
339  }
340  else
341  wrapper.ptr = std::static_pointer_cast<T>(ar.getSharedPointer(id));
342  }
343 
345 
346  template <class Archive, class T, class D> inline
347  void CEREAL_SAVE_FUNCTION_NAME( Archive & ar, memory_detail::PtrWrapper<std::unique_ptr<T, D> const &> const & wrapper )
348  {
349  auto & ptr = wrapper.ptr;
350 
351  // unique_ptr get one byte of metadata which signifies whether they were a nullptr
352  // 0 == nullptr
353  // 1 == not null
354 
355  if( !ptr )
356  ar( CEREAL_NVP_("valid", uint8_t(0)) );
357  else
358  {
359  ar( CEREAL_NVP_("valid", uint8_t(1)) );
360  ar( CEREAL_NVP_("data", *ptr) );
361  }
362  }
363 
365 
366  template <class Archive, class T, class D> inline
368  CEREAL_LOAD_FUNCTION_NAME( Archive & ar, memory_detail::PtrWrapper<std::unique_ptr<T, D> &> & wrapper )
369  {
370  uint8_t isValid;
371  ar( CEREAL_NVP_("valid", isValid) );
372 
373  auto & ptr = wrapper.ptr;
374 
375  if( isValid )
376  {
377  using NonConstT = typename std::remove_const<T>::type;
378  // Storage type for the pointer - since we can't default construct this type,
379  // we'll allocate it using std::aligned_storage
380  using AlignedStorage = typename std::aligned_storage<sizeof(NonConstT), CEREAL_ALIGNOF(NonConstT)>::type;
381 
382  // Allocate storage - note the AlignedStorage type so that deleter is correct if
383  // an exception is thrown before we are initialized
384  std::unique_ptr<AlignedStorage> stPtr( new AlignedStorage() );
385 
386  // Use wrapper to enter into "data" nvp of ptr_wrapper
387  memory_detail::LoadAndConstructLoadWrapper<Archive, NonConstT> loadWrapper( reinterpret_cast<NonConstT *>( stPtr.get() ) );
388 
389  // Initialize storage
390  ar( CEREAL_NVP_("data", loadWrapper) );
391 
392  // Transfer ownership to correct unique_ptr type
393  ptr.reset( reinterpret_cast<T *>( stPtr.release() ) );
394  }
395  else
396  ptr.reset( nullptr );
397  }
398 
400 
401  template <class Archive, class T, class D> inline
403  CEREAL_LOAD_FUNCTION_NAME( Archive & ar, memory_detail::PtrWrapper<std::unique_ptr<T, D> &> & wrapper )
404  {
405  uint8_t isValid;
406  ar( CEREAL_NVP_("valid", isValid) );
407 
408  if( isValid )
409  {
410  using NonConstT = typename std::remove_const<T>::type;
411  std::unique_ptr<NonConstT, D> ptr( detail::Construct<NonConstT, Archive>::load_andor_construct() );
412  ar( CEREAL_NVP_( "data", *ptr ) );
413  wrapper.ptr = std::move(ptr);
414  }
415  else
416  {
417  wrapper.ptr.reset( nullptr );
418  }
419  }
420 } // namespace cereal
421 
422 // automatically include polymorphic support
424 
425 #endif // CEREAL_TYPES_SHARED_PTR_HPP_
Main cereal functionality.
Used to construct types with no default constructor.
Definition: access.hpp:165
std::enable_shared_from_this< BaseType > ParentType
Definition: memory.hpp:136
bool itsRestored
Definition: memory.hpp:170
StorageType itsState
Definition: memory.hpp:169
~EnableSharedStateHelper()
Restores the state of the held pointer if not done previously.
Definition: memory.hpp:162
typename ::cereal::traits::get_shared_from_this_base< T >::type BaseType
Definition: memory.hpp:135
EnableSharedStateHelper(T *ptr)
Saves the state of some type inheriting from enable_shared_from_this.
Definition: memory.hpp:142
typename std::aligned_storage< sizeof(ParentType), CEREAL_ALIGNOF(ParentType)>::type StorageType
Definition: memory.hpp:137
ParentType * itsPtr
Definition: memory.hpp:168
void restore()
Restores the state of the held pointer (can only be done once)
Definition: memory.hpp:151
#define CEREAL_NVP_(name, value)
Convenience for creating a templated NVP.
Definition: helpers.hpp:201
#define CEREAL_ALIGNOF
Checks if C++14 is available.
Definition: macros.hpp:153
type
The type the bitset is encoded with.
Definition: bitset.hpp:44
static const uint32_t msb_32bit
Definition: helpers.hpp:298
PtrWrapper< T > make_ptr_wrapper(T &&t)
Make a PtrWrapper.
Definition: memory.hpp:57
void loadAndConstructSharedPtr(Archive &ar, T *ptr, std::true_type)
Definition: memory.hpp:179
in certain simple scenarios. They should probably not be used if maximizing performance is the main o...
Definition: access.hpp:42
std::enable_if< std::is_arithmetic< T >::value, void >::type CEREAL_LOAD_FUNCTION_NAME(BinaryInputArchive &ar, T &t)
Loading for POD types from binary.
Definition: binary.hpp:126
std::enable_if< std::is_arithmetic< T >::value, void >::type CEREAL_SAVE_FUNCTION_NAME(BinaryOutputArchive &ar, T const &t)
Saving for POD types to binary.
Definition: binary.hpp:118
Definition: json.hpp:5678
const GenericPointer< typename T::ValueType > T2 value
Definition: pointer.h:1282
Support for pointers to polymorphic base classes.
unsigned int uint32_t
Definition: stdint.h:126
unsigned char uint8_t
Definition: stdint.h:124
Definition: traits.hpp:1339
static T * load_andor_construct(A &, construct< T > &)
Definition: traits.hpp:1344
A struct that acts as a wrapper around calling load_andor_construct.
Definition: memory.hpp:68
::cereal::construct< T > construct
Definition: memory.hpp:84
void CEREAL_SERIALIZE_FUNCTION_NAME(Archive &ar)
Definition: memory.hpp:79
LoadAndConstructLoadWrapper(T *ptr, F &&sharedFromThisFunc)
Constructor for embedding an early call for restoring shared_from_this.
Definition: memory.hpp:75
LoadAndConstructLoadWrapper(T *ptr)
Definition: memory.hpp:69
A wrapper class to notify cereal that it is ok to serialize the contained pointer.
Definition: memory.hpp:46
PtrWrapper(PtrWrapper const &)=default
PtrWrapper & operator=(PtrWrapper const &)=delete
PtrWrapper(T &&p)
Definition: memory.hpp:47
T & ptr
Definition: memory.hpp:48