|
Chris@16
|
1 #ifndef BOOST_ARCHIVE_DETAIL_ISERIALIZER_HPP
|
|
Chris@16
|
2 #define BOOST_ARCHIVE_DETAIL_ISERIALIZER_HPP
|
|
Chris@16
|
3
|
|
Chris@16
|
4 // MS compatible compilers support #pragma once
|
|
Chris@16
|
5 #if defined(_MSC_VER) && (_MSC_VER >= 1020)
|
|
Chris@16
|
6 # pragma once
|
|
Chris@16
|
7 #pragma inline_depth(511)
|
|
Chris@16
|
8 #pragma inline_recursion(on)
|
|
Chris@16
|
9 #endif
|
|
Chris@16
|
10
|
|
Chris@16
|
11 #if defined(__MWERKS__)
|
|
Chris@16
|
12 #pragma inline_depth(511)
|
|
Chris@16
|
13 #endif
|
|
Chris@16
|
14
|
|
Chris@16
|
15 /////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
|
|
Chris@16
|
16 // iserializer.hpp: interface for serialization system.
|
|
Chris@16
|
17
|
|
Chris@16
|
18 // (C) Copyright 2002 Robert Ramey - http://www.rrsd.com .
|
|
Chris@16
|
19 // Use, modification and distribution is subject to the Boost Software
|
|
Chris@16
|
20 // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
|
Chris@16
|
21 // http://www.boost.org/LICENSE_1_0.txt)
|
|
Chris@16
|
22
|
|
Chris@16
|
23 // See http://www.boost.org for updates, documentation, and revision history.
|
|
Chris@16
|
24
|
|
Chris@16
|
25 #include <new> // for placement new
|
|
Chris@16
|
26 #include <memory> // for auto_ptr
|
|
Chris@16
|
27 #include <cstddef> // size_t, NULL
|
|
Chris@16
|
28
|
|
Chris@16
|
29 #include <boost/config.hpp>
|
|
Chris@16
|
30 #include <boost/detail/workaround.hpp>
|
|
Chris@16
|
31 #if defined(BOOST_NO_STDC_NAMESPACE)
|
|
Chris@16
|
32 namespace std{
|
|
Chris@16
|
33 using ::size_t;
|
|
Chris@16
|
34 } // namespace std
|
|
Chris@16
|
35 #endif
|
|
Chris@16
|
36
|
|
Chris@16
|
37 #include <boost/static_assert.hpp>
|
|
Chris@16
|
38
|
|
Chris@16
|
39 #include <boost/mpl/eval_if.hpp>
|
|
Chris@16
|
40 #include <boost/mpl/identity.hpp>
|
|
Chris@16
|
41 #include <boost/mpl/greater_equal.hpp>
|
|
Chris@16
|
42 #include <boost/mpl/equal_to.hpp>
|
|
Chris@16
|
43 #include <boost/mpl/bool.hpp>
|
|
Chris@16
|
44 #include <boost/detail/no_exceptions_support.hpp>
|
|
Chris@16
|
45
|
|
Chris@16
|
46 #ifndef BOOST_SERIALIZATION_DEFAULT_TYPE_INFO
|
|
Chris@16
|
47 #include <boost/serialization/extended_type_info_typeid.hpp>
|
|
Chris@16
|
48 #endif
|
|
Chris@16
|
49 #include <boost/serialization/throw_exception.hpp>
|
|
Chris@16
|
50 #include <boost/serialization/smart_cast.hpp>
|
|
Chris@16
|
51 #include <boost/serialization/static_warning.hpp>
|
|
Chris@16
|
52
|
|
Chris@16
|
53 #include <boost/type_traits/is_pointer.hpp>
|
|
Chris@16
|
54 #include <boost/type_traits/is_enum.hpp>
|
|
Chris@16
|
55 #include <boost/type_traits/is_const.hpp>
|
|
Chris@16
|
56 #include <boost/type_traits/remove_const.hpp>
|
|
Chris@16
|
57 #include <boost/type_traits/remove_extent.hpp>
|
|
Chris@16
|
58 #include <boost/type_traits/is_polymorphic.hpp>
|
|
Chris@16
|
59
|
|
Chris@16
|
60 #include <boost/serialization/assume_abstract.hpp>
|
|
Chris@16
|
61
|
|
Chris@16
|
62 #define DONT_USE_HAS_NEW_OPERATOR ( \
|
|
Chris@16
|
63 defined(__BORLANDC__) \
|
|
Chris@16
|
64 || BOOST_WORKAROUND(__IBMCPP__, < 1210) \
|
|
Chris@16
|
65 || defined(BOOST_MSVC) && (BOOST_MSVC <= 1300) \
|
|
Chris@16
|
66 || defined(__SUNPRO_CC) && (__SUNPRO_CC < 0x590) \
|
|
Chris@16
|
67 )
|
|
Chris@16
|
68
|
|
Chris@16
|
69 #if ! DONT_USE_HAS_NEW_OPERATOR
|
|
Chris@16
|
70 #include <boost/type_traits/has_new_operator.hpp>
|
|
Chris@16
|
71 #endif
|
|
Chris@16
|
72
|
|
Chris@16
|
73 #include <boost/serialization/serialization.hpp>
|
|
Chris@16
|
74 #include <boost/serialization/version.hpp>
|
|
Chris@16
|
75 #include <boost/serialization/level.hpp>
|
|
Chris@16
|
76 #include <boost/serialization/tracking.hpp>
|
|
Chris@16
|
77 #include <boost/serialization/type_info_implementation.hpp>
|
|
Chris@16
|
78 #include <boost/serialization/nvp.hpp>
|
|
Chris@16
|
79 #include <boost/serialization/void_cast.hpp>
|
|
Chris@16
|
80 #include <boost/serialization/array.hpp>
|
|
Chris@16
|
81 #include <boost/serialization/collection_size_type.hpp>
|
|
Chris@16
|
82 #include <boost/serialization/singleton.hpp>
|
|
Chris@16
|
83 #include <boost/serialization/wrapper.hpp>
|
|
Chris@16
|
84
|
|
Chris@16
|
85 // the following is need only for dynamic cast of polymorphic pointers
|
|
Chris@16
|
86 #include <boost/archive/archive_exception.hpp>
|
|
Chris@16
|
87 #include <boost/archive/detail/basic_iarchive.hpp>
|
|
Chris@16
|
88 #include <boost/archive/detail/basic_iserializer.hpp>
|
|
Chris@16
|
89 #include <boost/archive/detail/basic_pointer_iserializer.hpp>
|
|
Chris@16
|
90 #include <boost/archive/detail/archive_serializer_map.hpp>
|
|
Chris@16
|
91 #include <boost/archive/detail/check.hpp>
|
|
Chris@16
|
92
|
|
Chris@16
|
93 namespace boost {
|
|
Chris@16
|
94
|
|
Chris@16
|
95 namespace serialization {
|
|
Chris@16
|
96 class extended_type_info;
|
|
Chris@16
|
97 } // namespace serialization
|
|
Chris@16
|
98
|
|
Chris@16
|
99 namespace archive {
|
|
Chris@16
|
100
|
|
Chris@16
|
101 // an accessor to permit friend access to archives. Needed because
|
|
Chris@16
|
102 // some compilers don't handle friend templates completely
|
|
Chris@16
|
103 class load_access {
|
|
Chris@16
|
104 public:
|
|
Chris@16
|
105 template<class Archive, class T>
|
|
Chris@16
|
106 static void load_primitive(Archive &ar, T &t){
|
|
Chris@16
|
107 ar.load(t);
|
|
Chris@16
|
108 }
|
|
Chris@16
|
109 };
|
|
Chris@16
|
110
|
|
Chris@16
|
111 namespace detail {
|
|
Chris@16
|
112
|
|
Chris@16
|
113 #ifdef BOOST_MSVC
|
|
Chris@16
|
114 # pragma warning(push)
|
|
Chris@16
|
115 # pragma warning(disable : 4511 4512)
|
|
Chris@16
|
116 #endif
|
|
Chris@16
|
117
|
|
Chris@16
|
118 template<class Archive, class T>
|
|
Chris@16
|
119 class iserializer : public basic_iserializer
|
|
Chris@16
|
120 {
|
|
Chris@16
|
121 private:
|
|
Chris@16
|
122 virtual void destroy(/*const*/ void *address) const {
|
|
Chris@16
|
123 boost::serialization::access::destroy(static_cast<T *>(address));
|
|
Chris@16
|
124 }
|
|
Chris@16
|
125 protected:
|
|
Chris@16
|
126 // protected constructor since it's always created by singleton
|
|
Chris@16
|
127 explicit iserializer() :
|
|
Chris@16
|
128 basic_iserializer(
|
|
Chris@16
|
129 boost::serialization::singleton<
|
|
Chris@16
|
130 BOOST_DEDUCED_TYPENAME
|
|
Chris@16
|
131 boost::serialization::type_info_implementation< T >::type
|
|
Chris@16
|
132 >::get_const_instance()
|
|
Chris@16
|
133 )
|
|
Chris@16
|
134 {}
|
|
Chris@16
|
135 public:
|
|
Chris@16
|
136 virtual BOOST_DLLEXPORT void load_object_data(
|
|
Chris@16
|
137 basic_iarchive & ar,
|
|
Chris@16
|
138 void *x,
|
|
Chris@16
|
139 const unsigned int file_version
|
|
Chris@16
|
140 ) const BOOST_USED;
|
|
Chris@16
|
141 virtual bool class_info() const {
|
|
Chris@16
|
142 return boost::serialization::implementation_level< T >::value
|
|
Chris@16
|
143 >= boost::serialization::object_class_info;
|
|
Chris@16
|
144 }
|
|
Chris@16
|
145 virtual bool tracking(const unsigned int /* flags */) const {
|
|
Chris@16
|
146 return boost::serialization::tracking_level< T >::value
|
|
Chris@16
|
147 == boost::serialization::track_always
|
|
Chris@16
|
148 || ( boost::serialization::tracking_level< T >::value
|
|
Chris@16
|
149 == boost::serialization::track_selectively
|
|
Chris@16
|
150 && serialized_as_pointer());
|
|
Chris@16
|
151 }
|
|
Chris@16
|
152 virtual version_type version() const {
|
|
Chris@16
|
153 return version_type(::boost::serialization::version< T >::value);
|
|
Chris@16
|
154 }
|
|
Chris@16
|
155 virtual bool is_polymorphic() const {
|
|
Chris@16
|
156 return boost::is_polymorphic< T >::value;
|
|
Chris@16
|
157 }
|
|
Chris@16
|
158 virtual ~iserializer(){};
|
|
Chris@16
|
159 };
|
|
Chris@16
|
160
|
|
Chris@16
|
161 #ifdef BOOST_MSVC
|
|
Chris@16
|
162 # pragma warning(pop)
|
|
Chris@16
|
163 #endif
|
|
Chris@16
|
164
|
|
Chris@16
|
165 template<class Archive, class T>
|
|
Chris@16
|
166 BOOST_DLLEXPORT void iserializer<Archive, T>::load_object_data(
|
|
Chris@16
|
167 basic_iarchive & ar,
|
|
Chris@16
|
168 void *x,
|
|
Chris@16
|
169 const unsigned int file_version
|
|
Chris@16
|
170 ) const {
|
|
Chris@16
|
171 // note: we now comment this out. Before we permited archive
|
|
Chris@16
|
172 // version # to be very large. Now we don't. To permit
|
|
Chris@16
|
173 // readers of these old archives, we have to suppress this
|
|
Chris@16
|
174 // code. Perhaps in the future we might re-enable it but
|
|
Chris@16
|
175 // permit its suppression with a runtime switch.
|
|
Chris@16
|
176 #if 0
|
|
Chris@16
|
177 // trap case where the program cannot handle the current version
|
|
Chris@16
|
178 if(file_version > static_cast<const unsigned int>(version()))
|
|
Chris@16
|
179 boost::serialization::throw_exception(
|
|
Chris@16
|
180 archive::archive_exception(
|
|
Chris@16
|
181 boost::archive::archive_exception::unsupported_class_version,
|
|
Chris@16
|
182 get_debug_info()
|
|
Chris@16
|
183 )
|
|
Chris@16
|
184 );
|
|
Chris@16
|
185 #endif
|
|
Chris@16
|
186 // make sure call is routed through the higest interface that might
|
|
Chris@16
|
187 // be specialized by the user.
|
|
Chris@16
|
188 boost::serialization::serialize_adl(
|
|
Chris@16
|
189 boost::serialization::smart_cast_reference<Archive &>(ar),
|
|
Chris@16
|
190 * static_cast<T *>(x),
|
|
Chris@16
|
191 file_version
|
|
Chris@16
|
192 );
|
|
Chris@16
|
193 }
|
|
Chris@16
|
194
|
|
Chris@16
|
195 #ifdef BOOST_MSVC
|
|
Chris@16
|
196 # pragma warning(push)
|
|
Chris@16
|
197 # pragma warning(disable : 4511 4512)
|
|
Chris@16
|
198 #endif
|
|
Chris@16
|
199
|
|
Chris@16
|
200 template<class Archive, class T>
|
|
Chris@16
|
201 class pointer_iserializer :
|
|
Chris@16
|
202 public basic_pointer_iserializer
|
|
Chris@16
|
203 {
|
|
Chris@16
|
204 private:
|
|
Chris@16
|
205 virtual const basic_iserializer & get_basic_serializer() const {
|
|
Chris@16
|
206 return boost::serialization::singleton<
|
|
Chris@16
|
207 iserializer<Archive, T>
|
|
Chris@16
|
208 >::get_const_instance();
|
|
Chris@16
|
209 }
|
|
Chris@16
|
210 BOOST_DLLEXPORT virtual void load_object_ptr(
|
|
Chris@16
|
211 basic_iarchive & ar,
|
|
Chris@16
|
212 void * & x,
|
|
Chris@16
|
213 const unsigned int file_version
|
|
Chris@16
|
214 ) const BOOST_USED;
|
|
Chris@16
|
215 protected:
|
|
Chris@16
|
216 // this should alway be a singleton so make the constructor protected
|
|
Chris@16
|
217 pointer_iserializer();
|
|
Chris@16
|
218 ~pointer_iserializer();
|
|
Chris@16
|
219 };
|
|
Chris@16
|
220
|
|
Chris@16
|
221 #ifdef BOOST_MSVC
|
|
Chris@16
|
222 # pragma warning(pop)
|
|
Chris@16
|
223 #endif
|
|
Chris@16
|
224
|
|
Chris@16
|
225 // note trick to be sure that operator new is using class specific
|
|
Chris@16
|
226 // version if such exists. Due to Peter Dimov.
|
|
Chris@16
|
227 // note: the following fails if T has no default constructor.
|
|
Chris@16
|
228 // otherwise it would have been ideal
|
|
Chris@16
|
229 //struct heap_allocator : public T
|
|
Chris@16
|
230 //{
|
|
Chris@16
|
231 // T * invoke(){
|
|
Chris@16
|
232 // return ::new(sizeof(T));
|
|
Chris@16
|
233 // }
|
|
Chris@16
|
234 //}
|
|
Chris@16
|
235
|
|
Chris@16
|
236 template<class T>
|
|
Chris@16
|
237 struct heap_allocator
|
|
Chris@16
|
238 {
|
|
Chris@16
|
239 // boost::has_new_operator< T > doesn't work on these compilers
|
|
Chris@16
|
240 #if DONT_USE_HAS_NEW_OPERATOR
|
|
Chris@16
|
241 // This doesn't handle operator new overload for class T
|
|
Chris@16
|
242 static T * invoke(){
|
|
Chris@16
|
243 return static_cast<T *>(operator new(sizeof(T)));
|
|
Chris@16
|
244 }
|
|
Chris@16
|
245 #else
|
|
Chris@16
|
246 struct has_new_operator {
|
|
Chris@16
|
247 static T* invoke() {
|
|
Chris@16
|
248 return static_cast<T *>((T::operator new)(sizeof(T)));
|
|
Chris@16
|
249 }
|
|
Chris@16
|
250 };
|
|
Chris@16
|
251 struct doesnt_have_new_operator {
|
|
Chris@16
|
252 static T* invoke() {
|
|
Chris@16
|
253 return static_cast<T *>(operator new(sizeof(T)));
|
|
Chris@16
|
254 }
|
|
Chris@16
|
255 };
|
|
Chris@16
|
256 static T * invoke() {
|
|
Chris@16
|
257 typedef BOOST_DEDUCED_TYPENAME
|
|
Chris@16
|
258 mpl::eval_if<
|
|
Chris@16
|
259 boost::has_new_operator< T >,
|
|
Chris@16
|
260 mpl::identity<has_new_operator >,
|
|
Chris@16
|
261 mpl::identity<doesnt_have_new_operator >
|
|
Chris@16
|
262 >::type typex;
|
|
Chris@16
|
263 return typex::invoke();
|
|
Chris@16
|
264 }
|
|
Chris@16
|
265 #endif
|
|
Chris@16
|
266 };
|
|
Chris@16
|
267
|
|
Chris@16
|
268 // due to Martin Ecker
|
|
Chris@16
|
269 template <typename T>
|
|
Chris@16
|
270 class auto_ptr_with_deleter
|
|
Chris@16
|
271 {
|
|
Chris@16
|
272 public:
|
|
Chris@16
|
273 explicit auto_ptr_with_deleter(T* p) :
|
|
Chris@16
|
274 m_p(p)
|
|
Chris@16
|
275 {}
|
|
Chris@16
|
276 ~auto_ptr_with_deleter(){
|
|
Chris@16
|
277 if (m_p)
|
|
Chris@16
|
278 boost::serialization::access::destroy(m_p);
|
|
Chris@16
|
279 }
|
|
Chris@16
|
280 T* get() const {
|
|
Chris@16
|
281 return m_p;
|
|
Chris@16
|
282 }
|
|
Chris@16
|
283
|
|
Chris@16
|
284 T* release() {
|
|
Chris@16
|
285 T* p = m_p;
|
|
Chris@16
|
286 m_p = NULL;
|
|
Chris@16
|
287 return p;
|
|
Chris@16
|
288 }
|
|
Chris@16
|
289 private:
|
|
Chris@16
|
290 T* m_p;
|
|
Chris@16
|
291 };
|
|
Chris@16
|
292
|
|
Chris@16
|
293 // note: BOOST_DLLEXPORT is so that code for polymorphic class
|
|
Chris@16
|
294 // serialized only through base class won't get optimized out
|
|
Chris@16
|
295 template<class Archive, class T>
|
|
Chris@16
|
296 BOOST_DLLEXPORT void pointer_iserializer<Archive, T>::load_object_ptr(
|
|
Chris@16
|
297 basic_iarchive & ar,
|
|
Chris@16
|
298 void * & x,
|
|
Chris@16
|
299 const unsigned int file_version
|
|
Chris@16
|
300 ) const
|
|
Chris@16
|
301 {
|
|
Chris@16
|
302 Archive & ar_impl =
|
|
Chris@16
|
303 boost::serialization::smart_cast_reference<Archive &>(ar);
|
|
Chris@16
|
304
|
|
Chris@16
|
305 auto_ptr_with_deleter< T > ap(heap_allocator< T >::invoke());
|
|
Chris@16
|
306 if(NULL == ap.get())
|
|
Chris@16
|
307 boost::serialization::throw_exception(std::bad_alloc()) ;
|
|
Chris@16
|
308
|
|
Chris@16
|
309 T * t = ap.get();
|
|
Chris@16
|
310 x = t;
|
|
Chris@16
|
311
|
|
Chris@16
|
312 // catch exception during load_construct_data so that we don't
|
|
Chris@16
|
313 // automatically delete the t which is most likely not fully
|
|
Chris@16
|
314 // constructed
|
|
Chris@16
|
315 BOOST_TRY {
|
|
Chris@16
|
316 // this addresses an obscure situtation that occurs when
|
|
Chris@16
|
317 // load_constructor de-serializes something through a pointer.
|
|
Chris@16
|
318 ar.next_object_pointer(t);
|
|
Chris@16
|
319 boost::serialization::load_construct_data_adl<Archive, T>(
|
|
Chris@16
|
320 ar_impl,
|
|
Chris@16
|
321 t,
|
|
Chris@16
|
322 file_version
|
|
Chris@16
|
323 );
|
|
Chris@16
|
324 }
|
|
Chris@16
|
325 BOOST_CATCH(...){
|
|
Chris@16
|
326 ap.release();
|
|
Chris@16
|
327 BOOST_RETHROW;
|
|
Chris@16
|
328 }
|
|
Chris@16
|
329 BOOST_CATCH_END
|
|
Chris@16
|
330
|
|
Chris@16
|
331 ar_impl >> boost::serialization::make_nvp(NULL, * t);
|
|
Chris@16
|
332 ap.release();
|
|
Chris@16
|
333 }
|
|
Chris@16
|
334
|
|
Chris@16
|
335 template<class Archive, class T>
|
|
Chris@16
|
336 pointer_iserializer<Archive, T>::pointer_iserializer() :
|
|
Chris@16
|
337 basic_pointer_iserializer(
|
|
Chris@16
|
338 boost::serialization::singleton<
|
|
Chris@16
|
339 BOOST_DEDUCED_TYPENAME
|
|
Chris@16
|
340 boost::serialization::type_info_implementation< T >::type
|
|
Chris@16
|
341 >::get_const_instance()
|
|
Chris@16
|
342 )
|
|
Chris@16
|
343 {
|
|
Chris@16
|
344 boost::serialization::singleton<
|
|
Chris@16
|
345 iserializer<Archive, T>
|
|
Chris@16
|
346 >::get_mutable_instance().set_bpis(this);
|
|
Chris@16
|
347 archive_serializer_map<Archive>::insert(this);
|
|
Chris@16
|
348 }
|
|
Chris@16
|
349
|
|
Chris@16
|
350 template<class Archive, class T>
|
|
Chris@16
|
351 pointer_iserializer<Archive, T>::~pointer_iserializer(){
|
|
Chris@16
|
352 archive_serializer_map<Archive>::erase(this);
|
|
Chris@16
|
353 }
|
|
Chris@16
|
354
|
|
Chris@16
|
355 template<class Archive>
|
|
Chris@16
|
356 struct load_non_pointer_type {
|
|
Chris@16
|
357 // note this bounces the call right back to the archive
|
|
Chris@16
|
358 // with no runtime overhead
|
|
Chris@16
|
359 struct load_primitive {
|
|
Chris@16
|
360 template<class T>
|
|
Chris@16
|
361 static void invoke(Archive & ar, T & t){
|
|
Chris@16
|
362 load_access::load_primitive(ar, t);
|
|
Chris@16
|
363 }
|
|
Chris@16
|
364 };
|
|
Chris@16
|
365 // note this bounces the call right back to the archive
|
|
Chris@16
|
366 // with no runtime overhead
|
|
Chris@16
|
367 struct load_only {
|
|
Chris@16
|
368 template<class T>
|
|
Chris@16
|
369 static void invoke(Archive & ar, const T & t){
|
|
Chris@16
|
370 // short cut to user's serializer
|
|
Chris@16
|
371 // make sure call is routed through the higest interface that might
|
|
Chris@16
|
372 // be specialized by the user.
|
|
Chris@16
|
373 boost::serialization::serialize_adl(
|
|
Chris@16
|
374 ar,
|
|
Chris@16
|
375 const_cast<T &>(t),
|
|
Chris@16
|
376 boost::serialization::version< T >::value
|
|
Chris@16
|
377 );
|
|
Chris@16
|
378 }
|
|
Chris@16
|
379 };
|
|
Chris@16
|
380
|
|
Chris@16
|
381 // note this save class information including version
|
|
Chris@16
|
382 // and serialization level to the archive
|
|
Chris@16
|
383 struct load_standard {
|
|
Chris@16
|
384 template<class T>
|
|
Chris@16
|
385 static void invoke(Archive &ar, const T & t){
|
|
Chris@16
|
386 void * x = & const_cast<T &>(t);
|
|
Chris@16
|
387 ar.load_object(
|
|
Chris@16
|
388 x,
|
|
Chris@16
|
389 boost::serialization::singleton<
|
|
Chris@16
|
390 iserializer<Archive, T>
|
|
Chris@16
|
391 >::get_const_instance()
|
|
Chris@16
|
392 );
|
|
Chris@16
|
393 }
|
|
Chris@16
|
394 };
|
|
Chris@16
|
395
|
|
Chris@16
|
396 struct load_conditional {
|
|
Chris@16
|
397 template<class T>
|
|
Chris@16
|
398 static void invoke(Archive &ar, T &t){
|
|
Chris@16
|
399 //if(0 == (ar.get_flags() & no_tracking))
|
|
Chris@16
|
400 load_standard::invoke(ar, t);
|
|
Chris@16
|
401 //else
|
|
Chris@16
|
402 // load_only::invoke(ar, t);
|
|
Chris@16
|
403 }
|
|
Chris@16
|
404 };
|
|
Chris@16
|
405
|
|
Chris@16
|
406 template<class T>
|
|
Chris@16
|
407 static void invoke(Archive & ar, T &t){
|
|
Chris@16
|
408 typedef BOOST_DEDUCED_TYPENAME mpl::eval_if<
|
|
Chris@16
|
409 // if its primitive
|
|
Chris@16
|
410 mpl::equal_to<
|
|
Chris@16
|
411 boost::serialization::implementation_level< T >,
|
|
Chris@16
|
412 mpl::int_<boost::serialization::primitive_type>
|
|
Chris@16
|
413 >,
|
|
Chris@16
|
414 mpl::identity<load_primitive>,
|
|
Chris@16
|
415 // else
|
|
Chris@16
|
416 BOOST_DEDUCED_TYPENAME mpl::eval_if<
|
|
Chris@16
|
417 // class info / version
|
|
Chris@16
|
418 mpl::greater_equal<
|
|
Chris@16
|
419 boost::serialization::implementation_level< T >,
|
|
Chris@16
|
420 mpl::int_<boost::serialization::object_class_info>
|
|
Chris@16
|
421 >,
|
|
Chris@16
|
422 // do standard load
|
|
Chris@16
|
423 mpl::identity<load_standard>,
|
|
Chris@16
|
424 // else
|
|
Chris@16
|
425 BOOST_DEDUCED_TYPENAME mpl::eval_if<
|
|
Chris@16
|
426 // no tracking
|
|
Chris@16
|
427 mpl::equal_to<
|
|
Chris@16
|
428 boost::serialization::tracking_level< T >,
|
|
Chris@16
|
429 mpl::int_<boost::serialization::track_never>
|
|
Chris@16
|
430 >,
|
|
Chris@16
|
431 // do a fast load
|
|
Chris@16
|
432 mpl::identity<load_only>,
|
|
Chris@16
|
433 // else
|
|
Chris@16
|
434 // do a fast load only tracking is turned off
|
|
Chris@16
|
435 mpl::identity<load_conditional>
|
|
Chris@16
|
436 > > >::type typex;
|
|
Chris@16
|
437 check_object_versioning< T >();
|
|
Chris@16
|
438 check_object_level< T >();
|
|
Chris@16
|
439 typex::invoke(ar, t);
|
|
Chris@16
|
440 }
|
|
Chris@16
|
441 };
|
|
Chris@16
|
442
|
|
Chris@16
|
443 template<class Archive>
|
|
Chris@16
|
444 struct load_pointer_type {
|
|
Chris@16
|
445 struct abstract
|
|
Chris@16
|
446 {
|
|
Chris@16
|
447 template<class T>
|
|
Chris@16
|
448 static const basic_pointer_iserializer * register_type(Archive & /* ar */){
|
|
Chris@16
|
449 // it has? to be polymorphic
|
|
Chris@16
|
450 BOOST_STATIC_ASSERT(boost::is_polymorphic< T >::value);
|
|
Chris@16
|
451 return static_cast<basic_pointer_iserializer *>(NULL);
|
|
Chris@16
|
452 }
|
|
Chris@16
|
453 };
|
|
Chris@16
|
454
|
|
Chris@16
|
455 struct non_abstract
|
|
Chris@16
|
456 {
|
|
Chris@16
|
457 template<class T>
|
|
Chris@16
|
458 static const basic_pointer_iserializer * register_type(Archive & ar){
|
|
Chris@16
|
459 return ar.register_type(static_cast<T *>(NULL));
|
|
Chris@16
|
460 }
|
|
Chris@16
|
461 };
|
|
Chris@16
|
462
|
|
Chris@16
|
463 template<class T>
|
|
Chris@16
|
464 static const basic_pointer_iserializer * register_type(Archive &ar, const T & /*t*/){
|
|
Chris@16
|
465 // there should never be any need to load an abstract polymorphic
|
|
Chris@16
|
466 // class pointer. Inhibiting code generation for this
|
|
Chris@16
|
467 // permits abstract base classes to be used - note: exception
|
|
Chris@16
|
468 // virtual serialize functions used for plug-ins
|
|
Chris@16
|
469 typedef BOOST_DEDUCED_TYPENAME
|
|
Chris@16
|
470 mpl::eval_if<
|
|
Chris@16
|
471 boost::serialization::is_abstract<const T>,
|
|
Chris@16
|
472 boost::mpl::identity<abstract>,
|
|
Chris@16
|
473 boost::mpl::identity<non_abstract>
|
|
Chris@16
|
474 >::type typex;
|
|
Chris@16
|
475 return typex::template register_type< T >(ar);
|
|
Chris@16
|
476 }
|
|
Chris@16
|
477
|
|
Chris@16
|
478 template<class T>
|
|
Chris@16
|
479 static T * pointer_tweak(
|
|
Chris@16
|
480 const boost::serialization::extended_type_info & eti,
|
|
Chris@16
|
481 void const * const t,
|
|
Chris@16
|
482 const T &
|
|
Chris@16
|
483 ) {
|
|
Chris@16
|
484 // tweak the pointer back to the base class
|
|
Chris@16
|
485 return static_cast<T *>(
|
|
Chris@16
|
486 const_cast<void *>(
|
|
Chris@16
|
487 boost::serialization::void_upcast(
|
|
Chris@16
|
488 eti,
|
|
Chris@16
|
489 boost::serialization::singleton<
|
|
Chris@16
|
490 BOOST_DEDUCED_TYPENAME
|
|
Chris@16
|
491 boost::serialization::type_info_implementation< T >::type
|
|
Chris@16
|
492 >::get_const_instance(),
|
|
Chris@16
|
493 t
|
|
Chris@16
|
494 )
|
|
Chris@16
|
495 )
|
|
Chris@16
|
496 );
|
|
Chris@16
|
497 }
|
|
Chris@16
|
498
|
|
Chris@16
|
499 template<class T>
|
|
Chris@16
|
500 static void check_load(T & /* t */){
|
|
Chris@16
|
501 check_pointer_level< T >();
|
|
Chris@16
|
502 check_pointer_tracking< T >();
|
|
Chris@16
|
503 }
|
|
Chris@16
|
504
|
|
Chris@16
|
505 static const basic_pointer_iserializer *
|
|
Chris@16
|
506 find(const boost::serialization::extended_type_info & type){
|
|
Chris@16
|
507 return static_cast<const basic_pointer_iserializer *>(
|
|
Chris@16
|
508 archive_serializer_map<Archive>::find(type)
|
|
Chris@16
|
509 );
|
|
Chris@16
|
510 }
|
|
Chris@16
|
511
|
|
Chris@16
|
512 template<class Tptr>
|
|
Chris@16
|
513 static void invoke(Archive & ar, Tptr & t){
|
|
Chris@16
|
514 check_load(*t);
|
|
Chris@16
|
515 const basic_pointer_iserializer * bpis_ptr = register_type(ar, *t);
|
|
Chris@16
|
516 const basic_pointer_iserializer * newbpis_ptr = ar.load_pointer(
|
|
Chris@16
|
517 // note major hack here !!!
|
|
Chris@16
|
518 // I tried every way to convert Tptr &t (where Tptr might
|
|
Chris@16
|
519 // include const) to void * &. This is the only way
|
|
Chris@16
|
520 // I could make it work. RR
|
|
Chris@16
|
521 (void * & )t,
|
|
Chris@16
|
522 bpis_ptr,
|
|
Chris@16
|
523 find
|
|
Chris@16
|
524 );
|
|
Chris@16
|
525 // if the pointer isn't that of the base class
|
|
Chris@16
|
526 if(newbpis_ptr != bpis_ptr){
|
|
Chris@16
|
527 t = pointer_tweak(newbpis_ptr->get_eti(), t, *t);
|
|
Chris@16
|
528 }
|
|
Chris@16
|
529 }
|
|
Chris@16
|
530 };
|
|
Chris@16
|
531
|
|
Chris@16
|
532 template<class Archive>
|
|
Chris@16
|
533 struct load_enum_type {
|
|
Chris@16
|
534 template<class T>
|
|
Chris@16
|
535 static void invoke(Archive &ar, T &t){
|
|
Chris@16
|
536 // convert integers to correct enum to load
|
|
Chris@16
|
537 int i;
|
|
Chris@16
|
538 ar >> boost::serialization::make_nvp(NULL, i);
|
|
Chris@16
|
539 t = static_cast< T >(i);
|
|
Chris@16
|
540 }
|
|
Chris@16
|
541 };
|
|
Chris@16
|
542
|
|
Chris@16
|
543 template<class Archive>
|
|
Chris@16
|
544 struct load_array_type {
|
|
Chris@16
|
545 template<class T>
|
|
Chris@16
|
546 static void invoke(Archive &ar, T &t){
|
|
Chris@16
|
547 typedef BOOST_DEDUCED_TYPENAME remove_extent< T >::type value_type;
|
|
Chris@16
|
548
|
|
Chris@16
|
549 // convert integers to correct enum to load
|
|
Chris@16
|
550 // determine number of elements in the array. Consider the
|
|
Chris@16
|
551 // fact that some machines will align elements on boundries
|
|
Chris@16
|
552 // other than characters.
|
|
Chris@16
|
553 std::size_t current_count = sizeof(t) / (
|
|
Chris@16
|
554 static_cast<char *>(static_cast<void *>(&t[1]))
|
|
Chris@16
|
555 - static_cast<char *>(static_cast<void *>(&t[0]))
|
|
Chris@16
|
556 );
|
|
Chris@16
|
557 boost::serialization::collection_size_type count;
|
|
Chris@16
|
558 ar >> BOOST_SERIALIZATION_NVP(count);
|
|
Chris@16
|
559 if(static_cast<std::size_t>(count) > current_count)
|
|
Chris@16
|
560 boost::serialization::throw_exception(
|
|
Chris@16
|
561 archive::archive_exception(
|
|
Chris@16
|
562 boost::archive::archive_exception::array_size_too_short
|
|
Chris@16
|
563 )
|
|
Chris@16
|
564 );
|
|
Chris@16
|
565 ar >> serialization::make_array(static_cast<value_type*>(&t[0]),count);
|
|
Chris@16
|
566 }
|
|
Chris@16
|
567 };
|
|
Chris@16
|
568
|
|
Chris@16
|
569 } // detail
|
|
Chris@16
|
570
|
|
Chris@16
|
571 template<class Archive, class T>
|
|
Chris@16
|
572 inline void load(Archive & ar, T &t){
|
|
Chris@16
|
573 // if this assertion trips. It means we're trying to load a
|
|
Chris@16
|
574 // const object with a compiler that doesn't have correct
|
|
Chris@16
|
575 // funtion template ordering. On other compilers, this is
|
|
Chris@16
|
576 // handled below.
|
|
Chris@16
|
577 detail::check_const_loading< T >();
|
|
Chris@16
|
578 typedef
|
|
Chris@16
|
579 BOOST_DEDUCED_TYPENAME mpl::eval_if<is_pointer< T >,
|
|
Chris@16
|
580 mpl::identity<detail::load_pointer_type<Archive> >
|
|
Chris@16
|
581 ,//else
|
|
Chris@16
|
582 BOOST_DEDUCED_TYPENAME mpl::eval_if<is_array< T >,
|
|
Chris@16
|
583 mpl::identity<detail::load_array_type<Archive> >
|
|
Chris@16
|
584 ,//else
|
|
Chris@16
|
585 BOOST_DEDUCED_TYPENAME mpl::eval_if<is_enum< T >,
|
|
Chris@16
|
586 mpl::identity<detail::load_enum_type<Archive> >
|
|
Chris@16
|
587 ,//else
|
|
Chris@16
|
588 mpl::identity<detail::load_non_pointer_type<Archive> >
|
|
Chris@16
|
589 >
|
|
Chris@16
|
590 >
|
|
Chris@16
|
591 >::type typex;
|
|
Chris@16
|
592 typex::invoke(ar, t);
|
|
Chris@16
|
593 }
|
|
Chris@16
|
594
|
|
Chris@16
|
595 #if 0
|
|
Chris@16
|
596
|
|
Chris@16
|
597 // BORLAND
|
|
Chris@16
|
598 #if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x560))
|
|
Chris@16
|
599 // borland has a couple of problems
|
|
Chris@16
|
600 // a) if function is partially specialized - see below
|
|
Chris@16
|
601 // const paramters are transformed to non-const ones
|
|
Chris@16
|
602 // b) implementation of base_object can't be made to work
|
|
Chris@16
|
603 // correctly which results in all base_object s being const.
|
|
Chris@16
|
604 // So, strip off the const for borland. This breaks the trap
|
|
Chris@16
|
605 // for loading const objects - but I see no alternative
|
|
Chris@16
|
606 template<class Archive, class T>
|
|
Chris@16
|
607 inline void load(Archive &ar, const T & t){
|
|
Chris@16
|
608 load(ar, const_cast<T &>(t));
|
|
Chris@16
|
609 }
|
|
Chris@16
|
610 #endif
|
|
Chris@16
|
611
|
|
Chris@16
|
612 // let wrappers through.
|
|
Chris@16
|
613 #ifndef BOOST_NO_FUNCTION_TEMPLATE_ORDERING
|
|
Chris@16
|
614 template<class Archive, class T>
|
|
Chris@16
|
615 inline void load_wrapper(Archive &ar, const T&t, mpl::true_){
|
|
Chris@16
|
616 boost::archive::load(ar, const_cast<T&>(t));
|
|
Chris@16
|
617 }
|
|
Chris@16
|
618
|
|
Chris@16
|
619 #if !BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x560))
|
|
Chris@16
|
620 template<class Archive, class T>
|
|
Chris@16
|
621 inline void load(Archive &ar, const T&t){
|
|
Chris@16
|
622 load_wrapper(ar,t,serialization::is_wrapper< T >());
|
|
Chris@16
|
623 }
|
|
Chris@16
|
624 #endif
|
|
Chris@16
|
625 #endif
|
|
Chris@16
|
626
|
|
Chris@16
|
627 #endif
|
|
Chris@16
|
628
|
|
Chris@16
|
629 } // namespace archive
|
|
Chris@16
|
630 } // namespace boost
|
|
Chris@16
|
631
|
|
Chris@16
|
632 #endif // BOOST_ARCHIVE_DETAIL_ISERIALIZER_HPP
|