27 #ifndef CEREAL_TYPES_POLYMORPHIC_HPP_
28 #define CEREAL_TYPES_POLYMORPHIC_HPP_
30 #include <cereal/cereal.hpp>
31 #include <cereal/types/memory.hpp>
33 #include <cereal/details/util.hpp>
34 #include <cereal/details/helpers.hpp>
35 #include <cereal/details/traits.hpp>
36 #include <cereal/details/polymorphic_impl.hpp>
53 #define CEREAL_REGISTER_TYPE(T) \
57 struct binding_name<T> \
59 static constexpr char const * name() { return #T; }; \
62 CEREAL_BIND_TO_ARCHIVES(T);
70 #define CEREAL_REGISTER_TYPE_WITH_NAME(T, Name) \
74 struct binding_name<T> \
75 { static constexpr char const * name() { return Name; }; }; \
77 CEREAL_BIND_TO_ARCHIVES(T);
81 namespace polymorphic_detail
84 template<
class Archive>
inline
85 typename ::cereal::detail::InputBindingMap<Archive>::Serializers getInputBinding(Archive & ar, std::uint32_t
const nameid)
89 typename ::cereal::detail::InputBindingMap<Archive>::Serializers emptySerializers;
90 emptySerializers.shared_ptr = [](
void*, std::shared_ptr<void> & ptr) { ptr.reset(); };
91 emptySerializers.unique_ptr = [](
void*, std::unique_ptr<void> & ptr) { ptr.reset(); };
92 return emptySerializers;
96 if(nameid & detail::msb_32bit)
99 ar.registerPolymorphicName(nameid, name);
102 name = ar.getPolymorphicName(nameid);
104 auto & bindingMap = detail::StaticObject<detail::InputBindingMap<Archive>>::getInstance().map;
106 auto binding = bindingMap.find(name);
107 if(binding == bindingMap.end())
108 throw cereal::Exception(
"Trying to load an unregistered polymorphic type (" + name +
")");
109 return binding->second;
113 template<
class Archive,
class T>
inline
114 typename std::enable_if<std::is_default_constructible<T>::value || traits::has_load_and_allocate<T, Archive>(),
bool>::type
115 serialize_wrapper(Archive & ar, std::shared_ptr<T> & ptr, std::uint32_t
const nameid)
117 if(nameid & detail::msb2_32bit)
119 ar( memory_detail::make_ptr_wrapper(ptr) );
126 template<
class Archive,
class T,
class D>
inline
127 typename std::enable_if<std::is_default_constructible<T>::value || traits::has_load_and_allocate<T, Archive>(),
bool>::type
128 serialize_wrapper(Archive & ar, std::unique_ptr<T, D> & ptr, std::uint32_t
const nameid)
130 if(nameid & detail::msb2_32bit)
132 ar( memory_detail::make_ptr_wrapper(ptr) );
138 template<
class Archive,
class T>
inline
139 typename std::enable_if<!std::is_default_constructible<T>::value && !traits::has_load_and_allocate<T, Archive>(),
bool>::type
140 serialize_wrapper(Archive &, std::shared_ptr<T> &, std::uint32_t
const nameid)
142 if(nameid & detail::msb2_32bit)
143 throw cereal::Exception(
"Cannot load a polymorphic type that is not default constructable and does not have a load_and_allocate function");
147 template<
class Archive,
class T,
class D>
inline
148 typename std::enable_if<!std::is_default_constructible<T>::value && !traits::has_load_and_allocate<T, Archive>(),
bool>::type
149 serialize_wrapper(Archive &, std::unique_ptr<T, D> &, std::uint32_t
const nameid)
151 if(nameid & detail::msb2_32bit)
152 throw cereal::Exception(
"Cannot load a polymorphic type that is not default constructable and does not have a load_and_allocate function");
161 template <
class Archive,
class T>
inline
162 typename std::enable_if<std::is_polymorphic<T>::value,
void>::type
163 save( Archive & ar, std::shared_ptr<T>
const & ptr )
168 ar( _CEREAL_NVP(
"id", std::uint32_t(0)) );
172 std::type_info
const & ptrinfo =
typeid(*ptr.get());
173 static std::type_info
const & tinfo =
typeid(T);
179 ar( _CEREAL_NVP(
"id", detail::msb2_32bit) );
181 ar( _CEREAL_NVP(
"ptr_wrapper", memory_detail::make_ptr_wrapper(ptr)) );
186 auto & bindingMap = detail::StaticObject<detail::OutputBindingMap<Archive>>::getInstance().map;
188 auto binding = bindingMap.find(std::type_index(ptrinfo));
189 if(binding == bindingMap.end())
190 throw cereal::Exception(
"Trying to save an unregistered polymorphic type (" + cereal::util::demangle(ptrinfo.name()) +
")");
192 binding->second.shared_ptr(&ar, ptr.get());
196 template <
class Archive,
class T>
inline
197 typename std::enable_if<std::is_polymorphic<T>::value,
void>::type
198 load( Archive & ar, std::shared_ptr<T> & ptr )
200 std::uint32_t nameid;
204 if(polymorphic_detail::serialize_wrapper(ar, ptr, nameid))
207 auto binding = polymorphic_detail::getInputBinding(ar, nameid);
208 std::shared_ptr<void> result;
209 binding.shared_ptr(&ar, result);
210 ptr = std::static_pointer_cast<T>(result);
214 template <
class Archive,
class T>
inline
215 typename std::enable_if<std::is_polymorphic<T>::value,
void>::type
216 save( Archive & ar, std::weak_ptr<T>
const & ptr )
218 auto const sptr = ptr.lock();
219 ar( _CEREAL_NVP(
"locked_ptr", sptr) );
223 template <
class Archive,
class T>
inline
224 typename std::enable_if<std::is_polymorphic<T>::value,
void>::type
225 load( Archive & ar, std::weak_ptr<T> & ptr )
227 std::shared_ptr<T> sptr;
233 template <
class Archive,
class T,
class D>
inline
234 typename std::enable_if<std::is_polymorphic<T>::value,
void>::type
235 save( Archive & ar, std::unique_ptr<T, D>
const & ptr )
240 ar( _CEREAL_NVP(
"id", std::uint32_t(0)) );
244 std::type_info
const & ptrinfo =
typeid(*ptr.get());
245 static std::type_info
const & tinfo =
typeid(T);
251 ar( _CEREAL_NVP(
"id", detail::msb2_32bit) );
253 ar( _CEREAL_NVP(
"ptr_wrapper", memory_detail::make_ptr_wrapper(ptr)) );
258 auto & bindingMap = detail::StaticObject<detail::OutputBindingMap<Archive>>::getInstance().map;
260 auto binding = bindingMap.find(std::type_index(ptrinfo));
261 if(binding == bindingMap.end())
262 throw cereal::Exception(
"Trying to save an unregistered polymorphic type (" + cereal::util::demangle(ptrinfo.name()) +
")");
264 binding->second.unique_ptr(&ar, ptr.get());
268 template <
class Archive,
class T,
class D>
inline
269 typename std::enable_if<std::is_polymorphic<T>::value,
void>::type
270 load( Archive & ar, std::unique_ptr<T, D> & ptr )
272 std::uint32_t nameid;
276 if(polymorphic_detail::serialize_wrapper(ar, ptr, nameid))
279 auto binding = polymorphic_detail::getInputBinding(ar, nameid);
280 std::unique_ptr<void> result;
281 binding.unique_ptr(&ar, result);
282 ptr.reset(static_cast<T*>(result.release()));
285 #endif // CEREAL_TYPES_POLYMORPHIC_HPP_