1 #ifndef BOOST_ARCHIVE_DETAIL_ISERIALIZER_HPP
2 #define BOOST_ARCHIVE_DETAIL_ISERIALIZER_HPP
4 // MS compatible compilers support #pragma once
7 #pragma inline_depth(511)
8 #pragma inline_recursion(on)
11 #if defined(__MWERKS__)
12 #pragma inline_depth(511)
15 /////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
16 // iserializer.hpp: interface for serialization system.
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)
23 // See http://www.boost.org for updates, documentation, and revision history.
25 #include <new> // for placement new
26 #include <cstddef> // size_t, NULL
28 #include <boost/config.hpp>
29 #include <boost/detail/workaround.hpp>
30 #if defined(BOOST_NO_STDC_NAMESPACE)
36 #include <boost/static_assert.hpp>
38 #include <boost/mpl/eval_if.hpp>
39 #include <boost/mpl/identity.hpp>
40 #include <boost/mpl/greater_equal.hpp>
41 #include <boost/mpl/equal_to.hpp>
42 #include <boost/core/no_exceptions_support.hpp>
44 #ifndef BOOST_SERIALIZATION_DEFAULT_TYPE_INFO
45 #include <boost/serialization/extended_type_info_typeid.hpp>
47 #include <boost/serialization/throw_exception.hpp>
48 #include <boost/serialization/smart_cast.hpp>
49 #include <boost/serialization/static_warning.hpp>
51 #include <boost/type_traits/is_pointer.hpp>
52 #include <boost/type_traits/is_enum.hpp>
53 #include <boost/type_traits/is_const.hpp>
54 #include <boost/type_traits/remove_const.hpp>
55 #include <boost/type_traits/remove_extent.hpp>
56 #include <boost/type_traits/is_polymorphic.hpp>
58 #include <boost/serialization/assume_abstract.hpp>
61 #define DONT_USE_HAS_NEW_OPERATOR ( \
62 BOOST_WORKAROUND(__IBMCPP__, < 1210) \
63 || defined(__SUNPRO_CC) && (__SUNPRO_CC < 0x590) \
66 #define DONT_USE_HAS_NEW_OPERATOR 0
69 #if ! DONT_USE_HAS_NEW_OPERATOR
70 #include <boost/type_traits/has_new_operator.hpp>
73 #include <boost/serialization/serialization.hpp>
74 #include <boost/serialization/version.hpp>
75 #include <boost/serialization/level.hpp>
76 #include <boost/serialization/tracking.hpp>
77 #include <boost/serialization/type_info_implementation.hpp>
78 #include <boost/serialization/nvp.hpp>
79 #include <boost/serialization/void_cast.hpp>
80 #include <boost/serialization/collection_size_type.hpp>
81 #include <boost/serialization/singleton.hpp>
82 #include <boost/serialization/wrapper.hpp>
83 #include <boost/serialization/array_wrapper.hpp>
85 // the following is need only for dynamic cast of polymorphic pointers
86 #include <boost/archive/archive_exception.hpp>
87 #include <boost/archive/detail/basic_iarchive.hpp>
88 #include <boost/archive/detail/basic_iserializer.hpp>
89 #include <boost/archive/detail/basic_pointer_iserializer.hpp>
90 #include <boost/archive/detail/archive_serializer_map.hpp>
91 #include <boost/archive/detail/check.hpp>
95 namespace serialization {
96 class extended_type_info;
97 } // namespace serialization
101 // an accessor to permit friend access to archives. Needed because
102 // some compilers don't handle friend templates completely
105 template<class Archive, class T>
106 static void load_primitive(Archive &ar, T &t){
114 # pragma warning(push)
115 # pragma warning(disable : 4511 4512)
118 template<class Archive, class T>
119 class iserializer : public basic_iserializer
122 virtual void destroy(/*const*/ void *address) const {
123 boost::serialization::access::destroy(static_cast<T *>(address));
126 // protected constructor since it's always created by singleton
127 explicit iserializer() :
129 boost::serialization::singleton<
131 boost::serialization::type_info_implementation< T >::type
132 >::get_const_instance()
136 virtual BOOST_DLLEXPORT void load_object_data(
139 const unsigned int file_version
141 virtual bool class_info() const {
142 return boost::serialization::implementation_level< T >::value
143 >= boost::serialization::object_class_info;
145 virtual bool tracking(const unsigned int /* flags */) const {
146 return boost::serialization::tracking_level< T >::value
147 == boost::serialization::track_always
148 || ( boost::serialization::tracking_level< T >::value
149 == boost::serialization::track_selectively
150 && serialized_as_pointer());
152 virtual version_type version() const {
153 return version_type(::boost::serialization::version< T >::value);
155 virtual bool is_polymorphic() const {
156 return boost::is_polymorphic< T >::value;
158 virtual ~iserializer(){};
162 # pragma warning(pop)
165 template<class Archive, class T>
166 BOOST_DLLEXPORT void iserializer<Archive, T>::load_object_data(
169 const unsigned int file_version
171 // note: we now comment this out. Before we permited archive
172 // version # to be very large. Now we don't. To permit
173 // readers of these old archives, we have to suppress this
174 // code. Perhaps in the future we might re-enable it but
175 // permit its suppression with a runtime switch.
177 // trap case where the program cannot handle the current version
178 if(file_version > static_cast<const unsigned int>(version()))
179 boost::serialization::throw_exception(
180 archive::archive_exception(
181 boost::archive::archive_exception::unsupported_class_version,
186 // make sure call is routed through the higest interface that might
187 // be specialized by the user.
188 boost::serialization::serialize_adl(
189 boost::serialization::smart_cast_reference<Archive &>(ar),
190 * static_cast<T *>(x),
196 # pragma warning(push)
197 # pragma warning(disable : 4511 4512)
200 // the purpose of this code is to allocate memory for an object
201 // without requiring the constructor to be called. Presumably
202 // the allocated object will be subsequently initialized with
204 // note: we have the boost type trait has_new_operator but we
205 // have no corresponding has_delete_operator. So we presume
206 // that the former being true would imply that the a delete
207 // operator is also defined for the class T.
210 struct heap_allocation {
211 // boost::has_new_operator< T > doesn't work on these compilers
212 #if DONT_USE_HAS_NEW_OPERATOR
213 // This doesn't handle operator new overload for class T
214 static T * invoke_new(){
215 return static_cast<T *>(operator new(sizeof(T)));
217 static void invoke_delete(T *t){
218 (operator delete(t));
221 // note: we presume that a true value for has_new_operator
222 // implies the existence of a class specific delete operator as well
223 // as a class specific new operator.
224 struct has_new_operator {
225 static T * invoke_new() {
226 return static_cast<T *>((T::operator new)(sizeof(T)));
228 static void invoke_delete(T * t) {
229 // if compilation fails here, the likely cause that the class
230 // T has a class specific new operator but no class specific
231 // delete operator which matches the following signature.
232 // note that this solution addresses the issue that two
233 // possible signatures. But it doesn't address the possibility
234 // that the class might have class specific new with NO
235 // class specific delete at all. Patches (compatible with
240 struct doesnt_have_new_operator {
241 static T* invoke_new() {
242 return static_cast<T *>(operator new(sizeof(T)));
244 static void invoke_delete(T * t) {
245 // Note: I'm reliance upon automatic conversion from T * to void * here
249 static T * invoke_new() {
252 boost::has_new_operator< T >,
253 mpl::identity<has_new_operator >,
254 mpl::identity<doesnt_have_new_operator >
256 return typex::invoke_new();
258 static void invoke_delete(T *t) {
261 boost::has_new_operator< T >,
262 mpl::identity<has_new_operator >,
263 mpl::identity<doesnt_have_new_operator >
265 typex::invoke_delete(t);
268 explicit heap_allocation(){
288 template<class Archive, class T>
289 class pointer_iserializer :
290 public basic_pointer_iserializer
293 virtual void * heap_allocation() const {
294 detail::heap_allocation<T> h;
299 virtual const basic_iserializer & get_basic_serializer() const {
300 return boost::serialization::singleton<
301 iserializer<Archive, T>
302 >::get_const_instance();
304 BOOST_DLLEXPORT virtual void load_object_ptr(
307 const unsigned int file_version
310 // this should alway be a singleton so make the constructor protected
311 pointer_iserializer();
312 ~pointer_iserializer();
316 # pragma warning(pop)
319 // note: BOOST_DLLEXPORT is so that code for polymorphic class
320 // serialized only through base class won't get optimized out
321 template<class Archive, class T>
322 BOOST_DLLEXPORT void pointer_iserializer<Archive, T>::load_object_ptr(
325 const unsigned int file_version
329 boost::serialization::smart_cast_reference<Archive &>(ar);
331 // note that the above will throw std::bad_alloc if the allocation
332 // fails so we don't have to address this contingency here.
334 // catch exception during load_construct_data so that we don't
335 // automatically delete the t which is most likely not fully
338 // this addresses an obscure situation that occurs when
339 // load_constructor de-serializes something through a pointer.
340 ar.next_object_pointer(t);
341 boost::serialization::load_construct_data_adl<Archive, T>(
348 // if we get here the load_construct failed. The heap_allocation
349 // will be automatically deleted so we don't have to do anything
355 ar_impl >> boost::serialization::make_nvp(NULL, * static_cast<T *>(t));
358 template<class Archive, class T>
359 pointer_iserializer<Archive, T>::pointer_iserializer() :
360 basic_pointer_iserializer(
361 boost::serialization::singleton<
363 boost::serialization::type_info_implementation< T >::type
364 >::get_const_instance()
367 boost::serialization::singleton<
368 iserializer<Archive, T>
369 >::get_mutable_instance().set_bpis(this);
370 archive_serializer_map<Archive>::insert(this);
373 template<class Archive, class T>
374 pointer_iserializer<Archive, T>::~pointer_iserializer(){
375 archive_serializer_map<Archive>::erase(this);
378 template<class Archive>
379 struct load_non_pointer_type {
380 // note this bounces the call right back to the archive
381 // with no runtime overhead
382 struct load_primitive {
384 static void invoke(Archive & ar, T & t){
385 load_access::load_primitive(ar, t);
388 // note this bounces the call right back to the archive
389 // with no runtime overhead
392 static void invoke(Archive & ar, const T & t){
393 // short cut to user's serializer
394 // make sure call is routed through the higest interface that might
395 // be specialized by the user.
396 boost::serialization::serialize_adl(
399 boost::serialization::version< T >::value
404 // note this save class information including version
405 // and serialization level to the archive
406 struct load_standard {
408 static void invoke(Archive &ar, const T & t){
409 void * x = & const_cast<T &>(t);
412 boost::serialization::singleton<
413 iserializer<Archive, T>
414 >::get_const_instance()
419 struct load_conditional {
421 static void invoke(Archive &ar, T &t){
422 //if(0 == (ar.get_flags() & no_tracking))
423 load_standard::invoke(ar, t);
425 // load_only::invoke(ar, t);
430 static void invoke(Archive & ar, T &t){
431 typedef typename mpl::eval_if<
434 boost::serialization::implementation_level< T >,
435 mpl::int_<boost::serialization::primitive_type>
437 mpl::identity<load_primitive>,
439 typename mpl::eval_if<
440 // class info / version
442 boost::serialization::implementation_level< T >,
443 mpl::int_<boost::serialization::object_class_info>
446 mpl::identity<load_standard>,
448 typename mpl::eval_if<
451 boost::serialization::tracking_level< T >,
452 mpl::int_<boost::serialization::track_never>
455 mpl::identity<load_only>,
457 // do a fast load only tracking is turned off
458 mpl::identity<load_conditional>
460 check_object_versioning< T >();
461 check_object_level< T >();
462 typex::invoke(ar, t);
466 template<class Archive>
467 struct load_pointer_type {
471 static const basic_pointer_iserializer * register_type(Archive & /* ar */){
472 // it has? to be polymorphic
473 BOOST_STATIC_ASSERT(boost::is_polymorphic< T >::value);
474 return static_cast<basic_pointer_iserializer *>(NULL);
481 static const basic_pointer_iserializer * register_type(Archive & ar){
482 return ar.register_type(static_cast<T *>(NULL));
487 static const basic_pointer_iserializer * register_type(Archive &ar, const T & /*t*/){
488 // there should never be any need to load an abstract polymorphic
489 // class pointer. Inhibiting code generation for this
490 // permits abstract base classes to be used - note: exception
491 // virtual serialize functions used for plug-ins
494 boost::serialization::is_abstract<const T>,
495 boost::mpl::identity<abstract>,
496 boost::mpl::identity<non_abstract>
498 return typex::template register_type< T >(ar);
502 static T * pointer_tweak(
503 const boost::serialization::extended_type_info & eti,
504 void const * const t,
507 // tweak the pointer back to the base class
508 void * upcast = const_cast<void *>(
509 boost::serialization::void_upcast(
511 boost::serialization::singleton<
513 boost::serialization::type_info_implementation< T >::type
514 >::get_const_instance(),
519 boost::serialization::throw_exception(
520 archive_exception(archive_exception::unregistered_class)
522 return static_cast<T *>(upcast);
526 static void check_load(T & /* t */){
527 check_pointer_level< T >();
528 check_pointer_tracking< T >();
531 static const basic_pointer_iserializer *
532 find(const boost::serialization::extended_type_info & type){
533 return static_cast<const basic_pointer_iserializer *>(
534 archive_serializer_map<Archive>::find(type)
539 static void invoke(Archive & ar, Tptr & t){
541 const basic_pointer_iserializer * bpis_ptr = register_type(ar, *t);
542 const basic_pointer_iserializer * newbpis_ptr = ar.load_pointer(
543 // note major hack here !!!
544 // I tried every way to convert Tptr &t (where Tptr might
545 // include const) to void * &. This is the only way
546 // I could make it work. RR
551 // if the pointer isn't that of the base class
552 if(newbpis_ptr != bpis_ptr){
553 t = pointer_tweak(newbpis_ptr->get_eti(), t, *t);
558 template<class Archive>
559 struct load_enum_type {
561 static void invoke(Archive &ar, T &t){
562 // convert integers to correct enum to load
564 ar >> boost::serialization::make_nvp(NULL, i);
565 t = static_cast< T >(i);
569 template<class Archive>
570 struct load_array_type {
572 static void invoke(Archive &ar, T &t){
573 typedef typename remove_extent< T >::type value_type;
575 // convert integers to correct enum to load
576 // determine number of elements in the array. Consider the
577 // fact that some machines will align elements on boundries
578 // other than characters.
579 std::size_t current_count = sizeof(t) / (
580 static_cast<char *>(static_cast<void *>(&t[1]))
581 - static_cast<char *>(static_cast<void *>(&t[0]))
583 boost::serialization::collection_size_type count;
584 ar >> BOOST_SERIALIZATION_NVP(count);
585 if(static_cast<std::size_t>(count) > current_count)
586 boost::serialization::throw_exception(
587 archive::archive_exception(
588 boost::archive::archive_exception::array_size_too_short
591 // explict template arguments to pass intel C++ compiler
592 ar >> serialization::make_array<
594 boost::serialization::collection_size_type
596 static_cast<value_type *>(&t[0]),
604 template<class Archive, class T>
605 inline void load(Archive & ar, T &t){
606 // if this assertion trips. It means we're trying to load a
607 // const object with a compiler that doesn't have correct
608 // funtion template ordering. On other compilers, this is
610 detail::check_const_loading< T >();
612 typename mpl::eval_if<is_pointer< T >,
613 mpl::identity<detail::load_pointer_type<Archive> >
615 typename mpl::eval_if<is_array< T >,
616 mpl::identity<detail::load_array_type<Archive> >
618 typename mpl::eval_if<is_enum< T >,
619 mpl::identity<detail::load_enum_type<Archive> >
621 mpl::identity<detail::load_non_pointer_type<Archive> >
625 typex::invoke(ar, t);
628 } // namespace archive
631 #endif // BOOST_ARCHIVE_DETAIL_ISERIALIZER_HPP