std_variant.hpp 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. #ifndef BOOST_SERIALIZATION_STD_VARIANT_HPP
  2. #define BOOST_SERIALIZATION_STD_VARIANT_HPP
  3. // MS compatible compilers support #pragma once
  4. #if defined(_MSC_VER)
  5. # pragma once
  6. #endif
  7. /////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
  8. // variant.hpp - non-intrusive serialization of variant types
  9. //
  10. // copyright (c) 2019 Samuel Debionne, ESRF
  11. //
  12. // Use, modification and distribution is subject to the Boost Software
  13. // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
  14. // http://www.boost.org/LICENSE_1_0.txt)
  15. //
  16. // See http://www.boost.org for updates, documentation, and revision history.
  17. //
  18. // Widely inspired form boost::variant serialization
  19. //
  20. #include <boost/serialization/throw_exception.hpp>
  21. #include <variant>
  22. #include <boost/archive/archive_exception.hpp>
  23. #include <boost/serialization/split_free.hpp>
  24. #include <boost/serialization/serialization.hpp>
  25. #include <boost/serialization/nvp.hpp>
  26. namespace boost {
  27. namespace serialization {
  28. template<class Archive>
  29. struct std_variant_save_visitor
  30. {
  31. std_variant_save_visitor(Archive& ar) :
  32. m_ar(ar)
  33. {}
  34. template<class T>
  35. void operator()(T const & value) const
  36. {
  37. m_ar << BOOST_SERIALIZATION_NVP(value);
  38. }
  39. private:
  40. Archive & m_ar;
  41. };
  42. template<class Archive>
  43. struct std_variant_load_visitor
  44. {
  45. std_variant_load_visitor(Archive& ar) :
  46. m_ar(ar)
  47. {}
  48. template<class T>
  49. void operator()(T & value) const
  50. {
  51. m_ar >> BOOST_SERIALIZATION_NVP(value);
  52. }
  53. private:
  54. Archive & m_ar;
  55. };
  56. template<class Archive, class ...Types>
  57. void save(
  58. Archive & ar,
  59. std::variant<Types...> const & v,
  60. unsigned int /*version*/
  61. ){
  62. const std::size_t which = v.index();
  63. ar << BOOST_SERIALIZATION_NVP(which);
  64. std_variant_save_visitor<Archive> visitor(ar);
  65. std::visit(visitor, v);
  66. }
  67. // Minimalist metaprogramming for handling parameter pack
  68. namespace mp {
  69. namespace detail {
  70. template <typename Seq>
  71. struct front_impl;
  72. template <template <typename...> class Seq, typename T, typename... Ts>
  73. struct front_impl<Seq<T, Ts...>> {
  74. using type = T;
  75. };
  76. template <typename Seq>
  77. struct pop_front_impl;
  78. template <template <typename...> class Seq, typename T, typename... Ts>
  79. struct pop_front_impl<Seq<T, Ts...>> {
  80. using type = Seq<Ts...>;
  81. };
  82. } //namespace detail
  83. template <typename... Ts>
  84. struct typelist {};
  85. template <typename Seq>
  86. using front = typename detail::front_impl<Seq>::type;
  87. template <typename Seq>
  88. using pop_front = typename detail::pop_front_impl<Seq>::type;
  89. } // namespace mp
  90. template<std::size_t N, class Seq>
  91. struct variant_impl
  92. {
  93. template<class Archive, class V>
  94. static void load (
  95. Archive & ar,
  96. std::size_t which,
  97. V & v,
  98. const unsigned int version
  99. ){
  100. if(which == 0){
  101. // note: A non-intrusive implementation (such as this one)
  102. // necessary has to copy the value. This wouldn't be necessary
  103. // with an implementation that de-serialized to the address of the
  104. // aligned storage included in the variant.
  105. using type = mp::front<Seq>;
  106. type value;
  107. ar >> BOOST_SERIALIZATION_NVP(value);
  108. v = std::move(value);
  109. type * new_address = & std::get<type>(v);
  110. ar.reset_object_address(new_address, & value);
  111. return;
  112. }
  113. //typedef typename mpl::pop_front<S>::type type;
  114. using types = mp::pop_front<Seq>;
  115. variant_impl<N - 1, types>::load(ar, which - 1, v, version);
  116. }
  117. };
  118. template<class Seq>
  119. struct variant_impl<0, Seq>
  120. {
  121. template<class Archive, class V>
  122. static void load (
  123. Archive & /*ar*/,
  124. std::size_t /*which*/,
  125. V & /*v*/,
  126. const unsigned int /*version*/
  127. ){}
  128. };
  129. template<class Archive, class... Types>
  130. void load(
  131. Archive & ar,
  132. std::variant<Types...>& v,
  133. const unsigned int version
  134. ){
  135. std::size_t which;
  136. ar >> BOOST_SERIALIZATION_NVP(which);
  137. if(which >= sizeof...(Types))
  138. // this might happen if a type was removed from the list of variant types
  139. boost::serialization::throw_exception(
  140. boost::archive::archive_exception(
  141. boost::archive::archive_exception::unsupported_version
  142. )
  143. );
  144. variant_impl<sizeof...(Types), mp::typelist<Types...>>::load(ar, which, v, version);
  145. }
  146. template<class Archive,class... Types>
  147. inline void serialize(
  148. Archive & ar,
  149. std::variant<Types...> & v,
  150. const unsigned int file_version
  151. ){
  152. split_free(ar,v,file_version);
  153. }
  154. // Specialization for std::monostate
  155. template<class Archive>
  156. void serialize(Archive &ar, std::monostate &, const unsigned int /*version*/)
  157. {}
  158. } // namespace serialization
  159. } // namespace boost
  160. //template<typename T0_, BOOST_VARIANT_ENUM_SHIFTED_PARAMS(typename T)>
  161. #include <boost/serialization/tracking.hpp>
  162. namespace boost {
  163. namespace serialization {
  164. template<class... Types>
  165. struct tracking_level<
  166. std::variant<Types...>
  167. >{
  168. typedef mpl::integral_c_tag tag;
  169. typedef mpl::int_< ::boost::serialization::track_always> type;
  170. BOOST_STATIC_CONSTANT(int, value = type::value);
  171. };
  172. } // namespace serialization
  173. } // namespace boost
  174. #endif //BOOST_SERIALIZATION_VARIANT_HPP