hpp-util  4.14.0
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 requires(it.first, it.second->classid);
213  ar << make_nvp("requires", requires);
214  }
215  }
216  template <typename Archive,
217  std::enable_if_t<!Archive::is_saving::value, int> = 42>
218  void initialize_tpl(Archive& ar) // read
219  {
220  decltype(ptrs_.size()) size;
221  ar >> make_nvp("nrequires", size);
222  typedef std::pair<std::string, std::string> string_pair;
223  string_pair pair;
224  for (decltype(size) i = 0; i < size; ++i) {
225  ar >> make_nvp("requires", pair);
226  holder_base* hb = get(pair.first, true);
227  if (pair.second != hb->classid)
228  throw std::invalid_argument(
229  "Required pointer with name " + pair.first + " found of type " +
230  hb->classid + " but not of required type " + pair.second + ".");
231  }
232  }
233 };
234 
235 template <typename archive_base, typename... parent_classes>
236 class archive_tpl : public archive_base,
237  public archive_ptr_holder,
238  public parent_classes... {
239  public:
240  inline void initialize() { initialize_tpl<archive_base>(*this); }
241 
242  using archive_base::archive_base;
243 };
244 
245 template <typename Archive>
246 archive_ptr_holder& cast(Archive& ar) {
247  return dynamic_cast<archive_ptr_holder&>(ar);
248 }
249 template <typename Archive>
250 archive_ptr_holder* cast(Archive* ar) {
251  return dynamic_cast<archive_ptr_holder*>(ar);
252 }
253 
256 
259 
262 } // namespace serialization
263 } // namespace hpp
264 
265 #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:254
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:258
void insert(const std::string &k, holder_base *ptr)
Definition: serialization.hh:144
Definition: serialization.hh:236
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:257
archive_tpl< boost::archive::binary_oarchive > binary_oarchive
Definition: serialization.hh:255
archive_ptr_holder & cast(Archive &ar)
Definition: serialization.hh:246
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:240
bool containsOfType(const std::string &k) const
Definition: serialization.hh:140
archive_tpl< boost::archive::text_oarchive > text_oarchive
Definition: serialization.hh:261
archive_tpl< boost::archive::text_iarchive > text_iarchive
Definition: serialization.hh:260
void initialize_tpl(Archive &ar)
Definition: serialization.hh:206
Definition: serialization.hh:134