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