iserializer.hpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624
  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)
  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 <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. #ifndef BOOST_MSVC
  48. #define DONT_USE_HAS_NEW_OPERATOR ( \
  49. BOOST_WORKAROUND(__IBMCPP__, < 1210) \
  50. || defined(__SUNPRO_CC) && (__SUNPRO_CC < 0x590) \
  51. )
  52. #else
  53. #define DONT_USE_HAS_NEW_OPERATOR 0
  54. #endif
  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. 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. // 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 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. 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. 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. virtual void * heap_allocation() const {
  264. detail::heap_allocation<T> h;
  265. T * t = h.get();
  266. h.release();
  267. return t;
  268. }
  269. virtual const basic_iserializer & get_basic_serializer() const {
  270. return boost::serialization::singleton<
  271. iserializer<Archive, T>
  272. >::get_const_instance();
  273. }
  274. BOOST_DLLEXPORT virtual void load_object_ptr(
  275. basic_iarchive & ar,
  276. void * x,
  277. const unsigned int file_version
  278. ) const BOOST_USED;
  279. protected:
  280. // this should alway be a singleton so make the constructor protected
  281. pointer_iserializer();
  282. ~pointer_iserializer();
  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 higest 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 = & 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 & /*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 & /* 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 boundries
  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. ar >> serialization::make_array(static_cast<value_type*>(&t[0]),count);
  541. }
  542. };
  543. } // detail
  544. template<class Archive, class T>
  545. inline void load(Archive & ar, T &t){
  546. // if this assertion trips. It means we're trying to load a
  547. // const object with a compiler that doesn't have correct
  548. // funtion template ordering. On other compilers, this is
  549. // handled below.
  550. detail::check_const_loading< T >();
  551. typedef
  552. typename mpl::eval_if<is_pointer< T >,
  553. mpl::identity<detail::load_pointer_type<Archive> >
  554. ,//else
  555. typename mpl::eval_if<is_array< T >,
  556. mpl::identity<detail::load_array_type<Archive> >
  557. ,//else
  558. typename mpl::eval_if<is_enum< T >,
  559. mpl::identity<detail::load_enum_type<Archive> >
  560. ,//else
  561. mpl::identity<detail::load_non_pointer_type<Archive> >
  562. >
  563. >
  564. >::type typex;
  565. typex::invoke(ar, t);
  566. }
  567. } // namespace archive
  568. } // namespace boost
  569. #endif // BOOST_ARCHIVE_DETAIL_ISERIALIZER_HPP