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>
60 #if !defined(BOOST_MSVC) && \
61 (BOOST_WORKAROUND(__IBMCPP__, < 1210) || \
62 defined(__SUNPRO_CC) && (__SUNPRO_CC < 0x590))
63 #define DONT_USE_HAS_NEW_OPERATOR 1
65 #define DONT_USE_HAS_NEW_OPERATOR 0
68 #if ! DONT_USE_HAS_NEW_OPERATOR
69 #include <boost/type_traits/has_new_operator.hpp>
72 #include <boost/serialization/serialization.hpp>
73 #include <boost/serialization/version.hpp>
74 #include <boost/serialization/level.hpp>
75 #include <boost/serialization/tracking.hpp>
76 #include <boost/serialization/type_info_implementation.hpp>
77 #include <boost/serialization/nvp.hpp>
78 #include <boost/serialization/void_cast.hpp>
79 #include <boost/serialization/collection_size_type.hpp>
80 #include <boost/serialization/singleton.hpp>
81 #include <boost/serialization/wrapper.hpp>
82 #include <boost/serialization/array_wrapper.hpp>
84 // the following is need only for dynamic cast of polymorphic pointers
85 #include <boost/archive/archive_exception.hpp>
86 #include <boost/archive/detail/basic_iarchive.hpp>
87 #include <boost/archive/detail/basic_iserializer.hpp>
88 #include <boost/archive/detail/basic_pointer_iserializer.hpp>
89 #include <boost/archive/detail/archive_serializer_map.hpp>
90 #include <boost/archive/detail/check.hpp>
92 #include <boost/core/addressof.hpp>
96 namespace serialization {
97 class extended_type_info;
98 } // namespace serialization
102 // an accessor to permit friend access to archives. Needed because
103 // some compilers don't handle friend templates completely
106 template<class Archive, class T>
107 static void load_primitive(Archive &ar, T &t){
115 # pragma warning(push)
116 # pragma warning(disable : 4511 4512)
119 template<class Archive, class T>
120 class iserializer : public basic_iserializer
123 virtual void destroy(/*const*/ void *address) const {
124 boost::serialization::access::destroy(static_cast<T *>(address));
127 // protected constructor since it's always created by singleton
128 explicit iserializer() :
130 boost::serialization::singleton<
132 boost::serialization::type_info_implementation< T >::type
133 >::get_const_instance()
137 virtual BOOST_DLLEXPORT void load_object_data(
140 const unsigned int file_version
142 virtual bool class_info() const {
143 return boost::serialization::implementation_level< T >::value
144 >= boost::serialization::object_class_info;
146 virtual bool tracking(const unsigned int /* flags */) const {
147 return boost::serialization::tracking_level< T >::value
148 == boost::serialization::track_always
149 || ( boost::serialization::tracking_level< T >::value
150 == boost::serialization::track_selectively
151 && serialized_as_pointer());
153 virtual version_type version() const {
154 return version_type(::boost::serialization::version< T >::value);
156 virtual bool is_polymorphic() const {
157 return boost::is_polymorphic< T >::value;
159 virtual ~iserializer(){};
163 # pragma warning(pop)
166 template<class Archive, class T>
167 BOOST_DLLEXPORT void iserializer<Archive, T>::load_object_data(
170 const unsigned int file_version
172 // note: we now comment this out. Before we permited archive
173 // version # to be very large. Now we don't. To permit
174 // readers of these old archives, we have to suppress this
175 // code. Perhaps in the future we might re-enable it but
176 // permit its suppression with a runtime switch.
178 // trap case where the program cannot handle the current version
179 if(file_version > static_cast<const unsigned int>(version()))
180 boost::serialization::throw_exception(
181 archive::archive_exception(
182 boost::archive::archive_exception::unsupported_class_version,
187 // make sure call is routed through the higest interface that might
188 // be specialized by the user.
189 boost::serialization::serialize_adl(
190 boost::serialization::smart_cast_reference<Archive &>(ar),
191 * static_cast<T *>(x),
197 # pragma warning(push)
198 # pragma warning(disable : 4511 4512)
201 // the purpose of this code is to allocate memory for an object
202 // without requiring the constructor to be called. Presumably
203 // the allocated object will be subsequently initialized with
205 // note: we have the boost type trait has_new_operator but we
206 // have no corresponding has_delete_operator. So we presume
207 // that the former being true would imply that the a delete
208 // operator is also defined for the class T.
211 struct heap_allocation {
212 // boost::has_new_operator< T > doesn't work on these compilers
213 #if DONT_USE_HAS_NEW_OPERATOR
214 // This doesn't handle operator new overload for class T
215 static T * invoke_new(){
216 return static_cast<T *>(operator new(sizeof(T)));
218 static void invoke_delete(T *t){
219 (operator delete(t));
222 // note: we presume that a true value for has_new_operator
223 // implies the existence of a class specific delete operator as well
224 // as a class specific new operator.
225 struct has_new_operator {
226 static T * invoke_new() {
227 return static_cast<T *>((T::operator new)(sizeof(T)));
229 static void invoke_delete(T * t) {
230 // if compilation fails here, the likely cause that the class
231 // T has a class specific new operator but no class specific
232 // delete operator which matches the following signature.
233 // note that this solution addresses the issue that two
234 // possible signatures. But it doesn't address the possibility
235 // that the class might have class specific new with NO
236 // class specific delete at all. Patches (compatible with
238 (operator delete)(t);
241 struct doesnt_have_new_operator {
242 static T* invoke_new() {
243 return static_cast<T *>(operator new(sizeof(T)));
245 static void invoke_delete(T * t) {
246 // Note: I'm reliance upon automatic conversion from T * to void * here
247 (operator delete)(t);
250 static T * invoke_new() {
253 boost::has_new_operator< T >,
254 mpl::identity<has_new_operator >,
255 mpl::identity<doesnt_have_new_operator >
257 return typex::invoke_new();
259 static void invoke_delete(T *t) {
262 boost::has_new_operator< T >,
263 mpl::identity<has_new_operator >,
264 mpl::identity<doesnt_have_new_operator >
266 typex::invoke_delete(t);
269 explicit heap_allocation(){
289 template<class Archive, class T>
290 class pointer_iserializer :
291 public basic_pointer_iserializer
294 virtual void * heap_allocation() const {
295 detail::heap_allocation<T> h;
300 virtual const basic_iserializer & get_basic_serializer() const {
301 return boost::serialization::singleton<
302 iserializer<Archive, T>
303 >::get_const_instance();
305 BOOST_DLLEXPORT virtual void load_object_ptr(
308 const unsigned int file_version
311 // this should alway be a singleton so make the constructor protected
312 pointer_iserializer();
313 ~pointer_iserializer();
317 # pragma warning(pop)
320 // note: BOOST_DLLEXPORT is so that code for polymorphic class
321 // serialized only through base class won't get optimized out
322 template<class Archive, class T>
323 BOOST_DLLEXPORT void pointer_iserializer<Archive, T>::load_object_ptr(
326 const unsigned int file_version
330 boost::serialization::smart_cast_reference<Archive &>(ar);
332 // note that the above will throw std::bad_alloc if the allocation
333 // fails so we don't have to address this contingency here.
335 // catch exception during load_construct_data so that we don't
336 // automatically delete the t which is most likely not fully
339 // this addresses an obscure situation that occurs when
340 // load_constructor de-serializes something through a pointer.
341 ar.next_object_pointer(t);
342 boost::serialization::load_construct_data_adl<Archive, T>(
349 // if we get here the load_construct failed. The heap_allocation
350 // will be automatically deleted so we don't have to do anything
356 ar_impl >> boost::serialization::make_nvp(NULL, * static_cast<T *>(t));
359 template<class Archive, class T>
360 pointer_iserializer<Archive, T>::pointer_iserializer() :
361 basic_pointer_iserializer(
362 boost::serialization::singleton<
364 boost::serialization::type_info_implementation< T >::type
365 >::get_const_instance()
368 boost::serialization::singleton<
369 iserializer<Archive, T>
370 >::get_mutable_instance().set_bpis(this);
371 archive_serializer_map<Archive>::insert(this);
374 template<class Archive, class T>
375 pointer_iserializer<Archive, T>::~pointer_iserializer(){
376 archive_serializer_map<Archive>::erase(this);
379 template<class Archive>
380 struct load_non_pointer_type {
381 // note this bounces the call right back to the archive
382 // with no runtime overhead
383 struct load_primitive {
385 static void invoke(Archive & ar, T & t){
386 load_access::load_primitive(ar, t);
389 // note this bounces the call right back to the archive
390 // with no runtime overhead
393 static void invoke(Archive & ar, const T & t){
394 // short cut to user's serializer
395 // make sure call is routed through the higest interface that might
396 // be specialized by the user.
397 boost::serialization::serialize_adl(
400 boost::serialization::version< T >::value
405 // note this save class information including version
406 // and serialization level to the archive
407 struct load_standard {
409 static void invoke(Archive &ar, const T & t){
410 void * x = boost::addressof(const_cast<T &>(t));
413 boost::serialization::singleton<
414 iserializer<Archive, T>
415 >::get_const_instance()
420 struct load_conditional {
422 static void invoke(Archive &ar, T &t){
423 //if(0 == (ar.get_flags() & no_tracking))
424 load_standard::invoke(ar, t);
426 // load_only::invoke(ar, t);
431 static void invoke(Archive & ar, T &t){
432 typedef typename mpl::eval_if<
435 boost::serialization::implementation_level< T >,
436 mpl::int_<boost::serialization::primitive_type>
438 mpl::identity<load_primitive>,
440 typename mpl::eval_if<
441 // class info / version
443 boost::serialization::implementation_level< T >,
444 mpl::int_<boost::serialization::object_class_info>
447 mpl::identity<load_standard>,
449 typename mpl::eval_if<
452 boost::serialization::tracking_level< T >,
453 mpl::int_<boost::serialization::track_never>
456 mpl::identity<load_only>,
458 // do a fast load only tracking is turned off
459 mpl::identity<load_conditional>
461 check_object_versioning< T >();
462 check_object_level< T >();
463 typex::invoke(ar, t);
467 template<class Archive>
468 struct load_pointer_type {
472 static const basic_pointer_iserializer * register_type(Archive & /* ar */){
473 // it has? to be polymorphic
474 BOOST_STATIC_ASSERT(boost::is_polymorphic< T >::value);
475 return static_cast<basic_pointer_iserializer *>(NULL);
482 static const basic_pointer_iserializer * register_type(Archive & ar){
483 return ar.register_type(static_cast<T *>(NULL));
488 static const basic_pointer_iserializer * register_type(Archive &ar, const T* const /*t*/){
489 // there should never be any need to load an abstract polymorphic
490 // class pointer. Inhibiting code generation for this
491 // permits abstract base classes to be used - note: exception
492 // virtual serialize functions used for plug-ins
495 boost::serialization::is_abstract<const T>,
496 boost::mpl::identity<abstract>,
497 boost::mpl::identity<non_abstract>
499 return typex::template register_type< T >(ar);
503 static T * pointer_tweak(
504 const boost::serialization::extended_type_info & eti,
505 void const * const t,
508 // tweak the pointer back to the base class
509 void * upcast = const_cast<void *>(
510 boost::serialization::void_upcast(
512 boost::serialization::singleton<
514 boost::serialization::type_info_implementation< T >::type
515 >::get_const_instance(),
520 boost::serialization::throw_exception(
521 archive_exception(archive_exception::unregistered_class)
523 return static_cast<T *>(upcast);
527 static void check_load(T * const /* t */){
528 check_pointer_level< T >();
529 check_pointer_tracking< T >();
532 static const basic_pointer_iserializer *
533 find(const boost::serialization::extended_type_info & type){
534 return static_cast<const basic_pointer_iserializer *>(
535 archive_serializer_map<Archive>::find(type)
540 static void invoke(Archive & ar, Tptr & t){
542 const basic_pointer_iserializer * bpis_ptr = register_type(ar, t);
543 const basic_pointer_iserializer * newbpis_ptr = ar.load_pointer(
544 // note major hack here !!!
545 // I tried every way to convert Tptr &t (where Tptr might
546 // include const) to void * &. This is the only way
547 // I could make it work. RR
552 // if the pointer isn't that of the base class
553 if(newbpis_ptr != bpis_ptr){
554 t = pointer_tweak(newbpis_ptr->get_eti(), t, *t);
559 template<class Archive>
560 struct load_enum_type {
562 static void invoke(Archive &ar, T &t){
563 // convert integers to correct enum to load
565 ar >> boost::serialization::make_nvp(NULL, i);
566 t = static_cast< T >(i);
570 template<class Archive>
571 struct load_array_type {
573 static void invoke(Archive &ar, T &t){
574 typedef typename remove_extent< T >::type value_type;
576 // convert integers to correct enum to load
577 // determine number of elements in the array. Consider the
578 // fact that some machines will align elements on boundries
579 // other than characters.
580 std::size_t current_count = sizeof(t) / (
581 static_cast<char *>(static_cast<void *>(&t[1]))
582 - static_cast<char *>(static_cast<void *>(&t[0]))
584 boost::serialization::collection_size_type count;
585 ar >> BOOST_SERIALIZATION_NVP(count);
586 if(static_cast<std::size_t>(count) > current_count)
587 boost::serialization::throw_exception(
588 archive::archive_exception(
589 boost::archive::archive_exception::array_size_too_short
592 // explict template arguments to pass intel C++ compiler
593 ar >> serialization::make_array<
595 boost::serialization::collection_size_type
597 static_cast<value_type *>(&t[0]),
605 template<class Archive, class T>
606 inline void load(Archive & ar, T &t){
607 // if this assertion trips. It means we're trying to load a
608 // const object with a compiler that doesn't have correct
609 // function template ordering. On other compilers, this is
611 detail::check_const_loading< T >();
613 typename mpl::eval_if<is_pointer< T >,
614 mpl::identity<detail::load_pointer_type<Archive> >
616 typename mpl::eval_if<is_array< T >,
617 mpl::identity<detail::load_array_type<Archive> >
619 typename mpl::eval_if<is_enum< T >,
620 mpl::identity<detail::load_enum_type<Archive> >
622 mpl::identity<detail::load_non_pointer_type<Archive> >
626 typex::invoke(ar, t);
629 } // namespace archive
632 #endif // BOOST_ARCHIVE_DETAIL_ISERIALIZER_HPP