oserializer.hpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545
  1. #ifndef BOOST_ARCHIVE_OSERIALIZER_HPP
  2. #define BOOST_ARCHIVE_OSERIALIZER_HPP
  3. // MS compatible compilers support #pragma once
  4. #if defined(_MSC_VER)
  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. // oserializer.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 <boost/assert.hpp>
  20. #include <cstddef> // NULL
  21. #include <boost/config.hpp>
  22. #include <boost/static_assert.hpp>
  23. #include <boost/detail/workaround.hpp>
  24. #include <boost/mpl/eval_if.hpp>
  25. #include <boost/mpl/equal_to.hpp>
  26. #include <boost/mpl/greater_equal.hpp>
  27. #include <boost/mpl/identity.hpp>
  28. #include <boost/mpl/bool_fwd.hpp>
  29. #ifndef BOOST_SERIALIZATION_DEFAULT_TYPE_INFO
  30. #include <boost/serialization/extended_type_info_typeid.hpp>
  31. #endif
  32. #include <boost/serialization/throw_exception.hpp>
  33. #include <boost/serialization/smart_cast.hpp>
  34. #include <boost/serialization/assume_abstract.hpp>
  35. #include <boost/serialization/static_warning.hpp>
  36. #include <boost/type_traits/is_pointer.hpp>
  37. #include <boost/type_traits/is_enum.hpp>
  38. #include <boost/type_traits/is_const.hpp>
  39. #include <boost/type_traits/is_polymorphic.hpp>
  40. #include <boost/type_traits/remove_extent.hpp>
  41. #include <boost/serialization/serialization.hpp>
  42. #include <boost/serialization/version.hpp>
  43. #include <boost/serialization/level.hpp>
  44. #include <boost/serialization/tracking.hpp>
  45. #include <boost/serialization/type_info_implementation.hpp>
  46. #include <boost/serialization/nvp.hpp>
  47. #include <boost/serialization/void_cast.hpp>
  48. #include <boost/serialization/collection_size_type.hpp>
  49. #include <boost/serialization/array_wrapper.hpp>
  50. #include <boost/serialization/singleton.hpp>
  51. #include <boost/archive/archive_exception.hpp>
  52. #include <boost/archive/detail/basic_oarchive.hpp>
  53. #include <boost/archive/detail/basic_oserializer.hpp>
  54. #include <boost/archive/detail/basic_pointer_oserializer.hpp>
  55. #include <boost/archive/detail/archive_serializer_map.hpp>
  56. #include <boost/archive/detail/check.hpp>
  57. #include <boost/core/addressof.hpp>
  58. namespace boost {
  59. namespace serialization {
  60. class extended_type_info;
  61. } // namespace serialization
  62. namespace archive {
  63. // an accessor to permit friend access to archives. Needed because
  64. // some compilers don't handle friend templates completely
  65. class save_access {
  66. public:
  67. template<class Archive>
  68. static void end_preamble(Archive & ar){
  69. ar.end_preamble();
  70. }
  71. template<class Archive, class T>
  72. static void save_primitive(Archive & ar, const T & t){
  73. ar.end_preamble();
  74. ar.save(t);
  75. }
  76. };
  77. namespace detail {
  78. #ifdef BOOST_MSVC
  79. # pragma warning(push)
  80. # pragma warning(disable : 4511 4512)
  81. #endif
  82. template<class Archive, class T>
  83. class oserializer : public basic_oserializer
  84. {
  85. private:
  86. // private constructor to inhibit any existence other than the
  87. // static one
  88. public:
  89. explicit BOOST_DLLEXPORT oserializer() :
  90. basic_oserializer(
  91. boost::serialization::singleton<
  92. typename
  93. boost::serialization::type_info_implementation< T >::type
  94. >::get_const_instance()
  95. )
  96. {}
  97. BOOST_DLLEXPORT void save_object_data(
  98. basic_oarchive & ar,
  99. const void *x
  100. ) const BOOST_OVERRIDE BOOST_USED;
  101. bool class_info() const BOOST_OVERRIDE {
  102. return boost::serialization::implementation_level< T >::value
  103. >= boost::serialization::object_class_info;
  104. }
  105. bool tracking(const unsigned int /* flags */) const BOOST_OVERRIDE {
  106. return boost::serialization::tracking_level< T >::value == boost::serialization::track_always
  107. || (boost::serialization::tracking_level< T >::value == boost::serialization::track_selectively
  108. && serialized_as_pointer());
  109. }
  110. version_type version() const BOOST_OVERRIDE {
  111. return version_type(::boost::serialization::version< T >::value);
  112. }
  113. bool is_polymorphic() const BOOST_OVERRIDE {
  114. return boost::is_polymorphic< T >::value;
  115. }
  116. ~oserializer() BOOST_OVERRIDE {}
  117. };
  118. #ifdef BOOST_MSVC
  119. # pragma warning(pop)
  120. #endif
  121. template<class Archive, class T>
  122. BOOST_DLLEXPORT void oserializer<Archive, T>::save_object_data(
  123. basic_oarchive & ar,
  124. const void *x
  125. ) const {
  126. // make sure call is routed through the highest interface that might
  127. // be specialized by the user.
  128. BOOST_STATIC_ASSERT(boost::is_const< T >::value == false);
  129. boost::serialization::serialize_adl(
  130. boost::serialization::smart_cast_reference<Archive &>(ar),
  131. * static_cast<T *>(const_cast<void *>(x)),
  132. version()
  133. );
  134. }
  135. #ifdef BOOST_MSVC
  136. # pragma warning(push)
  137. # pragma warning(disable : 4511 4512)
  138. #endif
  139. template<class Archive, class T>
  140. class pointer_oserializer :
  141. public basic_pointer_oserializer
  142. {
  143. private:
  144. const basic_oserializer &
  145. get_basic_serializer() const BOOST_OVERRIDE {
  146. return boost::serialization::singleton<
  147. oserializer<Archive, T>
  148. >::get_const_instance();
  149. }
  150. BOOST_DLLEXPORT void save_object_ptr(
  151. basic_oarchive & ar,
  152. const void * x
  153. ) const BOOST_OVERRIDE BOOST_USED;
  154. public:
  155. pointer_oserializer();
  156. ~pointer_oserializer() BOOST_OVERRIDE;
  157. };
  158. #ifdef BOOST_MSVC
  159. # pragma warning(pop)
  160. #endif
  161. template<class Archive, class T>
  162. BOOST_DLLEXPORT void pointer_oserializer<Archive, T>::save_object_ptr(
  163. basic_oarchive & ar,
  164. const void * x
  165. ) const {
  166. BOOST_ASSERT(NULL != x);
  167. // make sure call is routed through the highest interface that might
  168. // be specialized by the user.
  169. T * t = static_cast<T *>(const_cast<void *>(x));
  170. const unsigned int file_version = boost::serialization::version< T >::value;
  171. Archive & ar_impl
  172. = boost::serialization::smart_cast_reference<Archive &>(ar);
  173. boost::serialization::save_construct_data_adl<Archive, T>(
  174. ar_impl,
  175. t,
  176. file_version
  177. );
  178. ar_impl << boost::serialization::make_nvp(NULL, * t);
  179. }
  180. template<class Archive, class T>
  181. pointer_oserializer<Archive, T>::pointer_oserializer() :
  182. basic_pointer_oserializer(
  183. boost::serialization::singleton<
  184. typename
  185. boost::serialization::type_info_implementation< T >::type
  186. >::get_const_instance()
  187. )
  188. {
  189. // make sure appropriate member function is instantiated
  190. boost::serialization::singleton<
  191. oserializer<Archive, T>
  192. >::get_mutable_instance().set_bpos(this);
  193. archive_serializer_map<Archive>::insert(this);
  194. }
  195. template<class Archive, class T>
  196. pointer_oserializer<Archive, T>::~pointer_oserializer(){
  197. archive_serializer_map<Archive>::erase(this);
  198. }
  199. template<class Archive>
  200. struct save_non_pointer_type {
  201. // note this bounces the call right back to the archive
  202. // with no runtime overhead
  203. struct save_primitive {
  204. template<class T>
  205. static void invoke(Archive & ar, const T & t){
  206. save_access::save_primitive(ar, t);
  207. }
  208. };
  209. // same as above but passes through serialization
  210. struct save_only {
  211. template<class T>
  212. static void invoke(Archive & ar, const T & t){
  213. // make sure call is routed through the highest interface that might
  214. // be specialized by the user.
  215. boost::serialization::serialize_adl(
  216. ar,
  217. const_cast<T &>(t),
  218. ::boost::serialization::version< T >::value
  219. );
  220. }
  221. };
  222. // adds class information to the archive. This includes
  223. // serialization level and class version
  224. struct save_standard {
  225. template<class T>
  226. static void invoke(Archive &ar, const T & t){
  227. ar.save_object(
  228. boost::addressof(t),
  229. boost::serialization::singleton<
  230. oserializer<Archive, T>
  231. >::get_const_instance()
  232. );
  233. }
  234. };
  235. // adds class information to the archive. This includes
  236. // serialization level and class version
  237. struct save_conditional {
  238. template<class T>
  239. static void invoke(Archive &ar, const T &t){
  240. //if(0 == (ar.get_flags() & no_tracking))
  241. save_standard::invoke(ar, t);
  242. //else
  243. // save_only::invoke(ar, t);
  244. }
  245. };
  246. template<class T>
  247. static void invoke(Archive & ar, const T & t){
  248. typedef
  249. typename mpl::eval_if<
  250. // if its primitive
  251. mpl::equal_to<
  252. boost::serialization::implementation_level< T >,
  253. mpl::int_<boost::serialization::primitive_type>
  254. >,
  255. mpl::identity<save_primitive>,
  256. // else
  257. typename mpl::eval_if<
  258. // class info / version
  259. mpl::greater_equal<
  260. boost::serialization::implementation_level< T >,
  261. mpl::int_<boost::serialization::object_class_info>
  262. >,
  263. // do standard save
  264. mpl::identity<save_standard>,
  265. // else
  266. typename mpl::eval_if<
  267. // no tracking
  268. mpl::equal_to<
  269. boost::serialization::tracking_level< T >,
  270. mpl::int_<boost::serialization::track_never>
  271. >,
  272. // do a fast save
  273. mpl::identity<save_only>,
  274. // else
  275. // do a fast save only tracking is turned off
  276. mpl::identity<save_conditional>
  277. > > >::type typex;
  278. check_object_versioning< T >();
  279. typex::invoke(ar, t);
  280. }
  281. template<class T>
  282. static void invoke(Archive & ar, T & t){
  283. check_object_level< T >();
  284. check_object_tracking< T >();
  285. invoke(ar, const_cast<const T &>(t));
  286. }
  287. };
  288. template<class Archive>
  289. struct save_pointer_type {
  290. struct abstract
  291. {
  292. template<class T>
  293. static const basic_pointer_oserializer * register_type(Archive & /* ar */){
  294. // it has? to be polymorphic
  295. BOOST_STATIC_ASSERT(boost::is_polymorphic< T >::value);
  296. return NULL;
  297. }
  298. };
  299. struct non_abstract
  300. {
  301. template<class T>
  302. static const basic_pointer_oserializer * register_type(Archive & ar){
  303. return ar.register_type(static_cast<T *>(NULL));
  304. }
  305. };
  306. template<class T>
  307. static const basic_pointer_oserializer * register_type(Archive &ar, T* const /*t*/){
  308. // there should never be any need to save an abstract polymorphic
  309. // class pointer. Inhibiting code generation for this
  310. // permits abstract base classes to be used - note: exception
  311. // virtual serialize functions used for plug-ins
  312. typedef
  313. typename mpl::eval_if<
  314. boost::serialization::is_abstract< T >,
  315. mpl::identity<abstract>,
  316. mpl::identity<non_abstract>
  317. >::type typex;
  318. return typex::template register_type< T >(ar);
  319. }
  320. struct non_polymorphic
  321. {
  322. template<class T>
  323. static void save(
  324. Archive &ar,
  325. T & t
  326. ){
  327. const basic_pointer_oserializer & bpos =
  328. boost::serialization::singleton<
  329. pointer_oserializer<Archive, T>
  330. >::get_const_instance();
  331. // save the requested pointer type
  332. ar.save_pointer(& t, & bpos);
  333. }
  334. };
  335. struct polymorphic
  336. {
  337. template<class T>
  338. static void save(
  339. Archive &ar,
  340. T & t
  341. ){
  342. typename
  343. boost::serialization::type_info_implementation< T >::type const
  344. & i = boost::serialization::singleton<
  345. typename
  346. boost::serialization::type_info_implementation< T >::type
  347. >::get_const_instance();
  348. boost::serialization::extended_type_info const * const this_type = & i;
  349. // retrieve the true type of the object pointed to
  350. // if this assertion fails its an error in this library
  351. BOOST_ASSERT(NULL != this_type);
  352. const boost::serialization::extended_type_info * true_type =
  353. i.get_derived_extended_type_info(t);
  354. // note:if this exception is thrown, be sure that derived pointer
  355. // is either registered or exported.
  356. if(NULL == true_type){
  357. boost::serialization::throw_exception(
  358. archive_exception(
  359. archive_exception::unregistered_class,
  360. "derived class not registered or exported"
  361. )
  362. );
  363. }
  364. // if its not a pointer to a more derived type
  365. const void *vp = static_cast<const void *>(&t);
  366. if(*this_type == *true_type){
  367. const basic_pointer_oserializer * bpos = register_type(ar, &t);
  368. ar.save_pointer(vp, bpos);
  369. return;
  370. }
  371. // convert pointer to more derived type. if this is thrown
  372. // it means that the base/derived relationship hasn't be registered
  373. vp = serialization::void_downcast(
  374. *true_type,
  375. *this_type,
  376. static_cast<const void *>(&t)
  377. );
  378. if(NULL == vp){
  379. boost::serialization::throw_exception(
  380. archive_exception(
  381. archive_exception::unregistered_cast,
  382. true_type->get_debug_info(),
  383. this_type->get_debug_info()
  384. )
  385. );
  386. }
  387. // since true_type is valid, and this only gets made if the
  388. // pointer oserializer object has been created, this should never
  389. // fail
  390. const basic_pointer_oserializer * bpos
  391. = static_cast<const basic_pointer_oserializer *>(
  392. boost::serialization::singleton<
  393. archive_serializer_map<Archive>
  394. >::get_const_instance().find(*true_type)
  395. );
  396. BOOST_ASSERT(NULL != bpos);
  397. if(NULL == bpos)
  398. boost::serialization::throw_exception(
  399. archive_exception(
  400. archive_exception::unregistered_class,
  401. "derived class not registered or exported"
  402. )
  403. );
  404. ar.save_pointer(vp, bpos);
  405. }
  406. };
  407. template<class T>
  408. static void save(
  409. Archive & ar,
  410. const T & t
  411. ){
  412. check_pointer_level< T >();
  413. check_pointer_tracking< T >();
  414. typedef typename mpl::eval_if<
  415. is_polymorphic< T >,
  416. mpl::identity<polymorphic>,
  417. mpl::identity<non_polymorphic>
  418. >::type type;
  419. type::save(ar, const_cast<T &>(t));
  420. }
  421. template<class TPtr>
  422. static void invoke(Archive &ar, const TPtr t){
  423. register_type(ar, t);
  424. if(NULL == t){
  425. basic_oarchive & boa
  426. = boost::serialization::smart_cast_reference<basic_oarchive &>(ar);
  427. boa.save_null_pointer();
  428. save_access::end_preamble(ar);
  429. return;
  430. }
  431. save(ar, * t);
  432. }
  433. };
  434. template<class Archive>
  435. struct save_enum_type
  436. {
  437. template<class T>
  438. static void invoke(Archive &ar, const T &t){
  439. // convert enum to integers on save
  440. const int i = static_cast<int>(t);
  441. ar << boost::serialization::make_nvp(NULL, i);
  442. }
  443. };
  444. template<class Archive>
  445. struct save_array_type
  446. {
  447. template<class T>
  448. static void invoke(Archive &ar, const T &t){
  449. typedef typename boost::remove_extent< T >::type value_type;
  450. save_access::end_preamble(ar);
  451. // consider alignment
  452. std::size_t c = sizeof(t) / (
  453. static_cast<const char *>(static_cast<const void *>(&t[1]))
  454. - static_cast<const char *>(static_cast<const void *>(&t[0]))
  455. );
  456. boost::serialization::collection_size_type count(c);
  457. ar << BOOST_SERIALIZATION_NVP(count);
  458. // explict template arguments to pass intel C++ compiler
  459. ar << serialization::make_array<
  460. const value_type,
  461. boost::serialization::collection_size_type
  462. >(
  463. static_cast<const value_type *>(&t[0]),
  464. count
  465. );
  466. }
  467. };
  468. } // detail
  469. template<class Archive, class T>
  470. inline void save(Archive & ar, /*const*/ T &t){
  471. typedef
  472. typename mpl::eval_if<is_pointer< T >,
  473. mpl::identity<detail::save_pointer_type<Archive> >,
  474. //else
  475. typename mpl::eval_if<is_enum< T >,
  476. mpl::identity<detail::save_enum_type<Archive> >,
  477. //else
  478. typename mpl::eval_if<is_array< T >,
  479. mpl::identity<detail::save_array_type<Archive> >,
  480. //else
  481. mpl::identity<detail::save_non_pointer_type<Archive> >
  482. >
  483. >
  484. >::type typex;
  485. typex::invoke(ar, t);
  486. }
  487. } // namespace archive
  488. } // namespace boost
  489. #endif // BOOST_ARCHIVE_OSERIALIZER_HPP