iserializer.hpp 20 KB

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