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 the copyright holder 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 THE COPYRIGHT HOLDER OR CONTRIBUTORS 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 : {
46 : namespace boost_variant_detail
47 : {
48 : //! @internal
49 : template <class Archive>
50 : struct variant_save_visitor : boost::static_visitor<>
51 : {
52 16 : variant_save_visitor(Archive & ar_) : ar(ar_) {}
53 :
54 : template<class T>
55 16 : void operator()(T const & value) const
56 : {
57 16 : ar( CEREAL_NVP_("data", value) );
58 16 : }
59 :
60 : Archive & ar;
61 : };
62 :
63 : //! @internal
64 : template <class Archive, class T>
65 : struct LoadAndConstructLoadWrapper
66 : {
67 : using ST = typename std::aligned_storage<sizeof(T), CEREAL_ALIGNOF(T)>::type;
68 :
69 4 : LoadAndConstructLoadWrapper() :
70 4 : construct( reinterpret_cast<T *>( &st ) )
71 4 : { }
72 :
73 4 : ~LoadAndConstructLoadWrapper()
74 : {
75 4 : if (construct.itsValid)
76 : {
77 4 : construct->~T();
78 : }
79 4 : }
80 :
81 4 : void CEREAL_SERIALIZE_FUNCTION_NAME( Archive & ar )
82 : {
83 4 : ::cereal::detail::Construct<T, Archive>::load_andor_construct( ar, construct );
84 4 : }
85 :
86 : ST st;
87 : ::cereal::construct<T> construct;
88 : };
89 :
90 : //! @internal
91 : template <class T> struct load_variant_wrapper;
92 :
93 : //! Avoid serializing variant void_ type
94 : /*! @internal */
95 : template <>
96 : struct load_variant_wrapper<boost::detail::variant::void_>
97 : {
98 : template <class Variant, class Archive>
99 : static void load_variant( Archive &, Variant & )
100 : { }
101 : };
102 :
103 : //! @internal
104 : template <class T>
105 : struct load_variant_wrapper
106 : {
107 : // default constructible
108 : template <class Archive, class Variant>
109 12 : static void load_variant_impl( Archive & ar, Variant & variant, std::true_type )
110 : {
111 8 : T value;
112 12 : ar( CEREAL_NVP_("data", value) );
113 12 : variant = std::move(value);
114 12 : }
115 :
116 : // not default constructible
117 : template<class Variant, class Archive>
118 4 : static void load_variant_impl(Archive & ar, Variant & variant, std::false_type )
119 : {
120 8 : LoadAndConstructLoadWrapper<Archive, T> loadWrapper;
121 :
122 4 : ar( CEREAL_NVP_("data", loadWrapper) );
123 4 : variant = std::move(*loadWrapper.construct.ptr());
124 4 : }
125 :
126 : //! @internal
127 : template<class Variant, class Archive>
128 16 : static void load_variant(Archive & ar, Variant & variant)
129 : {
130 16 : load_variant_impl( ar, variant, typename std::is_default_constructible<T>::type() );
131 16 : }
132 : };
133 : } // namespace boost_variant_detail
134 :
135 : //! Saving for boost::variant
136 : template <class Archive, typename ... VariantTypes> inline
137 16 : void CEREAL_SAVE_FUNCTION_NAME( Archive & ar, boost::variant<VariantTypes...> const & variant )
138 : {
139 16 : int32_t which = variant.which();
140 16 : ar( CEREAL_NVP_("which", which) );
141 16 : boost_variant_detail::variant_save_visitor<Archive> visitor(ar);
142 16 : variant.apply_visitor(visitor);
143 16 : }
144 :
145 : //! Loading for boost::variant
146 : template <class Archive, typename ... VariantTypes> inline
147 16 : void CEREAL_LOAD_FUNCTION_NAME( Archive & ar, boost::variant<VariantTypes...> & variant )
148 : {
149 : int32_t which;
150 16 : ar( CEREAL_NVP_("which", which) );
151 :
152 : using LoadFuncType = void(*)(Archive &, boost::variant<VariantTypes...> &);
153 16 : CEREAL_CONSTEXPR_LAMBDA LoadFuncType loadFuncArray[] = {&boost_variant_detail::load_variant_wrapper<VariantTypes>::load_variant...};
154 :
155 16 : if(which >= int32_t(sizeof(loadFuncArray)/sizeof(loadFuncArray[0])))
156 0 : throw Exception("Invalid 'which' selector when deserializing boost::variant");
157 :
158 16 : loadFuncArray[which](ar, variant);
159 16 : }
160 : } // namespace cereal
161 :
162 : #undef CEREAL_CONSTEXPR_LAMBDA
163 :
164 : #endif // CEREAL_TYPES_BOOST_VARIANT_HPP_
|