Line data Source code
1 : /*! \file boost_variant.hpp
2 : \brief Support for boost::variant
3 : \ingroup OtherTypes */
4 : /*
5 : Copyright (c) 2014, Randolph Voorhies, Shane Grant
6 : All rights reserved.
7 :
8 : Redistribution and use in source and binary forms, with or without
9 : modification, are permitted provided that the following conditions are met:
10 : * Redistributions of source code must retain the above copyright
11 : notice, this list of conditions and the following disclaimer.
12 : * Redistributions in binary form must reproduce the above copyright
13 : notice, this list of conditions and the following disclaimer in the
14 : documentation and/or other materials provided with the distribution.
15 : * Neither the name of cereal nor the
16 : names of its contributors may be used to endorse or promote products
17 : derived from this software without specific prior written permission.
18 :
19 : THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20 : ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 : WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 : DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES OR SHANE GRANT BE LIABLE FOR ANY
23 : DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 : (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 : LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26 : ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 : (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 : SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 : */
30 : #ifndef CEREAL_TYPES_BOOST_VARIANT_HPP_
31 : #define CEREAL_TYPES_BOOST_VARIANT_HPP_
32 :
33 : //! @internal
34 : #if defined(_MSC_VER) && _MSC_VER < 1911
35 : #define CEREAL_CONSTEXPR_LAMBDA
36 : #else // MSVC 2017 or newer, all other compilers
37 : #define CEREAL_CONSTEXPR_LAMBDA constexpr
38 : #endif
39 :
40 : #include "cereal/cereal.hpp"
41 : #include <boost/variant/variant_fwd.hpp>
42 : #include <boost/variant/static_visitor.hpp>
43 :
44 : namespace cereal
45 12 : {
46 : namespace boost_variant_detail
47 : {
48 12 : //! @internal
49 : template <class Archive>
50 12 : struct variant_save_visitor : boost::static_visitor<>
51 12 : {
52 17 : variant_save_visitor(Archive & ar_) : ar(ar_) {}
53 :
54 1 : template<class T>
55 17 : void operator()(T const & value) const
56 1 : {
57 16 : ar( CEREAL_NVP_("data", value) );
58 17 : }
59 2 :
60 1 : Archive & ar;
61 1 : };
62 2 :
63 2 : //! @internal
64 1 : template <class Archive, class T>
65 1 : struct LoadAndConstructLoadWrapper
66 2 : {
67 2 : using ST = typename std::aligned_storage<sizeof(T), CEREAL_ALIGNOF(T)>::type;
68 1 :
69 1 : LoadAndConstructLoadWrapper() :
70 2 : construct( reinterpret_cast<T *>( &st ) )
71 2 : { }
72 1 :
73 1 : ~LoadAndConstructLoadWrapper()
74 2 : {
75 2 : if (construct.itsValid)
76 1 : {
77 1 : construct->~T();
78 2 : }
79 2 : }
80 1 :
81 1 : void CEREAL_SERIALIZE_FUNCTION_NAME( Archive & ar )
82 2 : {
83 2 : ::cereal::detail::Construct<T, Archive>::load_andor_construct( ar, construct );
84 1 : }
85 1 :
86 2 : ST st;
87 2 : ::cereal::construct<T> construct;
88 1 : };
89 1 :
90 2 : //! @internal
91 2 : template <class T> struct load_variant_wrapper;
92 1 :
93 1 : //! Avoid serializing variant void_ type
94 2 : /*! @internal */
95 2 : template <>
96 1 : struct load_variant_wrapper<boost::detail::variant::void_>
97 1 : {
98 2 : template <class Variant, class Archive>
99 2 : static void load_variant( Archive &, Variant & )
100 : { }
101 1 : };
102 1 :
103 1 : //! @internal
104 : template <class T>
105 1 : struct load_variant_wrapper
106 1 : {
107 1 : // default constructible
108 : template <class Archive, class Variant>
109 1 : static void load_variant_impl( Archive & ar, Variant & variant, std::true_type )
110 1 : {
111 1 : T value;
112 : ar( CEREAL_NVP_("data", value) );
113 1 : variant = std::move(value);
114 1 : }
115 1 :
116 : // not default constructible
117 1 : template<class Variant, class Archive>
118 1 : static void load_variant_impl(Archive & ar, Variant & variant, std::false_type )
119 1 : {
120 : LoadAndConstructLoadWrapper<Archive, T> loadWrapper;
121 1 :
122 1 : ar( CEREAL_NVP_("data", loadWrapper) );
123 0 : variant = std::move(*loadWrapper.construct.ptr());
124 : }
125 0 :
126 : //! @internal
127 : template<class Variant, class Archive>
128 : static void load_variant(Archive & ar, Variant & variant)
129 : {
130 : load_variant_impl( ar, variant, typename std::is_default_constructible<T>::type() );
131 24 : }
132 : };
133 28 : } // namespace boost_variant_detail
134 4 :
135 12 : //! Saving for boost::variant
136 13 : template <class Archive, typename ... VariantTypes> inline
137 13 : void CEREAL_SAVE_FUNCTION_NAME( Archive & ar, boost::variant<VariantTypes...> const & variant )
138 1 : {
139 1 : int32_t which = variant.which();
140 13 : ar( CEREAL_NVP_("which", which) );
141 25 : boost_variant_detail::variant_save_visitor<Archive> visitor(ar);
142 2 : variant.apply_visitor(visitor);
143 1 : }
144 2 :
145 1 : //! Loading for boost::variant
146 3 : template <class Archive, typename ... VariantTypes> inline
147 2 : void CEREAL_LOAD_FUNCTION_NAME( Archive & ar, boost::variant<VariantTypes...> & variant )
148 1 : {
149 4 : int32_t which;
150 : ar( CEREAL_NVP_("which", which) );
151 4 :
152 1 : using LoadFuncType = void(*)(Archive &, boost::variant<VariantTypes...> &);
153 5 : CEREAL_CONSTEXPR_LAMBDA LoadFuncType loadFuncArray[] = {&boost_variant_detail::load_variant_wrapper<VariantTypes>::load_variant...};
154 :
155 5 : if(which >= int32_t(sizeof(loadFuncArray)/sizeof(loadFuncArray[0])))
156 1 : throw Exception("Invalid 'which' selector when deserializing boost::variant");
157 2 :
158 2 : loadFuncArray[which](ar, variant);
159 1 : }
160 1 : } // namespace cereal
161 :
162 1 : #undef CEREAL_CONSTEXPR_LAMBDA
163 2 :
164 1 : #endif // CEREAL_TYPES_BOOST_VARIANT_HPP_
|