oserializer.hpp 17 KB

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