oserializer.hpp 17 KB

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