pointer_variant_wrapper.hpp
Go to the documentation of this file.
1 
13 #ifndef MLPACK_CORE_CEREAL_POINTER_VARIANT_WRAPPER_HPP
14 #define MLPACK_CORE_CEREAL_POINTER_VARIANT_WRAPPER_HPP
15 
16 #include <cereal/archives/json.hpp>
17 #include <cereal/archives/portable_binary.hpp>
18 #include <cereal/archives/xml.hpp>
19 #include <cereal/types/boost_variant.hpp>
20 
21 #include <boost/variant.hpp>
22 #include <boost/variant/variant_fwd.hpp>
23 #include <boost/variant/static_visitor.hpp>
24 
25 #include "pointer_wrapper.hpp"
26 
27 namespace cereal {
28 
29 // Forward declaration.
30 template<typename... VariantTypes>
32 
40 template<typename... VariantTypes>
41 inline PointerVariantWrapper<VariantTypes...>
42 make_pointer_variant(boost::variant<VariantTypes...>& t)
43 {
44  return PointerVariantWrapper<VariantTypes...>(t);
45 }
46 
47 template<class Archive>
48 struct save_visitor : public boost::static_visitor<void>
49 {
50  save_visitor(Archive& ar) : ar(ar) {}
51 
52  template<class T>
53  void operator()(const T* value) const
54  {
55  ar(CEREAL_POINTER(value));
56  }
57 
58  template<typename... Types>
59  void operator()(boost::variant<Types*...>& value) const
60  {
61  ar(make_pointer_variant(value));
62  }
63 
64  Archive& ar;
65 };
66 
67 template<typename T>
68 struct load_visitor : public boost::static_visitor<void>
69 {
70  template<typename Archive, typename VariantType>
71  static void load_impl(Archive& ar, VariantType& variant, std::true_type)
72  {
73  // Note that T will be a pointer type.
74  T loadVariant;
75  ar(CEREAL_POINTER(loadVariant));
76  variant = loadVariant;
77  }
78 
79  template<typename Archive, typename VariantType>
80  static void load_impl(Archive& ar, VariantType& value, std::false_type)
81  {
82  // This must be a nested boost::variant.
83  T loadVariant;
84  ar(make_pointer_variant(loadVariant));
85  value = loadVariant;
86  }
87 
88  template<typename Archive, typename VariantType>
89  static void load(Archive& ar, VariantType& variant)
90  {
91  // Delegate to the proper load_impl() overload depending on whether T is a
92  // pointer type. If T is not a pointer type, then we expect it to be a
93  // nested boost::variant.
94  load_impl(ar, variant, typename std::is_pointer<T>::type());
95  }
96 };
97 
106 template<typename... VariantTypes>
108 {
109  public:
110  PointerVariantWrapper(boost::variant<VariantTypes...>& pointerVar) :
111  pointerVariant(pointerVar)
112  {}
113 
114  template<class Archive>
115  void save(Archive& ar) const
116  {
117  // which represents the index in std::variant.
118  int which = pointerVariant.which();
119  ar(CEREAL_NVP(which));
120  save_visitor<Archive> s(ar);
121  boost::apply_visitor(s, pointerVariant);
122  }
123 
124  template<class Archive>
125  void load(Archive& ar)
126  {
127  // Load the size of the serialized type.
128  int which;
129  ar(CEREAL_NVP(which));
130 
131  // Create function pointers to each overload of load_visitor<T>::load, for
132  // all T in VariantTypes.
133  using LoadFuncType = void(*)(Archive&, boost::variant<VariantTypes...>&);
134  LoadFuncType loadFuncArray[] = { &load_visitor<VariantTypes>::load... };
135 
136  if (which >= int(sizeof(loadFuncArray)/sizeof(loadFuncArray[0])))
137  throw std::runtime_error("Invalid 'which' selector when"
138  "deserializing boost::variant");
139 
140  loadFuncArray[which](ar, pointerVariant);
141  }
142 
143  private:
144  boost::variant<VariantTypes...>& pointerVariant;
145 };
146 
155 #define CEREAL_VARIANT_POINTER(T) cereal::make_pointer_variant(T)
156 
157 } // namespace cereal
158 
159 #endif // CEREAL_POINTER_VARIANT_WRAPPER_HPP
PointerVariantWrapper< VariantTypes... > make_pointer_variant(boost::variant< VariantTypes... > &t)
Serialize a boost variant in which the variant it self is a raw pointer.
void operator()(boost::variant< Types *... > &value) const
static void load_impl(Archive &ar, VariantType &value, std::false_type)
PointerVariantWrapper(boost::variant< VariantTypes... > &pointerVar)
#define CEREAL_POINTER(T)
Cereal does not support the serialization of raw pointer.
static void load_impl(Archive &ar, VariantType &variant, std::true_type)
The objective of this class is to create a wrapper for boost::variant.
static void load(Archive &ar, VariantType &variant)
void operator()(const T *value) const