1 #ifndef BOOST_ARCHIVE_OSERIALIZER_HPP
2 #define BOOST_ARCHIVE_OSERIALIZER_HPP
3
4 // MS compatible compilers support #pragma once
5 #if defined(_MSC_VER) && (_MSC_VER >= 1020)
6 # pragma once
7 #pragma inline_depth(511)
8 #pragma inline_recursion(on)
9 #endif
10
11 #if defined(__MWERKS__)
12 #pragma inline_depth(511)
13 #endif
14
15 /////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
16 // oserializer.hpp: interface for serialization system.
17
18 // (C) Copyright 2002 Robert Ramey - http://www.rrsd.com .
19 // Use, modification and distribution is subject to the Boost Software
20 // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
21 // http://www.boost.org/LICENSE_1_0.txt)
22
23 // See http://www.boost.org for updates, documentation, and revision history.
24
25 #include <boost/assert.hpp>
26 #include <cstddef> // NULL
27
28 #include <boost/config.hpp>
29 #include <boost/static_assert.hpp>
30 #include <boost/detail/workaround.hpp>
31
32 #include <boost/mpl/eval_if.hpp>
33 #include <boost/mpl/equal_to.hpp>
34 #include <boost/mpl/greater_equal.hpp>
35 #include <boost/mpl/identity.hpp>
36
37 #ifndef BOOST_SERIALIZATION_DEFAULT_TYPE_INFO
38 #include <boost/serialization/extended_type_info_typeid.hpp>
39 #endif
40 #include <boost/serialization/throw_exception.hpp>
41 #include <boost/serialization/smart_cast.hpp>
42 #include <boost/serialization/assume_abstract.hpp>
43 #include <boost/serialization/static_warning.hpp>
44
45 #include <boost/type_traits/is_pointer.hpp>
46 #include <boost/type_traits/is_enum.hpp>
47 #include <boost/type_traits/is_const.hpp>
48 #include <boost/type_traits/is_polymorphic.hpp>
49 #include <boost/type_traits/remove_extent.hpp>
50
51 #include <boost/serialization/serialization.hpp>
52 #include <boost/serialization/version.hpp>
53 #include <boost/serialization/level.hpp>
54 #include <boost/serialization/tracking.hpp>
55 #include <boost/serialization/type_info_implementation.hpp>
56 #include <boost/serialization/nvp.hpp>
57 #include <boost/serialization/void_cast.hpp>
58 #include <boost/serialization/array.hpp>
59 #include <boost/serialization/collection_size_type.hpp>
60 #include <boost/serialization/singleton.hpp>
61
62 #include <boost/archive/archive_exception.hpp>
63 #include <boost/archive/detail/basic_oarchive.hpp>
64 #include <boost/archive/detail/basic_oserializer.hpp>
65 #include <boost/archive/detail/basic_pointer_oserializer.hpp>
66 #include <boost/archive/detail/archive_serializer_map.hpp>
67 #include <boost/archive/detail/check.hpp>
68
69 namespace boost {
70
71 namespace serialization {
72 class extended_type_info;
73 } // namespace serialization
74
75 namespace archive {
76
77 // an accessor to permit friend access to archives. Needed because
78 // some compilers don't handle friend templates completely
79 class save_access {
80 public:
81 template<class Archive>
end_preamble(Archive & ar)82 static void end_preamble(Archive & ar){
83 ar.end_preamble();
84 }
85 template<class Archive, class T>
save_primitive(Archive & ar,const T & t)86 static void save_primitive(Archive & ar, const T & t){
87 ar.end_preamble();
88 ar.save(t);
89 }
90 };
91
92 namespace detail {
93
94 #ifdef BOOST_MSVC
95 # pragma warning(push)
96 # pragma warning(disable : 4511 4512)
97 #endif
98
99 template<class Archive, class T>
100 class oserializer : public basic_oserializer
101 {
102 private:
103 // private constructor to inhibit any existence other than the
104 // static one
105 public:
oserializer()106 explicit BOOST_DLLEXPORT oserializer() :
107 basic_oserializer(
108 boost::serialization::singleton<
109 BOOST_DEDUCED_TYPENAME
110 boost::serialization::type_info_implementation< T >::type
111 >::get_const_instance()
112 )
113 {}
114 virtual BOOST_DLLEXPORT void save_object_data(
115 basic_oarchive & ar,
116 const void *x
117 ) const BOOST_USED;
class_info() const118 virtual bool class_info() const {
119 return boost::serialization::implementation_level< T >::value
120 >= boost::serialization::object_class_info;
121 }
tracking(const unsigned int) const122 virtual bool tracking(const unsigned int /* flags */) const {
123 return boost::serialization::tracking_level< T >::value == boost::serialization::track_always
124 || (boost::serialization::tracking_level< T >::value == boost::serialization::track_selectively
125 && serialized_as_pointer());
126 }
version() const127 virtual version_type version() const {
128 return version_type(::boost::serialization::version< T >::value);
129 }
is_polymorphic() const130 virtual bool is_polymorphic() const {
131 return boost::is_polymorphic< T >::value;
132 }
~oserializer()133 virtual ~oserializer(){}
134 };
135
136 #ifdef BOOST_MSVC
137 # pragma warning(pop)
138 #endif
139
140 template<class Archive, class T>
save_object_data(basic_oarchive & ar,const void * x) const141 BOOST_DLLEXPORT void oserializer<Archive, T>::save_object_data(
142 basic_oarchive & ar,
143 const void *x
144 ) const {
145 // make sure call is routed through the highest interface that might
146 // be specialized by the user.
147 BOOST_STATIC_ASSERT(boost::is_const< T >::value == false);
148 boost::serialization::serialize_adl(
149 boost::serialization::smart_cast_reference<Archive &>(ar),
150 * static_cast<T *>(const_cast<void *>(x)),
151 version()
152 );
153 }
154
155 #ifdef BOOST_MSVC
156 # pragma warning(push)
157 # pragma warning(disable : 4511 4512)
158 #endif
159
160 template<class Archive, class T>
161 class pointer_oserializer :
162 public basic_pointer_oserializer
163 {
164 private:
165 const basic_oserializer &
get_basic_serializer() const166 get_basic_serializer() const {
167 return boost::serialization::singleton<
168 oserializer<Archive, T>
169 >::get_const_instance();
170 }
171 virtual BOOST_DLLEXPORT void save_object_ptr(
172 basic_oarchive & ar,
173 const void * x
174 ) const BOOST_USED;
175 public:
176 pointer_oserializer();
177 ~pointer_oserializer();
178 };
179
180 #ifdef BOOST_MSVC
181 # pragma warning(pop)
182 #endif
183
184 template<class Archive, class T>
save_object_ptr(basic_oarchive & ar,const void * x) const185 BOOST_DLLEXPORT void pointer_oserializer<Archive, T>::save_object_ptr(
186 basic_oarchive & ar,
187 const void * x
188 ) const {
189 BOOST_ASSERT(NULL != x);
190 // make sure call is routed through the highest interface that might
191 // be specialized by the user.
192 T * t = static_cast<T *>(const_cast<void *>(x));
193 const unsigned int file_version = boost::serialization::version< T >::value;
194 Archive & ar_impl
195 = boost::serialization::smart_cast_reference<Archive &>(ar);
196 boost::serialization::save_construct_data_adl<Archive, T>(
197 ar_impl,
198 t,
199 file_version
200 );
201 ar_impl << boost::serialization::make_nvp(NULL, * t);
202 }
203
204 template<class Archive, class T>
pointer_oserializer()205 pointer_oserializer<Archive, T>::pointer_oserializer() :
206 basic_pointer_oserializer(
207 boost::serialization::singleton<
208 BOOST_DEDUCED_TYPENAME
209 boost::serialization::type_info_implementation< T >::type
210 >::get_const_instance()
211 )
212 {
213 // make sure appropriate member function is instantiated
214 boost::serialization::singleton<
215 oserializer<Archive, T>
216 >::get_mutable_instance().set_bpos(this);
217 archive_serializer_map<Archive>::insert(this);
218 }
219
220 template<class Archive, class T>
~pointer_oserializer()221 pointer_oserializer<Archive, T>::~pointer_oserializer(){
222 archive_serializer_map<Archive>::erase(this);
223 }
224
225 template<class Archive>
226 struct save_non_pointer_type {
227 // note this bounces the call right back to the archive
228 // with no runtime overhead
229 struct save_primitive {
230 template<class T>
invokeboost::archive::detail::save_non_pointer_type::save_primitive231 static void invoke(Archive & ar, const T & t){
232 save_access::save_primitive(ar, t);
233 }
234 };
235 // same as above but passes through serialization
236 struct save_only {
237 template<class T>
invokeboost::archive::detail::save_non_pointer_type::save_only238 static void invoke(Archive & ar, const T & t){
239 // make sure call is routed through the highest interface that might
240 // be specialized by the user.
241 boost::serialization::serialize_adl(
242 ar,
243 const_cast<T &>(t),
244 ::boost::serialization::version< T >::value
245 );
246 }
247 };
248 // adds class information to the archive. This includes
249 // serialization level and class version
250 struct save_standard {
251 template<class T>
invokeboost::archive::detail::save_non_pointer_type::save_standard252 static void invoke(Archive &ar, const T & t){
253 ar.save_object(
254 & t,
255 boost::serialization::singleton<
256 oserializer<Archive, T>
257 >::get_const_instance()
258 );
259 }
260 };
261
262 // adds class information to the archive. This includes
263 // serialization level and class version
264 struct save_conditional {
265 template<class T>
invokeboost::archive::detail::save_non_pointer_type::save_conditional266 static void invoke(Archive &ar, const T &t){
267 //if(0 == (ar.get_flags() & no_tracking))
268 save_standard::invoke(ar, t);
269 //else
270 // save_only::invoke(ar, t);
271 }
272 };
273
274
275 template<class T>
invokeboost::archive::detail::save_non_pointer_type276 static void invoke(Archive & ar, const T & t){
277 typedef
278 BOOST_DEDUCED_TYPENAME mpl::eval_if<
279 // if its primitive
280 mpl::equal_to<
281 boost::serialization::implementation_level< T >,
282 mpl::int_<boost::serialization::primitive_type>
283 >,
284 mpl::identity<save_primitive>,
285 // else
286 BOOST_DEDUCED_TYPENAME mpl::eval_if<
287 // class info / version
288 mpl::greater_equal<
289 boost::serialization::implementation_level< T >,
290 mpl::int_<boost::serialization::object_class_info>
291 >,
292 // do standard save
293 mpl::identity<save_standard>,
294 // else
295 BOOST_DEDUCED_TYPENAME mpl::eval_if<
296 // no tracking
297 mpl::equal_to<
298 boost::serialization::tracking_level< T >,
299 mpl::int_<boost::serialization::track_never>
300 >,
301 // do a fast save
302 mpl::identity<save_only>,
303 // else
304 // do a fast save only tracking is turned off
305 mpl::identity<save_conditional>
306 > > >::type typex;
307 check_object_versioning< T >();
308 typex::invoke(ar, t);
309 }
310 template<class T>
invokeboost::archive::detail::save_non_pointer_type311 static void invoke(Archive & ar, T & t){
312 check_object_level< T >();
313 check_object_tracking< T >();
314 invoke(ar, const_cast<const T &>(t));
315 }
316 };
317
318 template<class Archive>
319 struct save_pointer_type {
320 struct abstract
321 {
322 template<class T>
register_typeboost::archive::detail::save_pointer_type::abstract323 static const basic_pointer_oserializer * register_type(Archive & /* ar */){
324 // it has? to be polymorphic
325 BOOST_STATIC_ASSERT(boost::is_polymorphic< T >::value);
326 return NULL;
327 }
328 };
329
330 struct non_abstract
331 {
332 template<class T>
register_typeboost::archive::detail::save_pointer_type::non_abstract333 static const basic_pointer_oserializer * register_type(Archive & ar){
334 return ar.register_type(static_cast<T *>(NULL));
335 }
336 };
337
338 template<class T>
register_typeboost::archive::detail::save_pointer_type339 static const basic_pointer_oserializer * register_type(Archive &ar, T & /*t*/){
340 // there should never be any need to save an abstract polymorphic
341 // class pointer. Inhibiting code generation for this
342 // permits abstract base classes to be used - note: exception
343 // virtual serialize functions used for plug-ins
344 typedef
345 BOOST_DEDUCED_TYPENAME mpl::eval_if<
346 boost::serialization::is_abstract< T >,
347 mpl::identity<abstract>,
348 mpl::identity<non_abstract>
349 >::type typex;
350 return typex::template register_type< T >(ar);
351 }
352
353 struct non_polymorphic
354 {
355 template<class T>
saveboost::archive::detail::save_pointer_type::non_polymorphic356 static void save(
357 Archive &ar,
358 T & t
359 ){
360 const basic_pointer_oserializer & bpos =
361 boost::serialization::singleton<
362 pointer_oserializer<Archive, T>
363 >::get_const_instance();
364 // save the requested pointer type
365 ar.save_pointer(& t, & bpos);
366 }
367 };
368
369 struct polymorphic
370 {
371 template<class T>
saveboost::archive::detail::save_pointer_type::polymorphic372 static void save(
373 Archive &ar,
374 T & t
375 ){
376 BOOST_DEDUCED_TYPENAME
377 boost::serialization::type_info_implementation< T >::type const
378 & i = boost::serialization::singleton<
379 BOOST_DEDUCED_TYPENAME
380 boost::serialization::type_info_implementation< T >::type
381 >::get_const_instance();
382
383 boost::serialization::extended_type_info const * const this_type = & i;
384
385 // retrieve the true type of the object pointed to
386 // if this assertion fails its an error in this library
387 BOOST_ASSERT(NULL != this_type);
388
389 const boost::serialization::extended_type_info * true_type =
390 i.get_derived_extended_type_info(t);
391
392 // note:if this exception is thrown, be sure that derived pointer
393 // is either registered or exported.
394 if(NULL == true_type){
395 boost::serialization::throw_exception(
396 archive_exception(
397 archive_exception::unregistered_class,
398 "derived class not registered or exported"
399 )
400 );
401 }
402
403 // if its not a pointer to a more derived type
404 const void *vp = static_cast<const void *>(&t);
405 if(*this_type == *true_type){
406 const basic_pointer_oserializer * bpos = register_type(ar, t);
407 ar.save_pointer(vp, bpos);
408 return;
409 }
410 // convert pointer to more derived type. if this is thrown
411 // it means that the base/derived relationship hasn't be registered
412 vp = serialization::void_downcast(
413 *true_type,
414 *this_type,
415 static_cast<const void *>(&t)
416 );
417 if(NULL == vp){
418 boost::serialization::throw_exception(
419 archive_exception(
420 archive_exception::unregistered_cast,
421 true_type->get_debug_info(),
422 this_type->get_debug_info()
423 )
424 );
425 }
426
427 // since true_type is valid, and this only gets made if the
428 // pointer oserializer object has been created, this should never
429 // fail
430 const basic_pointer_oserializer * bpos
431 = static_cast<const basic_pointer_oserializer *>(
432 boost::serialization::singleton<
433 archive_serializer_map<Archive>
434 >::get_const_instance().find(*true_type)
435 );
436 BOOST_ASSERT(NULL != bpos);
437 if(NULL == bpos)
438 boost::serialization::throw_exception(
439 archive_exception(
440 archive_exception::unregistered_class,
441 "derived class not registered or exported"
442 )
443 );
444 ar.save_pointer(vp, bpos);
445 }
446 };
447
448 template<class T>
saveboost::archive::detail::save_pointer_type449 static void save(
450 Archive & ar,
451 const T & t
452 ){
453 check_pointer_level< T >();
454 check_pointer_tracking< T >();
455 typedef BOOST_DEDUCED_TYPENAME mpl::eval_if<
456 is_polymorphic< T >,
457 mpl::identity<polymorphic>,
458 mpl::identity<non_polymorphic>
459 >::type type;
460 type::save(ar, const_cast<T &>(t));
461 }
462
463 template<class TPtr>
invokeboost::archive::detail::save_pointer_type464 static void invoke(Archive &ar, const TPtr t){
465 register_type(ar, * t);
466 if(NULL == t){
467 basic_oarchive & boa
468 = boost::serialization::smart_cast_reference<basic_oarchive &>(ar);
469 boa.save_null_pointer();
470 save_access::end_preamble(ar);
471 return;
472 }
473 save(ar, * t);
474 }
475 };
476
477 template<class Archive>
478 struct save_enum_type
479 {
480 template<class T>
invokeboost::archive::detail::save_enum_type481 static void invoke(Archive &ar, const T &t){
482 // convert enum to integers on save
483 const int i = static_cast<int>(t);
484 ar << boost::serialization::make_nvp(NULL, i);
485 }
486 };
487
488 template<class Archive>
489 struct save_array_type
490 {
491 template<class T>
invokeboost::archive::detail::save_array_type492 static void invoke(Archive &ar, const T &t){
493 typedef BOOST_DEDUCED_TYPENAME boost::remove_extent< T >::type value_type;
494
495 save_access::end_preamble(ar);
496 // consider alignment
497 std::size_t c = sizeof(t) / (
498 static_cast<const char *>(static_cast<const void *>(&t[1]))
499 - static_cast<const char *>(static_cast<const void *>(&t[0]))
500 );
501 boost::serialization::collection_size_type count(c);
502 ar << BOOST_SERIALIZATION_NVP(count);
503 ar << serialization::make_array(static_cast<value_type const*>(&t[0]),count);
504 }
505 };
506
507 } // detail
508
509 template<class Archive, class T>
save(Archive & ar,T & t)510 inline void save(Archive & ar, /*const*/ T &t){
511 typedef
512 BOOST_DEDUCED_TYPENAME mpl::eval_if<is_pointer< T >,
513 mpl::identity<detail::save_pointer_type<Archive> >,
514 //else
515 BOOST_DEDUCED_TYPENAME mpl::eval_if<is_enum< T >,
516 mpl::identity<detail::save_enum_type<Archive> >,
517 //else
518 BOOST_DEDUCED_TYPENAME mpl::eval_if<is_array< T >,
519 mpl::identity<detail::save_array_type<Archive> >,
520 //else
521 mpl::identity<detail::save_non_pointer_type<Archive> >
522 >
523 >
524 >::type typex;
525 typex::invoke(ar, t);
526 }
527
528 } // namespace archive
529 } // namespace boost
530
531 #endif // BOOST_ARCHIVE_OSERIALIZER_HPP
532