hpp-util  4.12.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 // This file is part of hpp-util
6 // hpp-util is free software: you can redistribute it
7 // and/or modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation, either version
9 // 3 of the License, or (at your option) any later version.
10 //
11 // hpp-util is distributed in the hope that it will be
12 // useful, but WITHOUT ANY WARRANTY; without even the implied warranty
13 // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 // General Lesser Public License for more details. You should have
15 // received a copy of the GNU Lesser General Public License along with
16 // hpp-util If not, see
17 // <http://www.gnu.org/licenses/>.
18 
19 #ifndef HPP_UTIL_SERIALIZATION_HH
20 #define HPP_UTIL_SERIALIZATION_HH
21 
22 #include <boost/version.hpp>
23 #include <boost/archive/binary_oarchive.hpp>
24 #include <boost/archive/text_oarchive.hpp>
25 #include <boost/archive/xml_oarchive.hpp>
26 #include <boost/archive/binary_iarchive.hpp>
27 #include <boost/archive/text_iarchive.hpp>
28 #include <boost/archive/xml_iarchive.hpp>
29 
30 #include <boost/preprocessor/comma_if.hpp>
31 #include <boost/preprocessor/facilities/is_empty.hpp>
32 #include <boost/serialization/export.hpp>
33 #include <boost/serialization/shared_ptr.hpp>
34 #include <boost/serialization/nvp.hpp>
35 #include <boost/serialization/utility.hpp>
36 
37 #include <hpp/util/config.hh>
39 
40 #define _HPP_SERIALIZATION_SPLIT_IMPLEMENT(type,archive,arg) \
41  template void type load<archive##_iarchive>(archive##_iarchive& ar, \
42  arg BOOST_PP_COMMA_IF(BOOST_PP_NOT(BOOST_PP_IS_EMPTY(arg))) \
43  const unsigned int ver); \
44  template void type save<archive##_oarchive>(archive##_oarchive& ar, \
45  BOOST_PP_IF(BOOST_PP_IS_EMPTY(arg),,const) arg BOOST_PP_COMMA_IF(BOOST_PP_NOT(BOOST_PP_IS_EMPTY(arg))) \
46  const unsigned int ver) BOOST_PP_IF(BOOST_PP_IS_EMPTY(arg),const,)
47 
48 #define _HPP_SERIALIZATION_IMPLEMENT(type,archive,arg) \
49  template void type serialize<archive##_iarchive>(archive##_iarchive& ar, \
50  arg BOOST_PP_COMMA_IF(BOOST_PP_NOT(BOOST_PP_IS_EMPTY(arg))) \
51  const unsigned int ver); \
52  template void type serialize<archive##_oarchive>(archive##_oarchive& ar, \
53  arg BOOST_PP_COMMA_IF(BOOST_PP_NOT(BOOST_PP_IS_EMPTY(arg))) \
54  const unsigned int ver)
55 
56 #define HPP_SERIALIZATION_SPLIT_IMPLEMENT(type) \
57  _HPP_SERIALIZATION_SPLIT_IMPLEMENT(type::,boost::archive::xml,); \
58  _HPP_SERIALIZATION_SPLIT_IMPLEMENT(type::,boost::archive::text,); \
59  _HPP_SERIALIZATION_SPLIT_IMPLEMENT(type::,boost::archive::binary,)
60 
61 #define HPP_SERIALIZATION_IMPLEMENT(type) \
62  _HPP_SERIALIZATION_IMPLEMENT(type::,boost::archive::xml,); \
63  _HPP_SERIALIZATION_IMPLEMENT(type::,boost::archive::text,); \
64  _HPP_SERIALIZATION_IMPLEMENT(type::,boost::archive::binary,)
65 
66 #define HPP_SERIALIZATION_FREE_IMPLEMENT(type) \
67  namespace boost { namespace serialization { \
68  _HPP_SERIALIZATION_IMPLEMENT(,archive::xml,type& t); \
69  _HPP_SERIALIZATION_IMPLEMENT(,archive::text,type& t); \
70  _HPP_SERIALIZATION_IMPLEMENT(,archive::binary,type& t); \
71  }}
72 
73 #define HPP_SERIALIZATION_SPLIT_FREE_IMPLEMENT(type) \
74  namespace boost { namespace serialization { \
75  template<class Archive> \
76  void serialize(Archive & ar, type& t, const unsigned int version) { \
77  split_free(ar, t, version); \
78  } \
79  _HPP_SERIALIZATION_IMPLEMENT(,archive::xml,type& t); \
80  _HPP_SERIALIZATION_IMPLEMENT(,archive::text,type& t); \
81  _HPP_SERIALIZATION_IMPLEMENT(,archive::binary,type& t); \
82  }}
83 
84 namespace hpp {
85 namespace serialization {
86 using boost::serialization::make_nvp;
87 using boost::serialization::guid;
88 using boost::serialization::guid_defined;
89 
90 class holder_base {
91 public:
92  const char* classid;
93  virtual ~holder_base() = default;
94 
95 protected:
96  holder_base(const char* classid) : classid(classid) {}
97 };
98 
99 template<typename T> class holder : public holder_base {
100 public:
101  T* t;
102  holder(T* t, const char* classid) : holder_base(classid), t(t) {}
103  holder(T* t) : holder(t, guid<T>())
104  { static_assert(guid_defined<T>::value, "You must use BOOST_CLASS_EXPORT_KEY on this class first."); }
105 
106  template <typename U> explicit operator holder<U>() { return holder<U>(dynamic_cast<U*>(t), classid); }
107 };
108 
110 {
111  std::map<std::string, holder_base*> ptrs_;
112 
113 public:
114  bool contains(const std::string& k) const { return ptrs_.count(k); }
115  template<typename T>
116  bool containsOfType(const std::string& k) const { return (get<T>(k, false)) != NULL; }
117 
118  void insert(const std::string& k, holder_base* ptr) { ptrs_[k] = ptr; }
119  template<typename T>
120  void insert(const std::string& k, T* ptr) { insert(k, (holder_base*)new holder<T>(ptr)); }
121  holder_base* get(const std::string& k, bool throwIfNotFound = false) const {
122  auto _ptr = ptrs_.find(k);
123  if (_ptr == ptrs_.end()) {
124  if (!throwIfNotFound) return NULL;
125  throw std::invalid_argument("Pointer with name " + k + " not found.");
126  }
127  else return _ptr->second;
128  }
129  template<typename T>
130  T* get(const std::string& k, bool throwIfNotFound = false) const {
131  holder_base* hb (get(k, throwIfNotFound));
132  if (hb == NULL) return NULL;
133  holder<T>* h;
134  if ((h = dynamic_cast<holder<T>*>(hb)) == NULL) {
135  if (!throwIfNotFound) return NULL;
136  throw std::invalid_argument("Pointer with name " + k + " found of type "
137  + hb->classid + " but not of requested type " + guid<T>() + ".");
138  }
139  return h->t;
140  }
141 
142  template<typename Base, typename Child>
143  void insertChildClass(const std::string& k, Child* ptr) {
144  static_assert(guid_defined<Child>::value, "You must use BOOST_CLASS_EXPORT_KEY on this class first.");
145  insert(k, (holder_base*)new holder<Base>(ptr, guid<Child>()));
146  }
147  template<typename Base, typename Child>
148  Child* getChildClass(const std::string& k, bool throwIfNotFound = false) const {
149  holder_base* hb (get(k, throwIfNotFound));
150  if (hb == NULL) return NULL;
151  holder<Base>* b;
152  if ((b = dynamic_cast<holder<Base>*>(hb)) == NULL) {
153  if (!throwIfNotFound) return NULL;
154  throw std::invalid_argument("Pointer with name " + k + " found of type "
155  + hb->classid + " but not of requested type " + guid<Child>() + ".");
156  }
157  holder<Child> c (*b);
158  if (c.t == NULL) {
159  if (!throwIfNotFound) return NULL;
160  throw std::invalid_argument("Pointer with name " + k + " found of type "
161  + hb->classid + " but not of requested type " + guid<Child>() + ".");
162  }
163  return c.t;
164  }
165 
167  for (auto it : ptrs_) delete it.second;
168  }
169 
170 protected:
171  template<typename Archive, std::enable_if_t<Archive::is_saving::value, int> = 42>
172  void initialize_tpl(Archive& ar) // save
173  {
174  auto size (ptrs_.size());
175  ar << make_nvp("nrequires", size);
176  typedef std::pair<std::string,std::string> string_pair;
177  for (auto it : ptrs_) {
178  string_pair requires(it.first, it.second->classid);
179  ar << make_nvp("requires", requires);
180  }
181  }
182  template<typename Archive, std::enable_if_t<!Archive::is_saving::value, int> = 42>
183  void initialize_tpl(Archive& ar) // read
184  {
185  decltype(ptrs_.size()) size;
186  ar >> make_nvp("nrequires", size);
187  typedef std::pair<std::string,std::string> string_pair;
188  string_pair pair;
189  for (decltype(size) i = 0; i < size; ++i) {
190  ar >> make_nvp("requires", pair);
191  holder_base* hb = get(pair.first, true);
192  if (pair.second != hb->classid)
193  throw std::invalid_argument("Required pointer with name " + pair.first + " found of type "
194  + hb->classid + " but not of required type " + pair.second + ".");
195  }
196  }
197 };
198 
199 template<typename archive_base, typename... parent_classes>
200 class archive_tpl : public archive_base, public archive_ptr_holder, public parent_classes...
201 {
202 public:
203  inline void initialize()
204  {
205  initialize_tpl<archive_base>(*this);
206  }
207 
208  using archive_base::archive_base;
209 };
210 
211 template<typename Archive>
212 archive_ptr_holder& cast(Archive& ar) { return dynamic_cast<archive_ptr_holder&>(ar); }
213 template<typename Archive>
214 archive_ptr_holder* cast(Archive* ar) { return dynamic_cast<archive_ptr_holder*>(ar); }
215 
218 
221 
224 } // namespace util
225 } // namespace hpp
226 
227 #endif // HPP_UTIL_SERIALIZATION_HH
bool contains(const std::string &k) const
Definition: serialization.hh:114
holder(T *t, const char *classid)
Definition: serialization.hh:102
Definition: serialization.hh:90
archive_tpl< boost::archive::binary_iarchive > binary_iarchive
Definition: serialization.hh:216
Definition: serialization.hh:99
Definition: assertion.hh:22
virtual ~archive_ptr_holder()
Definition: serialization.hh:166
void insertChildClass(const std::string &k, Child *ptr)
Definition: serialization.hh:143
archive_tpl< boost::archive::xml_oarchive > xml_oarchive
Definition: serialization.hh:220
void insert(const std::string &k, holder_base *ptr)
Definition: serialization.hh:118
Definition: serialization.hh:200
Child * getChildClass(const std::string &k, bool throwIfNotFound=false) const
Definition: serialization.hh:148
holder(T *t)
Definition: serialization.hh:103
T * t
Definition: serialization.hh:101
archive_tpl< boost::archive::xml_iarchive > xml_iarchive
Definition: serialization.hh:219
archive_tpl< boost::archive::binary_oarchive > binary_oarchive
Definition: serialization.hh:217
archive_ptr_holder & cast(Archive &ar)
Definition: serialization.hh:212
void insert(const std::string &k, T *ptr)
Definition: serialization.hh:120
const char * classid
Definition: serialization.hh:92
virtual ~holder_base()=default
holder_base(const char *classid)
Definition: serialization.hh:96
void initialize()
Definition: serialization.hh:203
bool containsOfType(const std::string &k) const
Definition: serialization.hh:116
archive_tpl< boost::archive::text_oarchive > text_oarchive
Definition: serialization.hh:223
archive_tpl< boost::archive::text_iarchive > text_iarchive
Definition: serialization.hh:222
void initialize_tpl(Archive &ar)
Definition: serialization.hh:172
Definition: serialization.hh:109