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