serialize_container.hpp 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. /* Copyright 2023 Joaquin M Lopez Munoz.
  2. * Distributed under the Boost Software License, Version 1.0.
  3. * (See accompanying file LICENSE_1_0.txt or copy at
  4. * http://www.boost.org/LICENSE_1_0.txt)
  5. *
  6. * See https://www.boost.org/libs/unordered for library home page.
  7. */
  8. #ifndef BOOST_UNORDERED_DETAIL_SERIALIZE_CONTAINER_HPP
  9. #define BOOST_UNORDERED_DETAIL_SERIALIZE_CONTAINER_HPP
  10. #include <boost/core/serialization.hpp>
  11. #include <boost/throw_exception.hpp>
  12. #include <boost/unordered/detail/archive_constructed.hpp>
  13. #include <boost/unordered/detail/bad_archive_exception.hpp>
  14. #include <boost/unordered/detail/serialization_version.hpp>
  15. #include <cstddef>
  16. namespace boost{
  17. namespace unordered{
  18. namespace detail{
  19. /* serialize_container(ar,x,v) serializes any of the unordered associative
  20. * containers in Boost.Unordered. Iterator serialization is also supported
  21. * through the following protocol:
  22. * - At saving time, for each iterator it in [x.begin(),x.end()),
  23. * serialization_track(ar,it) is ADL-called to instruct the archive to
  24. * track the positions internally pointed to by the iterator via
  25. * track_address().
  26. * - At loading time, these addresses are mapped to those of the equivalent
  27. * reconstructed positions using again serialization_track(ar,it).
  28. * - Serializing an iterator reduces to serializing pointers to previously
  29. * tracked addresses via serialize_address().
  30. */
  31. template<typename Iterator>
  32. std::pair<Iterator,bool> adapt_insert_return_type(Iterator it)
  33. {
  34. return std::pair<Iterator,bool>(it,true);
  35. }
  36. template<typename Iterator>
  37. std::pair<Iterator,bool> adapt_insert_return_type(std::pair<Iterator,bool> p)
  38. {
  39. return p;
  40. }
  41. template<typename Set,bool IsSaving> struct load_or_save_unordered_set;
  42. template<typename Set> struct load_or_save_unordered_set<Set,true> /* save */
  43. {
  44. template<typename Archive>
  45. void operator()(Archive& ar,const Set& x,unsigned int)const
  46. {
  47. typedef typename Set::value_type value_type;
  48. typedef typename Set::const_iterator const_iterator;
  49. const std::size_t s=x.size();
  50. const serialization_version<value_type> value_version;
  51. ar<<core::make_nvp("count",s);
  52. ar<<core::make_nvp("value_version",value_version);
  53. for(const_iterator first=x.begin(),last=x.end();first!=last;++first){
  54. core::save_construct_data_adl(ar,std::addressof(*first),value_version);
  55. ar<<core::make_nvp("item",*first);
  56. serialization_track(ar,first);
  57. }
  58. }
  59. };
  60. template<typename Set> struct load_or_save_unordered_set<Set,false> /* load */
  61. {
  62. template<typename Archive>
  63. void operator()(Archive& ar,Set& x,unsigned int)const
  64. {
  65. typedef typename Set::value_type value_type;
  66. typedef typename Set::iterator iterator;
  67. std::size_t s;
  68. serialization_version<value_type> value_version;
  69. ar>>core::make_nvp("count",s);
  70. ar>>core::make_nvp("value_version",value_version);
  71. x.clear();
  72. x.reserve(s); /* critical so that iterator tracking is stable */
  73. for(std::size_t n=0;n<s;++n){
  74. archive_constructed<value_type> value("item",ar,value_version);
  75. std::pair<iterator,bool> p=adapt_insert_return_type(
  76. x.insert(std::move(value.get())));
  77. if(!p.second)throw_exception(bad_archive_exception());
  78. ar.reset_object_address(
  79. std::addressof(*p.first),std::addressof(value.get()));
  80. serialization_track(ar,p.first);
  81. }
  82. }
  83. };
  84. template<typename Map,bool IsSaving> struct load_or_save_unordered_map;
  85. template<typename Map> struct load_or_save_unordered_map<Map,true> /* save */
  86. {
  87. template<typename Archive>
  88. void operator()(Archive& ar,const Map& x,unsigned int)const
  89. {
  90. typedef typename std::remove_const<
  91. typename Map::key_type>::type key_type;
  92. typedef typename std::remove_const<
  93. typename Map::mapped_type>::type mapped_type;
  94. typedef typename Map::const_iterator const_iterator;
  95. const std::size_t s=x.size();
  96. const serialization_version<key_type> key_version;
  97. const serialization_version<mapped_type> mapped_version;
  98. ar<<core::make_nvp("count",s);
  99. ar<<core::make_nvp("key_version",key_version);
  100. ar<<core::make_nvp("mapped_version",mapped_version);
  101. for(const_iterator first=x.begin(),last=x.end();first!=last;++first){
  102. /* To remain lib-independent from Boost.Serialization and not rely on
  103. * the user having included the serialization code for std::pair
  104. * (boost/serialization/utility.hpp), we serialize the key and the
  105. * mapped value separately.
  106. */
  107. core::save_construct_data_adl(
  108. ar,std::addressof(first->first),key_version);
  109. ar<<core::make_nvp("key",first->first);
  110. core::save_construct_data_adl(
  111. ar,std::addressof(first->second),mapped_version);
  112. ar<<core::make_nvp("mapped",first->second);
  113. serialization_track(ar,first);
  114. }
  115. }
  116. };
  117. template<typename Map> struct load_or_save_unordered_map<Map,false> /* load */
  118. {
  119. template<typename Archive>
  120. void operator()(Archive& ar,Map& x,unsigned int)const
  121. {
  122. typedef typename std::remove_const<
  123. typename Map::key_type>::type key_type;
  124. typedef typename std::remove_const<
  125. typename Map::mapped_type>::type mapped_type;
  126. typedef typename Map::iterator iterator;
  127. std::size_t s;
  128. serialization_version<key_type> key_version;
  129. serialization_version<mapped_type> mapped_version;
  130. ar>>core::make_nvp("count",s);
  131. ar>>core::make_nvp("key_version",key_version);
  132. ar>>core::make_nvp("mapped_version",mapped_version);
  133. x.clear();
  134. x.reserve(s); /* critical so that iterator tracking is stable */
  135. for(std::size_t n=0;n<s;++n){
  136. archive_constructed<key_type> key("key",ar,key_version);
  137. archive_constructed<mapped_type> mapped("mapped",ar,mapped_version);
  138. std::pair<iterator,bool> p=adapt_insert_return_type(
  139. x.emplace(std::move(key.get()),std::move(mapped.get())));
  140. if(!p.second)throw_exception(bad_archive_exception());
  141. ar.reset_object_address(
  142. std::addressof(p.first->first),std::addressof(key.get()));
  143. ar.reset_object_address(
  144. std::addressof(p.first->second),std::addressof(mapped.get()));
  145. serialization_track(ar,p.first);
  146. }
  147. }
  148. };
  149. template<typename Container,bool IsSet,bool IsSaving>
  150. struct load_or_save_container;
  151. template<typename Set,bool IsSaving>
  152. struct load_or_save_container<Set,true,IsSaving>:
  153. load_or_save_unordered_set<Set,IsSaving>{};
  154. template<typename Map,bool IsSaving>
  155. struct load_or_save_container<Map,false,IsSaving>:
  156. load_or_save_unordered_map<Map,IsSaving>{};
  157. template<typename Archive,typename Container>
  158. void serialize_container(Archive& ar,Container& x,unsigned int version)
  159. {
  160. load_or_save_container<
  161. Container,
  162. std::is_same<
  163. typename Container::key_type,typename Container::value_type>::value,
  164. Archive::is_saving::value>()(ar,x,version);
  165. }
  166. } /* namespace detail */
  167. } /* namespace unordered */
  168. } /* namespace boost */
  169. #endif