tree-gen
C++ code generator for tree structures
tree-base.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 #include <sstream>
12 #include <fstream>
13 
14 TREE_NAMESPACE_BEGIN
15 
19 namespace base {
20 
21 // Forward declarations for classes.
22 template <class T>
23 class Maybe;
24 template <class T>
25 class One;
26 template <class T>
27 class Any;
28 template <class T>
29 class Many;
30 class LinkBase;
31 template <class T>
32 class OptLink;
33 template <class T>
34 class Link;
35 
39 class RuntimeError : public TREE_RUNTIME_ERROR {
40 public:
41  explicit RuntimeError(const std::string &msg) : TREE_RUNTIME_ERROR(msg) {}
42 };
43 
47 class NotWellFormed : public RuntimeError {
48 public:
49  explicit NotWellFormed(const std::string &msg) : RuntimeError(msg) {}
50 };
51 
56 class OutOfRange : public TREE_RANGE_ERROR {
57 public:
58  explicit OutOfRange(const std::string &msg) : TREE_RANGE_ERROR(msg) {}
59 };
60 
66 class PointerMap {
67 private:
68 
73  TREE_MAP(const void*, size_t) map;
74 
79  size_t add_raw(const void *ptr, const char *name);
80 
85  size_t get_raw(const void *ptr, const char *name) const;
86 
87 public:
88 
92  static const size_t INVALID = (size_t)-1;
93 
99  bool enable_exceptions = true;
100 
106  template <class T>
107  size_t add(const Maybe<T> &ob);
108 
115  template <class T>
116  size_t add_ref(const T &ob);
117 
123  template <class T>
124  size_t get(const Maybe<T> &ob) const;
125 
131  template <class T>
132  size_t get(const OptLink<T> &ob) const;
133 
139  template <class T>
140  size_t get_ref(const T &ob) const;
141 
142 };
143 
149 class IdentifierMap {
150 private:
151 
155  TREE_MAP(size_t, std::shared_ptr<void>) nodes;
156 
160  using Link = std::pair<LinkBase&, size_t>;
161  TREE_VECTOR(Link) links;
162 
163 public:
164 
168  void register_node(size_t identifier, const std::shared_ptr<void> &ptr);
169 
173  void register_link(LinkBase &link, size_t identifier);
174 
178  void restore_links() const;
179 
180 };
181 
185 class Completable {
186 public:
187  virtual ~Completable() = default;
188 
195  virtual void find_reachable(PointerMap &map) const;
196 
207  virtual void check_complete(const PointerMap &map) const;
208 
219  virtual void check_well_formed() const final;
220 
230  virtual bool is_well_formed() const final;
231 
232 };
233 
237 class Base : public annotatable::Annotatable, public Completable {
238 };
239 
243 template <class T>
244 class Maybe : public Completable {
245 protected:
246 
250  std::shared_ptr<T> val;
251 
252 public:
253 
257  Maybe() : val() {}
258 
262  template <class S>
263  explicit Maybe(const std::shared_ptr<S> &value) : val(std::static_pointer_cast<T>(value)) {}
264 
268  template <class S>
269  explicit Maybe(std::shared_ptr<S> &&value) : val(std::static_pointer_cast<T>(std::move(value))) {}
270 
275  template <class S>
276  Maybe(const Maybe<S> &value) : val(std::static_pointer_cast<T>(value.get_ptr())) {}
277 
282  template <class S>
283  Maybe(Maybe<S> &&value) : val(std::static_pointer_cast<T>(std::move(value.get_ptr()))) {}
284 
288  template<typename S = T, class... Args>
289  void emplace(Args&&... args) {
290  val = std::static_pointer_cast<T>(std::make_shared<S>(std::forward<Args>(args)...));
291  }
292 
296  template<typename S = T, class... Args>
297  static One<T> make(Args&&... args);
298 
302  template <class S>
303  void set(const std::shared_ptr<S> &value) {
304  val = std::static_pointer_cast<T>(value);
305  }
306 
310  template <class S>
311  Maybe &operator=(const std::shared_ptr<S> &value) {
312  set<S>(value);
313  return *this;
314  }
315 
319  template <class S>
320  void set(std::shared_ptr<S> &&value) {
321  val = std::static_pointer_cast<T>(std::move(value));
322  }
323 
327  template <class S>
328  Maybe &operator=(std::shared_ptr<S> &&value) {
329  set<S>(std::move(value));
330  return *this;
331  }
332 
336  template <class S>
337  void set(const Maybe<S> &value) {
338  val = std::static_pointer_cast<T>(value.get_ptr());
339  }
340 
344  template <class S>
345  Maybe &operator=(const Maybe<S> &value) {
346  set<S>(std::move(value));
347  return *this;
348  }
349 
353  template <class S>
354  void set(Maybe<S> &&value) {
355  val = std::static_pointer_cast<T>(std::move(value.get_ptr()));
356  }
357 
361  template <class S>
362  Maybe &operator=(Maybe<S> &&value) {
363  set<S>(std::move(value));
364  return *this;
365  }
366 
374  template <class S>
375  void set_raw(S *ob) {
376  val = std::shared_ptr<T>(static_cast<T*>(ob));
377  }
378 
382  void reset() {
383  val.reset();
384  }
385 
389  virtual bool empty() const {
390  return val == nullptr;
391  }
392 
396  size_t size() const {
397  return val ? 1 : 0;
398  }
399 
405  T &deref() const {
406  if (!val) {
407  throw OutOfRange(
408  std::string("dereferencing empty Maybe/One object of type ") +
409  typeid(T).name()
410  );
411  }
412  return *val;
413  }
414 
419  T &operator*() const {
420  return deref();
421  }
422 
427  T *operator->() const {
428  return &deref();
429  }
430 
434  const std::shared_ptr<T> &get_ptr() const {
435  return val;
436  }
437 
441  std::shared_ptr<T> &get_ptr() {
442  return val;
443  }
444 
450  template <class S>
451  Maybe<S> as() const {
452  return Maybe<S>(std::dynamic_pointer_cast<S>(val));
453  }
454 
458  Maybe<const T> as_const() const {
459  return Maybe<const T>(std::const_pointer_cast<const T>(val));
460  }
461 
465  template <class V>
466  void visit(V &visitor) {
467  if (val) {
468  val->visit(visitor);
469  }
470  }
471 
475  bool equals(const Maybe &rhs) const {
476  if (val && rhs.get_ptr()) {
477  if (val == rhs.val) {
478  return true;
479  } else {
480  return val->equals(*rhs);
481  }
482  } else {
483  return val == rhs.get_ptr();
484  }
485  }
486 
490  bool operator==(const Maybe &rhs) const {
491  return val == rhs.get_ptr();
492  }
493 
497  bool operator!=(const Maybe &rhs) const {
498  return val != rhs.get_ptr();
499  }
500 
504  bool operator>(const Maybe &rhs) const {
505  return val > rhs.val;
506  }
507 
511  bool operator>=(const Maybe &rhs) const {
512  return val >= rhs.val;
513  }
514 
518  bool operator<(const Maybe &rhs) const {
519  return val < rhs.val;
520  }
521 
525  bool operator<=(const Maybe &rhs) const {
526  return val <= rhs.val;
527  }
528 
535  void find_reachable(PointerMap &map) const override {
536  if (val) {
537  map.add(*this);
538  val->find_reachable(map);
539  }
540  }
541 
552  void check_complete(const PointerMap &map) const override {
553  if (val) {
554  val->check_complete(map);
555  }
556  }
557 
561  One<typename std::remove_const<T>::type> copy() const;
562 
568  One<typename std::remove_const<T>::type> clone() const;
569 
570 protected:
571 
575  virtual std::string serdes_edge_type() const {
576  return "?";
577  }
578 
584  void deserialize(const cbor::MapReader &map, IdentifierMap &ids) {
585  // Note: this is in a function rather than in the constructor, because
586  // serdes_edge_type() would map to the base class if we just chain
587  // constructors, and we don't want to repeat this whole mess for One.
588  if (map.at("@T").as_string() != serdes_edge_type()) {
589  throw RuntimeError("Schema validation failed: unexpected edge type");
590  }
591  auto type = map.at("@t");
592  if (type.is_null()) {
593  val.reset();
594  } else {
595  val = T::deserialize(map, ids);
596  ids.register_node(map.at("@i").as_int(), std::static_pointer_cast<void>(val));
597  }
598  }
599 
600 public:
601 
607  void serialize(cbor::MapWriter &map, const PointerMap &ids) const {
608  map.append_string("@T", serdes_edge_type());
609  if (val) {
610  map.append_int("@i", ids.get(*this));
611  val->serialize(map, ids);
612  } else {
613  map.append_null("@t");
614  }
615  }
616 
621  Maybe(const cbor::MapReader &map, IdentifierMap &ids) : val() {
622  deserialize(map, ids);
623  }
624 
625 };
626 
630 template <class T>
631 class One : public Maybe<T> {
632 public:
633 
637  One() : Maybe<T>() {}
638 
642  template <class S>
643  explicit One(const std::shared_ptr<S> &value) : Maybe<T>(value) {}
644 
648  template <class S>
649  explicit One(std::shared_ptr<S> &&value) : Maybe<T>(std::move(value)) {}
650 
654  template <class S>
655  One(const Maybe<S> &value) : Maybe<T>(value.get_ptr()) {}
656 
660  template <class S>
661  One(Maybe<S> &&value) : Maybe<T>(std::move(value.get_ptr())) {}
662 
673  void check_complete(const PointerMap &map) const override {
674  if (!this->val) {
675  std::ostringstream ss{};
676  ss << "'One' edge of type " << typeid(T).name() << " is empty";
677  throw NotWellFormed(ss.str());
678  }
679  this->val->check_complete(map);
680  }
681 
682 protected:
683 
687  std::string serdes_edge_type() const override {
688  return "1";
689  }
690 
691 public:
692 
697  One(const cbor::MapReader &map, IdentifierMap &ids) : Maybe<T>() {
698  this->deserialize(map, ids);
699  }
700 
701 };
702 
706 template <class T>
707 One<typename std::remove_const<T>::type> Maybe<T>::copy() const {
708  if (val) {
709  return val->copy();
710  } else {
711  return Maybe<T>();
712  }
713 }
714 
718 template <class T>
719 One<typename std::remove_const<T>::type> Maybe<T>::clone() const {
720  if (val) {
721  return val->clone();
722  } else {
723  return Maybe<T>();
724  }
725 }
726 
730 template<typename T>
731 template<typename S, class... Args>
732 One<T> Maybe<T>::make(Args&&... args) {
733  return One<T>(std::static_pointer_cast<T>(std::make_shared<S>(std::forward<Args>(args)...)));
734 }
735 
739 template <class T, typename... Args>
740 One<T> make(Args... args) {
741  return One<T>(std::make_shared<T>(args...));
742 }
743 
747 template <class T>
748 class Any : public Completable {
749 protected:
750 
754  TREE_VECTOR(One<T>) vec;
755 
756 public:
757 
758  using iterator = typename TREE_VECTOR(One<T>)::iterator;
759  using Iterator = iterator;
760  using const_iterator = typename TREE_VECTOR(One<T>)::const_iterator;
761  using ConstIterator = const_iterator;
762  using reverse_iterator = typename TREE_VECTOR(One<T>)::reverse_iterator;
763  using ReverseIterator = reverse_iterator;
764  using const_reverse_iterator = typename TREE_VECTOR(One<T>)::const_reverse_iterator;
765  using ConstReverseIterator = const_reverse_iterator;
766 
770  Any() = default;
771 
775  Any(std::initializer_list<One<T>> inits) : vec(inits) {
776  }
777 
781  template <class S>
782  void add(const Maybe<S> &ob, signed_size_t pos=-1) {
783  if (ob.empty()) {
784  return;
785  }
786  if (pos < 0 || (size_t)pos >= size()) {
787  this->vec.emplace_back(
788  std::static_pointer_cast<T>(ob.get_ptr()));
789  } else {
790  this->vec.emplace(this->vec.cbegin() + pos,
791  std::static_pointer_cast<T>(
792  ob.get_ptr()));
793  }
794  }
795 
799  template <class S = T, typename... Args>
800  Any &emplace(Args... args) {
801  this->vec.emplace_back(std::static_pointer_cast<T>(std::make_shared<S>(std::forward<Args>(args)...)));
802  return *this;
803  }
804 
812  template <class S>
813  void add_raw(S *ob, signed_size_t pos=-1) {
814  if (!ob) {
815  throw RuntimeError("add_raw called with nullptr!");
816  }
817  if (pos < 0 || (size_t)pos >= size()) {
818  this->vec.emplace_back(std::shared_ptr<T>(static_cast<T*>(ob)));
819  } else {
820  this->vec.emplace(this->vec.cbegin() + pos, std::shared_ptr<T>(static_cast<T*>(ob)));
821  }
822  }
823 
827  void extend(const Any<T> &other) {
828  this->vec.insert(this->vec.end(), other.vec.begin(), other.vec.end());
829  }
830 
835  void remove(signed_size_t pos=-1) {
836  if (size() == 0) {
837  return;
838  }
839  if (pos < 0 || (size_t)pos >= size()) {
840  pos = size() - 1;
841  }
842  this->vec.erase(this->vec.cbegin() + pos);
843  }
844 
848  void reset() {
849  vec.clear();
850  }
851 
855  virtual bool empty() const {
856  return vec.empty();
857  }
858 
862  size_t size() const {
863  return vec.size();
864  }
865 
870  const One<T> &at(size_t index) const {
871  return vec.at(index);
872  }
873 
878  One<T> &at(size_t index) {
879  return vec.at(index);
880  }
881 
886  const One<T> &operator[] (size_t index) const {
887  return at(index);
888  }
889 
894  One<T> &operator[] (size_t index) {
895  return at(index);
896  }
897 
902  Maybe<T> front() const {
903  if (vec.empty()) {
904  return Maybe<T>();
905  } else {
906  return vec.front();
907  }
908  }
909 
914  Maybe<T> back() const {
915  if (vec.empty()) {
916  return Maybe<T>();
917  } else {
918  return vec.back();
919  }
920  }
921 
925  Iterator begin() {
926  return vec.begin();
927  }
928 
932  ConstIterator begin() const {
933  return vec.begin();
934  }
935 
939  Iterator end() {
940  return vec.end();
941  }
942 
946  ConstIterator end() const {
947  return vec.end();
948  }
949 
953  ReverseIterator rbegin() {
954  return vec.rbegin();
955  }
956 
960  ConstReverseIterator rbegin() const {
961  return vec.rbegin();
962  }
963 
967  ReverseIterator rend() {
968  return vec.rend();
969  }
970 
974  ConstReverseIterator rend() const {
975  return vec.rend();
976  }
977 
981  template <class V>
982  void visit(V &visitor) {
983  for (auto &sptr : this->vec) {
984  if (!sptr.empty()) {
985  sptr->visit(visitor);
986  }
987  }
988  }
989 
993  bool equals(const Any &rhs) const {
994  if (vec.size() != rhs.vec.size()) {
995  return false;
996  }
997  for (size_t i = 0; i < vec.size(); i++) {
998  if (!vec[i].equals(rhs.vec[i])) {
999  return false;
1000  }
1001  }
1002  return true;
1003  }
1004 
1008  bool operator==(const Any &rhs) const {
1009  return vec == rhs.vec;
1010  }
1011 
1015  inline bool operator!=(const Any &rhs) const {
1016  return !(*this == rhs);
1017  }
1018 
1022  const TREE_VECTOR(One<T>) &get_vec() const {
1023  return vec;
1024  }
1025 
1029  TREE_VECTOR(One<T>) &get_vec() {
1030  return vec;
1031  }
1032 
1039  void find_reachable(PointerMap &map) const override {
1040  for (auto &sptr : this->vec) {
1041  sptr.find_reachable(map);
1042  }
1043  }
1044 
1055  void check_complete(const PointerMap &map) const override {
1056  for (auto &sptr : this->vec) {
1057  sptr.check_complete(map);
1058  }
1059  }
1060 
1064  Many<typename std::remove_const<T>::type> copy() const;
1065 
1069  Many<typename std::remove_const<T>::type> clone() const;
1070 
1071 protected:
1072 
1076  virtual std::string serdes_edge_type() const {
1077  return "*";
1078  }
1079 
1085  void deserialize(const cbor::MapReader &map, IdentifierMap &ids) {
1086  // Note: this is in a function rather than in the constructor, because
1087  // serdes_edge_type() would map to the base class if we just chain
1088  // constructors, and we don't want to repeat this whole mess for Many.
1089  if (map.at("@T").as_string() != serdes_edge_type()) {
1090  throw RuntimeError("Schema validation failed: unexpected edge type");
1091  }
1092  for (const auto &it : map.at("@d").as_array()) {
1093  vec.emplace_back(it.as_map(), ids);
1094  }
1095  }
1096 
1097 public:
1098 
1104  void serialize(cbor::MapWriter &map, const PointerMap &ids) const {
1105  map.append_string("@T", serdes_edge_type());
1106  auto ar = map.append_array("@d");
1107  for (auto &sptr : this->vec) {
1108  auto submap = ar.append_map();
1109  sptr.serialize(submap, ids);
1110  }
1111  }
1112 
1117  Any(const cbor::MapReader &map, IdentifierMap &ids) : vec() {
1118  deserialize(map, ids);
1119  }
1120 
1121 };
1122 
1126 template <class T>
1127 class Many : public Any<T> {
1128 public:
1129 
1133  Many() = default;
1134 
1138  Many(std::initializer_list<One<T>> inits) : Any<T>(inits) {
1139  }
1140 
1151  void check_complete(const PointerMap &map) const override {
1152  if (this->empty()) {
1153  std::ostringstream ss{};
1154  ss << "'Many' edge of type " << typeid(T).name() << " is empty";
1155  throw NotWellFormed(ss.str());
1156  }
1157  Any<T>::check_complete(map);
1158  }
1159 
1160 protected:
1161 
1165  std::string serdes_edge_type() const override {
1166  return "+";
1167  }
1168 
1169 public:
1170 
1175  Many(const cbor::MapReader &map, IdentifierMap &ids) : Any<T>() {
1176  this->deserialize(map, ids);
1177  }
1178 
1179 };
1180 
1184 template <class T>
1185 Many<typename std::remove_const<T>::type> Any<T>::copy() const {
1186  Many<typename std::remove_const<T>::type> c{};
1187  for (auto &sptr : this->vec) {
1188  c.add(sptr.copy());
1189  }
1190  return c;
1191 }
1192 
1196 template <class T>
1197 Many<typename std::remove_const<T>::type> Any<T>::clone() const {
1198  Many<typename std::remove_const<T>::type> c{};
1199  for (auto &sptr : this->vec) {
1200  c.add(sptr.clone());
1201  }
1202  return c;
1203 }
1204 
1208 class LinkBase : public Completable {
1209 protected:
1210  friend class IdentifierMap;
1211 
1215  virtual void set_void_ptr(const std::shared_ptr<void> &ptr) = 0;
1216 
1217 };
1218 
1222 template <class T>
1223 class OptLink : public LinkBase {
1224 protected:
1225 
1229  std::weak_ptr<T> val;
1230 
1231 public:
1232 
1236  OptLink() : val() {}
1237 
1241  template <class S>
1242  OptLink(const Maybe<S> &value) : val(std::static_pointer_cast<T>(value.get_ptr())) {}
1243 
1247  template <class S>
1248  OptLink(Maybe<S> &&value) : val(std::static_pointer_cast<T>(std::move(value.get_ptr()))) {}
1249 
1253  template <class S>
1254  OptLink(const OptLink<S> &value) : val(std::static_pointer_cast<T>(value.get_ptr())) {}
1255 
1259  template <class S>
1260  OptLink(OptLink<S> &&value) : val(std::static_pointer_cast<T>(std::move(value.get_ptr()))) {}
1261 
1265  template <class S>
1266  void set(const Maybe<S> &value) {
1267  val = std::static_pointer_cast<T>(value.get_ptr());
1268  }
1269 
1273  template <class S>
1274  OptLink &operator=(const Maybe<S> &value) {
1275  set<S>(value);
1276  return *this;
1277  }
1278 
1282  template <class S>
1283  void set(Maybe<S> &&value) {
1284  val = std::static_pointer_cast<T>(std::move(value.get_ptr()));
1285  }
1286 
1290  template <class S>
1291  OptLink &operator=(Maybe<S> &&value) {
1292  set<S>(std::move(value));
1293  return *this;
1294  }
1295 
1299  void reset() {
1300  val.reset();
1301  }
1302 
1306  virtual bool empty() const {
1307  return val.expired();
1308  }
1309 
1313  size_t size() const {
1314  return val.expired() ? 0 : 1;
1315  }
1316 
1321  T &deref() {
1322  if (val.expired()) {
1323  throw OutOfRange(
1324  std::string("dereferencing empty or expired (Opt)Link object of type ") +
1325  typeid(T).name()
1326  );
1327  }
1328  return *(val.lock());
1329  }
1330 
1334  T &operator*() {
1335  return deref();
1336  }
1337 
1341  T *operator->() {
1342  return &deref();
1343  }
1344 
1349  T &deref() const {
1350  if (val.expired()) {
1351  throw OutOfRange("dereferencing empty or expired (Opt)Link object");
1352  }
1353  return *(val.lock());
1354  }
1355 
1359  T &operator*() const {
1360  return deref();
1361  }
1362 
1366  T *operator->() const {
1367  return &deref();
1368  }
1369 
1373  std::shared_ptr<T> get_ptr() const {
1374  return val.lock();
1375  }
1376 
1382  template <class S>
1383  Maybe<S> as() const {
1384  return Maybe<S>(std::dynamic_pointer_cast<S>(val.lock()));
1385  }
1386 
1390  Maybe<T> as_mut() const {
1391  return Maybe<T>(val.lock());
1392  }
1393 
1397  Maybe<const T> as_const() const {
1398  return Maybe<const T>(std::const_pointer_cast<const T>(val.lock()));
1399  }
1400 
1404  template <class V>
1405  void visit(V &visitor) {
1406  if (!val.expired()) {
1407  val.lock()->visit(visitor);
1408  }
1409  }
1410 
1415  bool equals(const OptLink &rhs) const {
1416  return get_ptr() == rhs.get_ptr();
1417  }
1418 
1422  bool operator==(const OptLink &rhs) const {
1423  return get_ptr() == rhs.get_ptr();
1424  }
1425 
1429  inline bool operator!=(const OptLink &rhs) const {
1430  return !(*this == rhs);
1431  }
1432 
1436  bool operator>(const OptLink &rhs) const {
1437  return get_ptr() > rhs.get_ptr();
1438  }
1439 
1443  bool operator>=(const OptLink &rhs) const {
1444  return get_ptr() >= rhs.get_ptr();
1445  }
1446 
1450  bool operator<(const OptLink &rhs) const {
1451  return get_ptr() < rhs.get_ptr();
1452  }
1453 
1457  bool operator<=(const OptLink &rhs) const {
1458  return get_ptr() <= rhs.get_ptr();
1459  }
1460 
1464  template <class S>
1465  bool links_to(const Maybe<S> target) {
1466  return get_ptr() == std::dynamic_pointer_cast<T>(target.get_ptr());
1467  }
1468 
1475  void find_reachable(PointerMap &map) const override {
1476  (void)map;
1477  }
1478 
1489  void check_complete(const PointerMap &map) const override {
1490  if (!this->empty()) {
1491  map.get(*this);
1492  }
1493  }
1494 
1495 protected:
1496 
1500  virtual std::string serdes_edge_type() const {
1501  return "@";
1502  }
1503 
1507  void set_void_ptr(const std::shared_ptr<void> &ptr) override {
1508  val = std::static_pointer_cast<T>(ptr);
1509  }
1510 
1517  void deserialize(const cbor::MapReader &map, IdentifierMap &ids) {
1518  (void)ids;
1519  // Note: this is in a function rather than in the constructor, because
1520  // serdes_edge_type() would map to the base class if we just chain
1521  // constructors, and we don't want to repeat this whole mess for Many.
1522  if (map.at("@T").as_string() != serdes_edge_type()) {
1523  throw RuntimeError("Schema validation failed: unexpected edge type");
1524  }
1525  val.reset();
1526  }
1527 
1528 public:
1529 
1533  void serialize(cbor::MapWriter &map, const PointerMap &ids) const {
1534  map.append_string("@T", serdes_edge_type());
1535  map.append_int("@l", ids.get(*this));
1536  }
1537 
1542  OptLink(const cbor::MapReader &map, IdentifierMap &ids) : val() {
1543  deserialize(map, ids);
1544  }
1545 
1546 };
1547 
1551 template <class T>
1552 class Link : public OptLink<T> {
1553 public:
1554 
1558  Link() : OptLink<T>() {}
1559 
1563  template <class S>
1564  Link(const Maybe<S> &value) : OptLink<T>(value) {}
1565 
1569  template <class S>
1570  Link(Maybe<S> &&value) : OptLink<T>(std::move(value)) {}
1571 
1575  template <class S>
1576  Link(const OptLink<S> &value) : OptLink<T>(value) {}
1577 
1581  template <class S>
1582  Link(OptLink<S> &&value) : OptLink<T>(std::move(value)) {}
1583 
1594  void check_complete(const PointerMap &map) const override {
1595  if (this->empty()) {
1596  std::ostringstream ss{};
1597  ss << "'Link' edge of type " << typeid(T).name() << " is empty";
1598  throw NotWellFormed(ss.str());
1599  }
1600  map.get(*this);
1601  }
1602 
1603 protected:
1604 
1608  std::string serdes_edge_type() const override {
1609  return "$";
1610  }
1611 
1612 public:
1613 
1618  Link(const cbor::MapReader &map, IdentifierMap &ids) : OptLink<T>() {
1619  this->deserialize(map, ids);
1620  }
1621 
1622 };
1623 
1629 template <class T>
1630 size_t PointerMap::add(const Maybe<T> &ob) {
1631  return add_raw(reinterpret_cast<const void*>(ob.get_ptr().get()), typeid(T).name());
1632 }
1633 
1640 template <class T>
1641 size_t PointerMap::add_ref(const T &ob) {
1642  return add_raw(reinterpret_cast<const void*>(&ob), typeid(T).name());
1643 }
1644 
1650 template <class T>
1651 size_t PointerMap::get(const Maybe<T> &ob) const {
1652  return get_raw(reinterpret_cast<const void*>(ob.get_ptr().get()), typeid(T).name());
1653 }
1654 
1660 template <class T>
1661 size_t PointerMap::get(const OptLink<T> &ob) const {
1662  return get_raw(reinterpret_cast<const void*>(ob.get_ptr().get()), typeid(T).name());
1663 }
1664 
1670 template <class T>
1671 size_t PointerMap::get_ref(const T &ob) const {
1672  return get_raw(reinterpret_cast<const void*>(&ob), typeid(T).name());
1673 }
1674 
1678 template <class T>
1679 void serialize(const Maybe<T> tree, std::ostream &stream) {
1680  tree::cbor::Writer writer{stream};
1681  PointerMap ids{};
1682  tree.find_reachable(ids);
1683  tree.check_complete(ids);
1684  auto map = writer.start();
1685  tree.serialize(map, ids);
1686  map.close();
1687 }
1688 
1692 template <class T>
1693 std::string serialize(const Maybe<T> tree) {
1694  std::ostringstream stream{};
1695  serialize<T>(tree, stream);
1696  return stream.str();
1697 }
1698 
1702 template <class T>
1703 void serialize_file(const Maybe<T> tree, const std::string &filename) {
1704  serialize<T>(tree, std::ofstream(filename));
1705 }
1706 
1710 template <class T>
1711 Maybe<T> deserialize(const std::string &cbor) {
1712  cbor::Reader reader{cbor};
1713  IdentifierMap ids{};
1714  Maybe<T> tree{reader.as_map(), ids};
1715  ids.restore_links();
1716  tree.check_well_formed();
1717  return tree;
1718 }
1719 
1723 template <class T>
1724 Maybe<T> deserialize(std::istream &stream) {
1725  std::ostringstream ss;
1726  ss << stream.rdbuf();
1727  return deserialize<T>(ss.str());
1728 }
1729 
1733 template <class T>
1734 Maybe<T> deserialize_file(const std::string &&filename) {
1735  return deserialize<T>(std::ifstream(filename));
1736 }
1737 
1738 } // namespace base
1739 TREE_NAMESPACE_END
Exactly one node.
Definition: tree-gen.hpp:645
STL namespace.
Zero or one nodes.
Definition: tree-gen.hpp:640
Link to zero or one nodes elsewhere in the tree.
Definition: tree-gen.hpp:660
One or more nodes.
Definition: tree-gen.hpp:655
Zero or more nodes.
Definition: tree-gen.hpp:650
Link to exactly one node elsewhere in the tree.
Definition: tree-gen.hpp:665