tree-gen
C++ code generator for tree structures
tree-annotatable.hpp.inc
Go to the documentation of this file.
1 
5 #include <memory>
6 #include <vector>
7 #include <typeinfo>
8 #include <typeindex>
9 #include <unordered_map>
10 #include <functional>
11 
12 TREE_NAMESPACE_BEGIN
13 
18 namespace annotatable {
19 
24 class Anything {
25 private:
26 
30  void *data;
31 
35  std::function<void(void *data)> destructor;
36 
40  std::type_index type;
41 
45  Anything(void *data, std::function<void(void *data)> destructor, std::type_index type);
46 
47 public:
48 
52  Anything();
53 
57  template <typename T>
58  static Anything make(const T &ob) {
59  return Anything(
60  new T(ob),
61  [](void *data) {
62  delete static_cast<T*>(data);
63  },
64  std::type_index(typeid(T))
65  );
66  }
67 
71  template <typename T>
72  static Anything make(T &&ob) {
73  return Anything(
74  new T(std::move(ob)),
75  [](void *data) {
76  delete static_cast<T*>(data);
77  },
78  std::type_index(typeid(T))
79  );
80  }
81 
85  ~Anything();
86 
87  // Anything objects are not copyable, because type information is lost
88  // after the initial construction.
89  Anything(const Anything&) = delete;
90  Anything& operator=(const Anything&) = delete;
91 
95  Anything(Anything &&src);
96 
100  Anything& operator=(Anything &&src);
101 
107  template <typename T>
108  T *get_mut() {
109  if (std::type_index(typeid(T)) != type) {
110  throw std::bad_cast();
111  }
112  return static_cast<T*>(data);
113  }
114 
120  template <typename T>
121  const T *get_const() const {
122  if (std::type_index(typeid(T)) != type) {
123  throw std::bad_cast();
124  }
125  return static_cast<T*>(data);
126  }
127 
131  void *get() {
132  return data;
133  }
134 
138  const void *get() const {
139  return data;
140  }
141 
145  std::type_index get_type_index() const;
146 
147 };
148 
153 class Serializable {
154 public:
155  virtual ~Serializable() = default;
156  virtual void serialize(cbor::MapWriter&) const = 0;
157 };
158 
163 class SerDesRegistry {
164 private:
165 
169  TREE_MAP(
170  std::type_index,
171  std::function<void(const std::shared_ptr<Anything>&, cbor::MapWriter&)>
172  ) serializers;
173 
178  TREE_MAP(
179  std::string,
180  std::function<std::shared_ptr<Anything>(const cbor::MapReader&)>
181  ) deserializers;
182 
183 public:
184 
204  template <typename T>
205  void add(
206  std::function<void(const T&, cbor::MapWriter&)> serialize,
207  std::function<T(const cbor::MapReader&)> deserialize,
208  const std::string &name = ""
209  ) {
210  const std::string full_name = std::string(
211  "{" + (name.empty() ? std::string(typeid(T).name()) : name) + "}");
212  serializers.insert(std::make_pair(
213  std::type_index(typeid(T)),
214  [serialize, full_name](const std::shared_ptr<Anything> &anything, cbor::MapWriter &map) {
215  auto submap = map.append_map(full_name);
216  serialize(*(anything->get_const<T>()), submap);
217  }
218  ));
219  deserializers.insert(std::make_pair(
220  full_name,
221  [deserialize](const cbor::MapReader &map) -> std::shared_ptr<Anything> {
222  return std::make_shared<Anything>(Anything::make(deserialize(map)));
223  }
224  ));
225  }
226 
248  template <typename T>
249  void add(const std::string &name = "") {
250  const std::string full_name = std::string(
251  "{" + (name.empty() ? std::string(typeid(T).name()) : name) + "}");
252  serializers.insert(std::make_pair(
253  std::type_index(typeid(T)),
254  [full_name](const std::shared_ptr<Anything> &anything, cbor::MapWriter &map) {
255  auto submap = map.append_map(full_name);
256  anything->get_const<T>()->serialize(submap);
257  }
258  ));
259  deserializers.insert(std::make_pair(
260  full_name,
261  [](const cbor::MapReader &map) -> std::shared_ptr<Anything> {
262  return std::make_shared<Anything>(Anything::make(T(map)));
263  }
264  ));
265  }
266 
272  void serialize(std::shared_ptr<Anything> obj, cbor::MapWriter &map) const;
273 
279  std::shared_ptr<Anything> deserialize(const std::string &key, const cbor::Reader &value) const;
280 
281 };
282 
287 #ifdef _MSC_VER
288 #ifdef BUILDING_TREE_LIB
289 __declspec(dllexport)
290 #else
291 __declspec(dllimport)
292 #endif
293 #endif
294 extern SerDesRegistry serdes_registry;
295 
299 class Annotatable {
300 private:
301 
305  using AnnotationMap = TREE_MAP(std::type_index, std::shared_ptr<Anything>);
306  AnnotationMap annotations = {};
307 
311  mutable const std::type_index *cached_annot_type = nullptr;
312 
316  mutable void *cached_annot_ptr = nullptr;
317 
322  template <typename T>
323  const std::type_index &get_static_type_index() const {
324  static const auto TI = std::type_index(typeid(T));
325  return TI;
326  }
327 
334  template <typename T>
335  void *find_annotation_cached() const {
336  const auto &ti = get_static_type_index<T>();
337  if (cached_annot_type == &ti) {
338  return cached_annot_ptr;
339  }
340  auto it = annotations.find(ti);
341  if (it != annotations.end()) {
342  cached_annot_type = &ti;
343  cached_annot_ptr = it->second->get();
344  return cached_annot_ptr;
345  } else {
346  return nullptr;
347  }
348  }
349 
350 public:
351 
356  virtual ~Annotatable();
357 
369  template <typename T>
370  void set_annotation(const T &ob) {
371  TREE_MAP_SET(annotations, get_static_type_index<T>(), std::make_shared<Anything>(Anything::make<T>(ob)));
372  cached_annot_type = nullptr;
373  }
374 
384  template <typename T>
385  void set_annotation(T &&ob) {
386  TREE_MAP_SET(annotations, get_static_type_index<T>(), std::make_shared<Anything>(Anything::make<T>(std::move(ob))));
387  cached_annot_type = nullptr;
388  }
389 
394  template <typename T>
395  bool has_annotation() const {
396  return find_annotation_cached<T>() != nullptr;
397  }
398 
403  template <typename T>
404  T *get_annotation_ptr() {
405  return static_cast<T*>(find_annotation_cached<T>());
406  }
407 
412  template <typename T>
413  const T *get_annotation_ptr() const {
414  return static_cast<const T*>(find_annotation_cached<T>());
415  }
416 
421  template <typename T>
422  T &get_annotation() {
423  if (auto annotation = get_annotation_ptr<T>()) {
424  return *annotation;
425  } else {
426  throw TREE_RUNTIME_ERROR("object does not have an annotation of this type");
427  }
428  }
429 
434  template <typename T>
435  const T &get_annotation() const {
436  if (auto annotation = get_annotation_ptr<T>()) {
437  return *annotation;
438  } else {
439  throw TREE_RUNTIME_ERROR("object does not have an annotation of this type");
440  }
441  }
442 
446  template <typename T>
447  void erase_annotation() {
448  annotations.erase(get_static_type_index<T>());
449  cached_annot_type = nullptr;
450  }
451 
457  template <typename T>
458  void copy_annotation(const Annotatable &src) {
459  if (auto annotation = src.get_annotation_ptr<T>()) {
460  set_annotation(*annotation);
461  } else {
462  erase_annotation<T>();
463  }
464  }
465 
471  void copy_annotations(const Annotatable &src);
472 
481  void serialize_annotations(cbor::MapWriter &map) const;
482 
492  void deserialize_annotations(const cbor::MapReader &map);
493 
494 };
495 
496 } // namespace annotatable
497 TREE_NAMESPACE_END
STL namespace.