hpp-util  4.15.1
Debugging tools for the HPP project.
serialization.hh
Go to the documentation of this file.
1 //
2 // Copyright (c) 2020 CNRS
3 // Authors: Joseph Mirabel
4 //
5 
6 // Redistribution and use in source and binary forms, with or without
7 // modification, are permitted provided that the following conditions are
8 // met:
9 //
10 // 1. Redistributions of source code must retain the above copyright
11 // notice, this list of conditions and the following disclaimer.
12 //
13 // 2. Redistributions in binary form must reproduce the above copyright
14 // notice, this list of conditions and the following disclaimer in the
15 // documentation and/or other materials provided with the distribution.
16 //
17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 // HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
28 // DAMAGE.
29 
30 #ifndef HPP_UTIL_SERIALIZATION_HH
31 #define HPP_UTIL_SERIALIZATION_HH
32 
33 #include <boost/archive/binary_iarchive.hpp>
34 #include <boost/archive/binary_oarchive.hpp>
35 #include <boost/archive/text_iarchive.hpp>
36 #include <boost/archive/text_oarchive.hpp>
37 #include <boost/archive/xml_iarchive.hpp>
38 #include <boost/archive/xml_oarchive.hpp>
39 #include <boost/preprocessor/comma_if.hpp>
40 #include <boost/preprocessor/facilities/is_empty.hpp>
41 #include <boost/serialization/export.hpp>
42 #include <boost/serialization/nvp.hpp>
43 #include <boost/serialization/shared_ptr.hpp>
44 #include <boost/serialization/utility.hpp>
45 #include <boost/version.hpp>
46 #include <hpp/util/config.hh>
48 
49 #define _HPP_SERIALIZATION_SPLIT_IMPLEMENT(type, archive, arg) \
50  template void type load<archive##_iarchive>( \
51  archive##_iarchive & ar, \
52  arg BOOST_PP_COMMA_IF(BOOST_PP_NOT(BOOST_PP_IS_EMPTY(arg))) \
53  const unsigned int ver); \
54  template void type save<archive##_oarchive>( \
55  archive##_oarchive & ar, \
56  BOOST_PP_IF(BOOST_PP_IS_EMPTY(arg), , const) \
57  arg BOOST_PP_COMMA_IF(BOOST_PP_NOT(BOOST_PP_IS_EMPTY(arg))) \
58  const unsigned int ver) \
59  BOOST_PP_IF(BOOST_PP_IS_EMPTY(arg), const, )
60 
61 #define _HPP_SERIALIZATION_IMPLEMENT(type, archive, arg) \
62  template void type serialize<archive##_iarchive>( \
63  archive##_iarchive & ar, \
64  arg BOOST_PP_COMMA_IF(BOOST_PP_NOT(BOOST_PP_IS_EMPTY(arg))) \
65  const unsigned int ver); \
66  template void type serialize<archive##_oarchive>( \
67  archive##_oarchive & ar, \
68  arg BOOST_PP_COMMA_IF(BOOST_PP_NOT(BOOST_PP_IS_EMPTY(arg))) \
69  const unsigned int ver)
70 
71 #define HPP_SERIALIZATION_SPLIT_IMPLEMENT(type) \
72  _HPP_SERIALIZATION_SPLIT_IMPLEMENT(type::, boost::archive::xml, ); \
73  _HPP_SERIALIZATION_SPLIT_IMPLEMENT(type::, boost::archive::text, ); \
74  _HPP_SERIALIZATION_SPLIT_IMPLEMENT(type::, boost::archive::binary, )
75 
76 #define HPP_SERIALIZATION_IMPLEMENT(type) \
77  _HPP_SERIALIZATION_IMPLEMENT(type::, boost::archive::xml, ); \
78  _HPP_SERIALIZATION_IMPLEMENT(type::, boost::archive::text, ); \
79  _HPP_SERIALIZATION_IMPLEMENT(type::, boost::archive::binary, )
80 
81 #define HPP_SERIALIZATION_FREE_IMPLEMENT(type) \
82  namespace boost { \
83  namespace serialization { \
84  _HPP_SERIALIZATION_IMPLEMENT(, archive::xml, type& t); \
85  _HPP_SERIALIZATION_IMPLEMENT(, archive::text, type& t); \
86  _HPP_SERIALIZATION_IMPLEMENT(, archive::binary, type& t); \
87  } \
88  }
89 
90 #define HPP_SERIALIZATION_SPLIT_FREE_IMPLEMENT(type) \
91  namespace boost { \
92  namespace serialization { \
93  template <class Archive> \
94  void serialize(Archive& ar, type& t, const unsigned int version) { \
95  split_free(ar, t, version); \
96  } \
97  _HPP_SERIALIZATION_IMPLEMENT(, archive::xml, type& t); \
98  _HPP_SERIALIZATION_IMPLEMENT(, archive::text, type& t); \
99  _HPP_SERIALIZATION_IMPLEMENT(, archive::binary, type& t); \
100  } \
101  }
102 
103 namespace hpp {
104 namespace serialization {
105 using boost::serialization::guid;
106 using boost::serialization::guid_defined;
107 using boost::serialization::make_nvp;
108 
109 class holder_base {
110  public:
111  const char* classid;
112  virtual ~holder_base() = default;
113 
114  protected:
115  holder_base(const char* classid) : classid(classid) {}
116 };
117 
118 template <typename T>
119 class holder : public holder_base {
120  public:
121  T* t;
122  holder(T* t, const char* classid) : holder_base(classid), t(t) {}
123  holder(T* t) : holder(t, guid<T>()) {
124  static_assert(guid_defined<T>::value,
125  "You must use BOOST_CLASS_EXPORT_KEY on this class first.");
126  }
127 
128  template <typename U>
129  explicit operator holder<U>() {
130  return holder<U>(dynamic_cast<U*>(t), classid);
131  }
132 };
133 
135  std::map<std::string, holder_base*> ptrs_;
136 
137  public:
138  bool contains(const std::string& k) const { return ptrs_.count(k); }
139  template <typename T>
140  bool containsOfType(const std::string& k) const {
141  return (get<T>(k, false)) != NULL;
142  }
143 
144  void insert(const std::string& k, holder_base* ptr) { ptrs_[k] = ptr; }
145  template <typename T>
146  void insert(const std::string& k, T* ptr) {
147  insert(k, (holder_base*)new holder<T>(ptr));
148  }
149  holder_base* get(const std::string& k, bool throwIfNotFound = false) const {
150  auto _ptr = ptrs_.find(k);
151  if (_ptr == ptrs_.end()) {
152  if (!throwIfNotFound) return NULL;
153  throw std::invalid_argument("Pointer with name " + k + " not found.");
154  } else
155  return _ptr->second;
156  }
157  template <typename T>
158  T* get(const std::string& k, bool throwIfNotFound = false) const {
159  holder_base* hb(get(k, throwIfNotFound));
160  if (hb == NULL) return NULL;
161  holder<T>* h;
162  if ((h = dynamic_cast<holder<T>*>(hb)) == NULL) {
163  if (!throwIfNotFound) return NULL;
164  throw std::invalid_argument("Pointer with name " + k + " found of type " +
165  hb->classid + " but not of requested type " +
166  guid<T>() + ".");
167  }
168  return h->t;
169  }
170 
171  template <typename Base, typename Child>
172  void insertChildClass(const std::string& k, Child* ptr) {
173  static_assert(guid_defined<Child>::value,
174  "You must use BOOST_CLASS_EXPORT_KEY on this class first.");
175  insert(k, (holder_base*)new holder<Base>(ptr, guid<Child>()));
176  }
177  template <typename Base, typename Child>
178  Child* getChildClass(const std::string& k,
179  bool throwIfNotFound = false) const {
180  holder_base* hb(get(k, throwIfNotFound));
181  if (hb == NULL) return NULL;
182  holder<Base>* b;
183  if ((b = dynamic_cast<holder<Base>*>(hb)) == NULL) {
184  if (!throwIfNotFound) return NULL;
185  throw std::invalid_argument("Pointer with name " + k + " found of type " +
186  hb->classid + " but not of requested type " +
187  guid<Child>() + ".");
188  }
189  holder<Child> c(*b);
190  if (c.t == NULL) {
191  if (!throwIfNotFound) return NULL;
192  throw std::invalid_argument("Pointer with name " + k + " found of type " +
193  hb->classid + " but not of requested type " +
194  guid<Child>() + ".");
195  }
196  return c.t;
197  }
198 
200  for (auto it : ptrs_) delete it.second;
201  }
202 
203  protected:
204  template <typename Archive,
205  std::enable_if_t<Archive::is_saving::value, int> = 42>
206  void initialize_tpl(Archive& ar) // save
207  {
208  auto size(ptrs_.size());
209  ar << make_nvp("nrequires", size);
210  typedef std::pair<std::string, std::string> string_pair;
211  for (auto it : ptrs_) {
212  string_pair
213  requires(it.first, it.second->classid);
214  ar << make_nvp("requires", requires);
215  }
216  }
217  template <typename Archive,
218  std::enable_if_t<!Archive::is_saving::value, int> = 42>
219  void initialize_tpl(Archive& ar) // read
220  {
221  decltype(ptrs_.size()) size;
222  ar >> make_nvp("nrequires", size);
223  typedef std::pair<std::string, std::string> string_pair;
224  string_pair pair;
225  for (decltype(size) i = 0; i < size; ++i) {
226  ar >> make_nvp("requires", pair);
227  holder_base* hb = get(pair.first, true);
228  if (pair.second != hb->classid)
229  throw std::invalid_argument(
230  "Required pointer with name " + pair.first + " found of type " +
231  hb->classid + " but not of required type " + pair.second + ".");
232  }
233  }
234 };
235 
236 template <typename archive_base, typename... parent_classes>
237 class archive_tpl : public archive_base,
238  public archive_ptr_holder,
239  public parent_classes... {
240  public:
241  inline void initialize() { initialize_tpl<archive_base>(*this); }
242 
243  using archive_base::archive_base;
244 };
245 
246 template <typename Archive>
247 archive_ptr_holder& cast(Archive& ar) {
248  return dynamic_cast<archive_ptr_holder&>(ar);
249 }
250 template <typename Archive>
251 archive_ptr_holder* cast(Archive* ar) {
252  return dynamic_cast<archive_ptr_holder*>(ar);
253 }
254 
257 
260 
263 } // namespace serialization
264 } // namespace hpp
265 
266 #endif // HPP_UTIL_SERIALIZATION_HH
bool contains(const std::string &k) const
Definition: serialization.hh:138
holder(T *t, const char *classid)
Definition: serialization.hh:122
Definition: serialization.hh:109
archive_tpl< boost::archive::binary_iarchive > binary_iarchive
Definition: serialization.hh:255
Definition: serialization.hh:119
Definition: assertion.hh:45
virtual ~archive_ptr_holder()
Definition: serialization.hh:199
void insertChildClass(const std::string &k, Child *ptr)
Definition: serialization.hh:172
archive_tpl< boost::archive::xml_oarchive > xml_oarchive
Definition: serialization.hh:259
void insert(const std::string &k, holder_base *ptr)
Definition: serialization.hh:144
Definition: serialization.hh:237
Child * getChildClass(const std::string &k, bool throwIfNotFound=false) const
Definition: serialization.hh:178
holder(T *t)
Definition: serialization.hh:123
T * t
Definition: serialization.hh:121
archive_tpl< boost::archive::xml_iarchive > xml_iarchive
Definition: serialization.hh:258
archive_tpl< boost::archive::binary_oarchive > binary_oarchive
Definition: serialization.hh:256
archive_ptr_holder & cast(Archive &ar)
Definition: serialization.hh:247
void insert(const std::string &k, T *ptr)
Definition: serialization.hh:146
const char * classid
Definition: serialization.hh:111
virtual ~holder_base()=default
holder_base(const char *classid)
Definition: serialization.hh:115
void initialize()
Definition: serialization.hh:241
bool containsOfType(const std::string &k) const
Definition: serialization.hh:140
archive_tpl< boost::archive::text_oarchive > text_oarchive
Definition: serialization.hh:262
archive_tpl< boost::archive::text_iarchive > text_iarchive
Definition: serialization.hh:261
void initialize_tpl(Archive &ar)
Definition: serialization.hh:206
Definition: serialization.hh:134