variant.hpp 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317
  1. #ifndef BOOST_SERIALIZATION_VARIANT_HPP
  2. #define BOOST_SERIALIZATION_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) 2005
  11. // troy d. straszheim <troy@resophonic.com>
  12. // http://www.resophonic.com
  13. //
  14. // copyright (c) 2019 Samuel Debionne, ESRF
  15. //
  16. // copyright (c) 2023
  17. // Robert Ramey <ramey@rrsd.com>
  18. // http://www.rrsd.com
  19. //
  20. // Use, modification and distribution is subject to the Boost Software
  21. // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
  22. // http://www.boost.org/LICENSE_1_0.txt)
  23. //
  24. // See http://www.boost.org for updates, documentation, and revision history.
  25. //
  26. // thanks to Robert Ramey, Peter Dimov, and Richard Crossley.
  27. //
  28. #include <boost/mpl/front.hpp>
  29. #include <boost/mpl/pop_front.hpp>
  30. #include <boost/mpl/eval_if.hpp>
  31. #include <boost/mpl/identity.hpp>
  32. #include <boost/mpl/size.hpp>
  33. #include <boost/mpl/empty.hpp>
  34. #include <boost/serialization/throw_exception.hpp>
  35. // Boost Variant supports all C++ versions back to C++03
  36. #include <boost/variant/variant.hpp>
  37. #include <boost/variant/get.hpp>
  38. // Boost Variant2 supports all C++ versions back to C++11
  39. #if BOOST_CXX_VERSION >= 201103L
  40. #include <boost/variant2/variant.hpp>
  41. #include <type_traits>
  42. #endif
  43. // Boost Variant2 supports all C++ versions back to C++11
  44. #ifndef BOOST_NO_CXX17_HDR_VARIANT
  45. #include <variant>
  46. //#include <type_traits>
  47. #endif
  48. #include <boost/archive/archive_exception.hpp>
  49. #include <boost/serialization/split_free.hpp>
  50. #include <boost/serialization/serialization.hpp>
  51. #include <boost/serialization/nvp.hpp>
  52. // use visitor from boost::variant
  53. template<class Visitor, BOOST_VARIANT_ENUM_PARAMS(class T)>
  54. typename Visitor::result_type visit(
  55. Visitor visitor,
  56. const boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> & t
  57. ){
  58. return boost::apply_visitor(visitor, t);
  59. }
  60. template<class Visitor, BOOST_VARIANT_ENUM_PARAMS(class T)>
  61. typename Visitor::result_type visit(
  62. Visitor visitor,
  63. const boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> & t,
  64. const boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> & u
  65. ){
  66. return boost::apply_visitor(visitor, t, u);
  67. }
  68. namespace boost {
  69. namespace serialization {
  70. template<class Archive>
  71. struct variant_save_visitor :
  72. boost::static_visitor<void>
  73. {
  74. variant_save_visitor(Archive& ar) :
  75. m_ar(ar)
  76. {}
  77. template<class T>
  78. void operator()(T const & value) const {
  79. m_ar << BOOST_SERIALIZATION_NVP(value);
  80. }
  81. private:
  82. Archive & m_ar;
  83. };
  84. template<class Archive, BOOST_VARIANT_ENUM_PARAMS(/* typename */ class T)>
  85. void save(
  86. Archive & ar,
  87. boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const & v,
  88. unsigned int /*version*/
  89. ){
  90. int which = v.which();
  91. ar << BOOST_SERIALIZATION_NVP(which);
  92. variant_save_visitor<Archive> visitor(ar);
  93. visit(visitor, v);
  94. }
  95. #if BOOST_CXX_VERSION >= 201103L
  96. template<class Archive, class ...Types>
  97. void save(
  98. Archive & ar,
  99. boost::variant2::variant<Types...> const & v,
  100. unsigned int /*version*/
  101. ){
  102. int which = v.index();
  103. ar << BOOST_SERIALIZATION_NVP(which);
  104. const variant_save_visitor<Archive> visitor(ar);
  105. visit(visitor, v);
  106. }
  107. #endif
  108. #ifndef BOOST_NO_CXX17_HDR_VARIANT
  109. template<class Archive, class ...Types>
  110. void save(
  111. Archive & ar,
  112. std::variant<Types...> const & v,
  113. unsigned int /*version*/
  114. ){
  115. int which = v.index();
  116. ar << BOOST_SERIALIZATION_NVP(which);
  117. const variant_save_visitor<Archive> visitor(ar);
  118. visit(visitor, v);
  119. }
  120. #endif
  121. template<class S>
  122. struct variant_impl {
  123. struct load_null {
  124. template<class Archive, class V>
  125. static void invoke(
  126. Archive & /*ar*/,
  127. std::size_t /*which*/,
  128. V & /*v*/,
  129. const unsigned int /*version*/
  130. ){}
  131. };
  132. struct load_member {
  133. template<class Archive, class V>
  134. static void invoke(
  135. Archive & ar,
  136. std::size_t which,
  137. V & v,
  138. const unsigned int version
  139. ){
  140. if(which == 0){
  141. // note: A non-intrusive implementation (such as this one)
  142. // necessary has to copy the value. This wouldn't be necessary
  143. // with an implementation that de-serialized to the address of the
  144. // aligned storage included in the variant.
  145. typedef typename mpl::front<S>::type head_type;
  146. head_type value;
  147. ar >> BOOST_SERIALIZATION_NVP(value);
  148. v = std::move(value);;
  149. head_type * new_address = & get<head_type>(v);
  150. ar.reset_object_address(new_address, & value);
  151. return;
  152. }
  153. typedef typename mpl::pop_front<S>::type type;
  154. variant_impl<type>::load_impl(ar, which - 1, v, version);
  155. }
  156. };
  157. template<class Archive, class V>
  158. static void load_impl(
  159. Archive & ar,
  160. std::size_t which,
  161. V & v,
  162. const unsigned int version
  163. ){
  164. typedef typename mpl::eval_if<mpl::empty<S>,
  165. mpl::identity<load_null>,
  166. mpl::identity<load_member>
  167. >::type typex;
  168. typex::invoke(ar, which, v, version);
  169. }
  170. }; // variant_impl
  171. template<class Archive, BOOST_VARIANT_ENUM_PARAMS(/* typename */ class T)>
  172. void load(
  173. Archive & ar,
  174. boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>& v,
  175. const unsigned int version
  176. ){
  177. int which;
  178. typedef typename boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>::types types;
  179. ar >> BOOST_SERIALIZATION_NVP(which);
  180. if(which >= mpl::size<types>::value){
  181. // this might happen if a type was removed from the list of variant types
  182. boost::serialization::throw_exception(
  183. boost::archive::archive_exception(
  184. boost::archive::archive_exception::unsupported_version
  185. )
  186. );
  187. }
  188. variant_impl<types>::load_impl(ar, which, v, version);
  189. }
  190. #if BOOST_CXX_VERSION >= 201103L
  191. template<class Archive, class ... Types>
  192. void load(
  193. Archive & ar,
  194. boost::variant2::variant<Types...> & v,
  195. const unsigned int version
  196. ){
  197. int which;
  198. typedef typename boost::variant<Types...>::types types;
  199. ar >> BOOST_SERIALIZATION_NVP(which);
  200. if(which >= sizeof...(Types)){
  201. // this might happen if a type was removed from the list of variant types
  202. boost::serialization::throw_exception(
  203. boost::archive::archive_exception(
  204. boost::archive::archive_exception::unsupported_version
  205. )
  206. );
  207. }
  208. variant_impl<types>::load_impl(ar, which, v, version);
  209. }
  210. #endif
  211. #ifndef BOOST_NO_CXX17_HDR_VARIANT
  212. template<class Archive, class ... Types>
  213. void load(
  214. Archive & ar,
  215. std::variant<Types...> & v,
  216. const unsigned int version
  217. ){
  218. int which;
  219. typedef typename boost::variant<Types...>::types types;
  220. ar >> BOOST_SERIALIZATION_NVP(which);
  221. if(which >= sizeof...(Types)){
  222. // this might happen if a type was removed from the list of variant types
  223. boost::serialization::throw_exception(
  224. boost::archive::archive_exception(
  225. boost::archive::archive_exception::unsupported_version
  226. )
  227. );
  228. }
  229. variant_impl<types>::load_impl(ar, which, v, version);
  230. }
  231. #endif
  232. template<class Archive,BOOST_VARIANT_ENUM_PARAMS(/* typename */ class T)>
  233. inline void serialize(
  234. Archive & ar,
  235. boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> & v,
  236. const unsigned int file_version
  237. ){
  238. boost::serialization::split_free(ar,v,file_version);
  239. }
  240. #if BOOST_CXX_VERSION >= 201103L
  241. template<class Archive, class ... Types>
  242. inline void serialize(
  243. Archive & ar,
  244. boost::variant2::variant<Types...> & v,
  245. const unsigned int file_version
  246. ){
  247. boost::serialization::split_free(ar,v,file_version);
  248. }
  249. #endif
  250. #ifndef BOOST_NO_CXX17_HDR_VARIANT
  251. template<class Archive, class ... Types>
  252. inline void serialize(
  253. Archive & ar,
  254. std::variant<Types...> & v,
  255. const unsigned int file_version
  256. ){
  257. boost::serialization::split_free(ar,v,file_version);
  258. }
  259. #endif
  260. } // namespace serialization
  261. } // namespace boost
  262. #include <boost/serialization/tracking.hpp>
  263. namespace boost {
  264. namespace serialization {
  265. template<BOOST_VARIANT_ENUM_PARAMS(/* typename */ class T)>
  266. struct tracking_level<
  267. variant<BOOST_VARIANT_ENUM_PARAMS(T)>
  268. >{
  269. typedef mpl::integral_c_tag tag;
  270. typedef mpl::int_< ::boost::serialization::track_always> type;
  271. BOOST_STATIC_CONSTANT(int, value = type::value);
  272. };
  273. #ifndef BOOST_NO_CXX17_HDR_VARIANT
  274. template<class... Types>
  275. struct tracking_level<
  276. std::variant<Types...>
  277. >{
  278. typedef mpl::integral_c_tag tag;
  279. typedef mpl::int_< ::boost::serialization::track_always> type;
  280. BOOST_STATIC_CONSTANT(int, value = type::value);
  281. };
  282. #endif
  283. } // namespace serialization
  284. } // namespace boost
  285. #endif //BOOST_SERIALIZATION_VARIANT_HPP