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