oserializer.hpp 17 KB

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