iserializer.hpp 21 KB

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