basic_oarchive.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470
  1. /////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
  2. // basic_oarchive.cpp:
  3. // (C) Copyright 2002 Robert Ramey - http://www.rrsd.com .
  4. // Use, modification and distribution is subject to the Boost Software
  5. // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
  6. // http://www.boost.org/LICENSE_1_0.txt)
  7. // See http://www.boost.org for updates, documentation, and revision history.
  8. #include <boost/config.hpp> // msvc 6.0 needs this for warning suppression
  9. #include <boost/assert.hpp>
  10. #include <set>
  11. #include <cstddef> // NULL
  12. #include <boost/limits.hpp>
  13. // including this here to work around an ICC in intel 7.0
  14. // normally this would be part of basic_oarchive.hpp below.
  15. #define BOOST_ARCHIVE_SOURCE
  16. // include this to prevent linker errors when the
  17. // same modules are marked export and import.
  18. #define BOOST_SERIALIZATION_SOURCE
  19. #include <boost/serialization/config.hpp>
  20. #include <boost/serialization/state_saver.hpp>
  21. #include <boost/serialization/throw_exception.hpp>
  22. #include <boost/serialization/extended_type_info.hpp>
  23. #include <boost/archive/detail/decl.hpp>
  24. #include <boost/archive/basic_archive.hpp>
  25. #include <boost/archive/detail/basic_oserializer.hpp>
  26. #include <boost/archive/detail/basic_pointer_oserializer.hpp>
  27. #include <boost/archive/detail/basic_oarchive.hpp>
  28. #include <boost/archive/archive_exception.hpp>
  29. #ifdef BOOST_MSVC
  30. # pragma warning(push)
  31. # pragma warning(disable : 4251 4231 4660 4275)
  32. #endif
  33. using namespace boost::serialization;
  34. namespace boost {
  35. namespace archive {
  36. namespace detail {
  37. class basic_oarchive_impl {
  38. friend class basic_oarchive;
  39. unsigned int m_flags;
  40. //////////////////////////////////////////////////////////////////////
  41. // information about each serialized object saved
  42. // keyed on address, class_id
  43. struct aobject
  44. {
  45. const void * address;
  46. class_id_type class_id;
  47. object_id_type object_id;
  48. bool operator<(const aobject &rhs) const
  49. {
  50. BOOST_ASSERT(NULL != address);
  51. BOOST_ASSERT(NULL != rhs.address);
  52. if( address < rhs.address )
  53. return true;
  54. if( address > rhs.address )
  55. return false;
  56. return class_id < rhs.class_id;
  57. }
  58. aobject & operator=(const aobject & rhs)
  59. {
  60. address = rhs.address;
  61. class_id = rhs.class_id;
  62. object_id = rhs.object_id;
  63. return *this;
  64. }
  65. aobject(
  66. const void *a,
  67. class_id_type class_id_,
  68. object_id_type object_id_
  69. ) :
  70. address(a),
  71. class_id(class_id_),
  72. object_id(object_id_)
  73. {}
  74. aobject() : address(NULL){}
  75. };
  76. // keyed on class_id, address
  77. typedef std::set<aobject> object_set_type;
  78. object_set_type object_set;
  79. //////////////////////////////////////////////////////////////////////
  80. // information about each serialized class saved
  81. // keyed on type_info
  82. struct cobject_type
  83. {
  84. const basic_oserializer * m_bos_ptr;
  85. const class_id_type m_class_id;
  86. bool m_initialized;
  87. cobject_type(
  88. std::size_t class_id,
  89. const basic_oserializer & bos
  90. ) :
  91. m_bos_ptr(& bos),
  92. m_class_id(class_id),
  93. m_initialized(false)
  94. {}
  95. cobject_type(const basic_oserializer & bos) :
  96. m_bos_ptr(& bos),
  97. m_initialized(false)
  98. {}
  99. cobject_type(
  100. const cobject_type & rhs
  101. ) :
  102. m_bos_ptr(rhs.m_bos_ptr),
  103. m_class_id(rhs.m_class_id),
  104. m_initialized(rhs.m_initialized)
  105. {}
  106. // the following cannot be defined because of the const
  107. // member. This will generate a link error if an attempt
  108. // is made to assign. This should never be necessary
  109. // use this only for lookup argument
  110. cobject_type & operator=(const cobject_type &rhs);
  111. bool operator<(const cobject_type &rhs) const {
  112. return *m_bos_ptr < *(rhs.m_bos_ptr);
  113. }
  114. };
  115. // keyed on type_info
  116. typedef std::set<cobject_type> cobject_info_set_type;
  117. cobject_info_set_type cobject_info_set;
  118. // list of objects initially stored as pointers - used to detect errors
  119. // keyed on object id
  120. std::set<object_id_type> stored_pointers;
  121. // address of the most recent object serialized as a poiner
  122. // whose data itself is now pending serialization
  123. const void * pending_object;
  124. const basic_oserializer * pending_bos;
  125. basic_oarchive_impl(unsigned int flags) :
  126. m_flags(flags),
  127. pending_object(NULL),
  128. pending_bos(NULL)
  129. {}
  130. const cobject_type &
  131. find(const basic_oserializer & bos);
  132. const basic_oserializer *
  133. find(const serialization::extended_type_info &ti) const;
  134. //public:
  135. const cobject_type &
  136. register_type(const basic_oserializer & bos);
  137. void save_object(
  138. basic_oarchive & ar,
  139. const void *t,
  140. const basic_oserializer & bos
  141. );
  142. void save_pointer(
  143. basic_oarchive & ar,
  144. const void * t,
  145. const basic_pointer_oserializer * bpos
  146. );
  147. };
  148. //////////////////////////////////////////////////////////////////////
  149. // basic_oarchive implementation functions
  150. // given a type_info - find its bos
  151. // return NULL if not found
  152. inline const basic_oserializer *
  153. basic_oarchive_impl::find(const serialization::extended_type_info & ti) const {
  154. #ifdef BOOST_MSVC
  155. # pragma warning(push)
  156. # pragma warning(disable : 4511 4512)
  157. #endif
  158. class bosarg :
  159. public basic_oserializer
  160. {
  161. bool class_info() const {
  162. BOOST_ASSERT(false);
  163. return false;
  164. }
  165. // returns true if objects should be tracked
  166. bool tracking(const unsigned int) const {
  167. BOOST_ASSERT(false);
  168. return false;
  169. }
  170. // returns class version
  171. version_type version() const {
  172. BOOST_ASSERT(false);
  173. return version_type(0);
  174. }
  175. // returns true if this class is polymorphic
  176. bool is_polymorphic() const{
  177. BOOST_ASSERT(false);
  178. return false;
  179. }
  180. void save_object_data(
  181. basic_oarchive & /*ar*/, const void * /*x*/
  182. ) const {
  183. BOOST_ASSERT(false);
  184. }
  185. public:
  186. bosarg(const serialization::extended_type_info & eti) :
  187. boost::archive::detail::basic_oserializer(eti)
  188. {}
  189. };
  190. #ifdef BOOST_MSVC
  191. #pragma warning(pop)
  192. #endif
  193. bosarg bos(ti);
  194. cobject_info_set_type::const_iterator cit
  195. = cobject_info_set.find(cobject_type(bos));
  196. // it should already have been "registered" - see below
  197. if(cit == cobject_info_set.end()){
  198. // if an entry is not found in the table it is because a pointer
  199. // of a derived class has been serialized through its base class
  200. // but the derived class hasn't been "registered"
  201. return NULL;
  202. }
  203. // return pointer to the real class
  204. return cit->m_bos_ptr;
  205. }
  206. inline const basic_oarchive_impl::cobject_type &
  207. basic_oarchive_impl::find(const basic_oserializer & bos)
  208. {
  209. std::pair<cobject_info_set_type::iterator, bool> cresult =
  210. cobject_info_set.insert(cobject_type(cobject_info_set.size(), bos));
  211. return *(cresult.first);
  212. }
  213. inline const basic_oarchive_impl::cobject_type &
  214. basic_oarchive_impl::register_type(
  215. const basic_oserializer & bos
  216. ){
  217. cobject_type co(cobject_info_set.size(), bos);
  218. std::pair<cobject_info_set_type::const_iterator, bool>
  219. result = cobject_info_set.insert(co);
  220. return *(result.first);
  221. }
  222. inline void
  223. basic_oarchive_impl::save_object(
  224. basic_oarchive & ar,
  225. const void *t,
  226. const basic_oserializer & bos
  227. ){
  228. // if its been serialized through a pointer and the preamble's been done
  229. if(t == pending_object && pending_bos == & bos){
  230. // just save the object data
  231. ar.end_preamble();
  232. (bos.save_object_data)(ar, t);
  233. return;
  234. }
  235. // get class information for this object
  236. const cobject_type & co = register_type(bos);
  237. if(bos.class_info()){
  238. if( ! co.m_initialized){
  239. ar.vsave(class_id_optional_type(co.m_class_id));
  240. ar.vsave(tracking_type(bos.tracking(m_flags)));
  241. ar.vsave(version_type(bos.version()));
  242. (const_cast<cobject_type &>(co)).m_initialized = true;
  243. }
  244. }
  245. // we're not tracking this type of object
  246. if(! bos.tracking(m_flags)){
  247. // just windup the preamble - no object id to write
  248. ar.end_preamble();
  249. // and save the data
  250. (bos.save_object_data)(ar, t);
  251. return;
  252. }
  253. // look for an existing object id
  254. object_id_type oid(object_set.size());
  255. // lookup to see if this object has already been written to the archive
  256. basic_oarchive_impl::aobject ao(t, co.m_class_id, oid);
  257. std::pair<basic_oarchive_impl::object_set_type::const_iterator, bool>
  258. aresult = object_set.insert(ao);
  259. oid = aresult.first->object_id;
  260. // if its a new object
  261. if(aresult.second){
  262. // write out the object id
  263. ar.vsave(oid);
  264. ar.end_preamble();
  265. // and data
  266. (bos.save_object_data)(ar, t);
  267. return;
  268. }
  269. // check that it wasn't originally stored through a pointer
  270. if(stored_pointers.end() != stored_pointers.find(oid)){
  271. // this has to be a user error. loading such an archive
  272. // would create duplicate objects
  273. boost::serialization::throw_exception(
  274. archive_exception(archive_exception::pointer_conflict)
  275. );
  276. }
  277. // just save the object id
  278. ar.vsave(object_reference_type(oid));
  279. ar.end_preamble();
  280. return;
  281. }
  282. // save a pointer to an object instance
  283. inline void
  284. basic_oarchive_impl::save_pointer(
  285. basic_oarchive & ar,
  286. const void * t,
  287. const basic_pointer_oserializer * bpos_ptr
  288. ){
  289. const basic_oserializer & bos = bpos_ptr->get_basic_serializer();
  290. std::size_t original_count = cobject_info_set.size();
  291. const cobject_type & co = register_type(bos);
  292. if(! co.m_initialized){
  293. ar.vsave(co.m_class_id);
  294. // if its a previously unregistered class
  295. if((cobject_info_set.size() > original_count)){
  296. if(bos.is_polymorphic()){
  297. const serialization::extended_type_info *eti = & bos.get_eti();
  298. const char * key = NULL;
  299. if(NULL != eti)
  300. key = eti->get_key();
  301. if(NULL != key){
  302. // the following is required by IBM C++ compiler which
  303. // makes a copy when passing a non-const to a const. This
  304. // is permitted by the standard but rarely seen in practice
  305. const class_name_type cn(key);
  306. if(cn.size() > (BOOST_SERIALIZATION_MAX_KEY_SIZE - 1))
  307. boost::serialization::throw_exception(
  308. boost::archive::archive_exception(
  309. boost::archive::archive_exception::
  310. invalid_class_name)
  311. );
  312. // write out the external class identifier
  313. ar.vsave(cn);
  314. }
  315. else
  316. // without an external class name
  317. // we won't be able to de-serialize it so bail now
  318. boost::serialization::throw_exception(
  319. archive_exception(archive_exception::unregistered_class)
  320. );
  321. }
  322. }
  323. if(bos.class_info()){
  324. ar.vsave(tracking_type(bos.tracking(m_flags)));
  325. ar.vsave(version_type(bos.version()));
  326. }
  327. (const_cast<cobject_type &>(co)).m_initialized = true;
  328. }
  329. else{
  330. ar.vsave(class_id_reference_type(co.m_class_id));
  331. }
  332. // if we're not tracking
  333. if(! bos.tracking(m_flags)){
  334. // just save the data itself
  335. ar.end_preamble();
  336. serialization::state_saver<const void *> x(pending_object);
  337. serialization::state_saver<const basic_oserializer *> y(pending_bos);
  338. pending_object = t;
  339. pending_bos = & bpos_ptr->get_basic_serializer();
  340. bpos_ptr->save_object_ptr(ar, t);
  341. return;
  342. }
  343. object_id_type oid(object_set.size());
  344. // lookup to see if this object has already been written to the archive
  345. basic_oarchive_impl::aobject ao(t, co.m_class_id, oid);
  346. std::pair<basic_oarchive_impl::object_set_type::const_iterator, bool>
  347. aresult = object_set.insert(ao);
  348. oid = aresult.first->object_id;
  349. // if the saved object already exists
  350. if(! aresult.second){
  351. // append the object id to he preamble
  352. ar.vsave(object_reference_type(oid));
  353. // and windup.
  354. ar.end_preamble();
  355. return;
  356. }
  357. // append id of this object to preamble
  358. ar.vsave(oid);
  359. ar.end_preamble();
  360. // and save the object itself
  361. serialization::state_saver<const void *> x(pending_object);
  362. serialization::state_saver<const basic_oserializer *> y(pending_bos);
  363. pending_object = t;
  364. pending_bos = & bpos_ptr->get_basic_serializer();
  365. bpos_ptr->save_object_ptr(ar, t);
  366. // add to the set of object initially stored through pointers
  367. stored_pointers.insert(oid);
  368. }
  369. } // namespace detail
  370. } // namespace archive
  371. } // namespace boost
  372. //////////////////////////////////////////////////////////////////////
  373. // implementation of basic_oarchive functions
  374. namespace boost {
  375. namespace archive {
  376. namespace detail {
  377. BOOST_ARCHIVE_DECL
  378. basic_oarchive::basic_oarchive(unsigned int flags)
  379. : pimpl(new basic_oarchive_impl(flags))
  380. {}
  381. BOOST_ARCHIVE_DECL
  382. basic_oarchive::~basic_oarchive()
  383. {}
  384. BOOST_ARCHIVE_DECL void
  385. basic_oarchive::save_object(
  386. const void *x,
  387. const basic_oserializer & bos
  388. ){
  389. pimpl->save_object(*this, x, bos);
  390. }
  391. BOOST_ARCHIVE_DECL void
  392. basic_oarchive::save_pointer(
  393. const void * t,
  394. const basic_pointer_oserializer * bpos_ptr
  395. ){
  396. pimpl->save_pointer(*this, t, bpos_ptr);
  397. }
  398. BOOST_ARCHIVE_DECL void
  399. basic_oarchive::register_basic_serializer(const basic_oserializer & bos){
  400. pimpl->register_type(bos);
  401. }
  402. BOOST_ARCHIVE_DECL library_version_type
  403. basic_oarchive::get_library_version() const{
  404. return BOOST_ARCHIVE_VERSION();
  405. }
  406. BOOST_ARCHIVE_DECL unsigned int
  407. basic_oarchive::get_flags() const{
  408. return pimpl->m_flags;
  409. }
  410. BOOST_ARCHIVE_DECL void
  411. basic_oarchive::end_preamble(){
  412. }
  413. BOOST_ARCHIVE_DECL helper_collection &
  414. basic_oarchive::get_helper_collection(){
  415. return *this;
  416. }
  417. } // namespace detail
  418. } // namespace archive
  419. } // namespace boost
  420. #ifdef BOOST_MSVC
  421. #pragma warning(pop)
  422. #endif