cereal
A C++11 library for serialization
 All Classes Files Functions Variables Typedefs Enumerations Groups
memory.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 #ifndef CEREAL_TYPES_SHARED_PTR_HPP_
28 #define CEREAL_TYPES_SHARED_PTR_HPP_
29 
30 #include <cereal/cereal.hpp>
31 #include <memory>
32 
33 namespace cereal
34 {
35  namespace memory_detail
36  {
38 
40  template<class T>
41  struct PtrWrapper
42  {
43  PtrWrapper(T && p) : ptr(std::forward<T>(p)) {}
44  T & ptr;
45  };
46 
48 
49  template<class T> inline
50  PtrWrapper<T> make_ptr_wrapper(T && t)
51  {
52  return {std::forward<T>(t)};
53  }
54  }
55 
57  template <class Archive, class T> inline
58  typename std::enable_if<!std::is_polymorphic<T>::value, void>::type
59  save( Archive & ar, std::shared_ptr<T> const & ptr )
60  {
61  ar( _CEREAL_NVP("ptr_wrapper", memory_detail::make_ptr_wrapper( ptr )) );
62  }
63 
65  template <class Archive, class T> inline
66  typename std::enable_if<!std::is_polymorphic<T>::value, void>::type
67  load( Archive & ar, std::shared_ptr<T> & ptr )
68  {
69  ar( memory_detail::make_ptr_wrapper( ptr ) );
70  }
71 
73  template <class Archive, class T> inline
74  typename std::enable_if<!std::is_polymorphic<T>::value, void>::type
75  save( Archive & ar, std::weak_ptr<T> const & ptr )
76  {
77  auto sptr = ptr.lock();
78  ar( _CEREAL_NVP("ptr_wrapper", memory_detail::make_ptr_wrapper( sptr )) );
79  }
80 
82  template <class Archive, class T> inline
83  typename std::enable_if<!std::is_polymorphic<T>::value, void>::type
84  load( Archive & ar, std::weak_ptr<T> & ptr )
85  {
86  std::shared_ptr<T> sptr;
87  ar( memory_detail::make_ptr_wrapper( sptr ) );
88  ptr = sptr;
89  }
90 
92  template <class Archive, class T, class D> inline
93  typename std::enable_if<!std::is_polymorphic<T>::value, void>::type
94  save( Archive & ar, std::unique_ptr<T, D> const & ptr )
95  {
96  ar( _CEREAL_NVP("ptr_wrapper", memory_detail::make_ptr_wrapper( ptr )) );
97  }
98 
100  template <class Archive, class T, class D> inline
101  typename std::enable_if<!std::is_polymorphic<T>::value, void>::type
102  load( Archive & ar, std::unique_ptr<T, D> & ptr )
103  {
104  ar( memory_detail::make_ptr_wrapper( ptr ) );
105  }
106 
107  // ######################################################################
108  // Pointer wrapper implementations follow below
109 
111  template <class Archive, class T> inline
112  void save( Archive & ar, memory_detail::PtrWrapper<std::shared_ptr<T> const &> const & wrapper )
113  {
114  auto & ptr = wrapper.ptr;
115 
116  uint32_t id = ar.registerSharedPointer( ptr.get() );
117  ar( _CEREAL_NVP("id", id) );
118 
119  if( id & detail::msb_32bit )
120  {
121  ar( _CEREAL_NVP("data", *ptr) );
122  }
123  }
124 
126  template <class Archive, class T> inline
127  typename std::enable_if<traits::has_load_and_allocate<T, Archive>(), void>::type
128  load( Archive & ar, memory_detail::PtrWrapper<std::shared_ptr<T> &> & wrapper )
129  {
130  auto & ptr = wrapper.ptr;
131 
132  uint32_t id;
133 
134  ar( id );
135 
136  if( id & detail::msb_32bit )
137  {
138  ptr.reset( detail::Load<T, Archive>::load_andor_allocate( ar ) );
139  ar.registerSharedPointer(id, ptr);
140  }
141  else
142  {
143  ptr = std::static_pointer_cast<T>(ar.getSharedPointer(id));
144  }
145  }
146 
148  template <class Archive, class T> inline
149  typename std::enable_if<!traits::has_load_and_allocate<T, Archive>(), void>::type
150  load( Archive & ar, memory_detail::PtrWrapper<std::shared_ptr<T> &> & wrapper )
151  {
152  auto & ptr = wrapper.ptr;
153 
154  uint32_t id;
155 
156  ar( id );
157 
158  if( id & detail::msb_32bit )
159  {
160  ptr.reset( detail::Load<T, Archive>::load_andor_allocate( ar ) );
161  ar( *ptr );
162  ar.registerSharedPointer(id, ptr);
163  }
164  else
165  {
166  ptr = std::static_pointer_cast<T>(ar.getSharedPointer(id));
167  }
168  }
169 
171  template <class Archive, class T, class D> inline
172  void save( Archive & ar, memory_detail::PtrWrapper<std::unique_ptr<T, D> const &> const & wrapper )
173  {
174  auto & ptr = wrapper.ptr;
175 
176  // unique_ptr get one byte of metadata which signifies whether they were a nullptr
177  // 0 == nullptr
178  // 1 == not null
179 
180  if( !ptr )
181  ar( _CEREAL_NVP("valid", uint8_t(0)) );
182  else
183  {
184  ar( _CEREAL_NVP("valid", uint8_t(1)) );
185  ar( _CEREAL_NVP("data", *ptr) );
186  }
187  }
188 
190  template <class Archive, class T, class D> inline
191  typename std::enable_if<traits::has_load_and_allocate<T, Archive>(), void>::type
192  load( Archive & ar, memory_detail::PtrWrapper<std::unique_ptr<T, D> &> & wrapper )
193  {
194  uint8_t isValid;
195  ar( isValid );
196 
197  auto & ptr = wrapper.ptr;
198 
199  if( isValid )
200  ptr.reset( detail::Load<T, Archive>::load_andor_allocate( ar ) );
201  else
202  ptr.reset( nullptr );
203  }
204 
206  template <class Archive, class T, class D> inline
207  typename std::enable_if<!traits::has_load_and_allocate<T, Archive>(), void>::type
208  load( Archive & ar, memory_detail::PtrWrapper<std::unique_ptr<T, D> &> & wrapper )
209  {
210  uint8_t isValid;
211  ar( isValid );
212 
213  auto & ptr = wrapper.ptr;
214 
215  if( isValid )
216  {
217  ptr.reset( detail::Load<T, Archive>::load_andor_allocate( ar ) );
218  ar( *ptr );
219  }
220  else
221  {
222  ptr.reset( nullptr );
223  }
224  }
225 } // namespace cereal
226 
227 #endif // CEREAL_TYPES_SHARED_PTR_HPP_