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