ROSE 0.11.145.192
Tree.h
1// WARNING: Changes to this file must be contributed back to Sawyer or else they will
2// be clobbered by the next update from Sawyer. The Sawyer repository is at
3// https://gitlab.com/charger7534/sawyer.git.
4
5
6
7
8#ifndef Sawyer_TreeVertex_H
9#define Sawyer_TreeVertex_H
10
11#include <Sawyer/Assert.h>
12#include <Sawyer/Exception.h>
13
14#include <boost/lexical_cast.hpp>
15#include <boost/range/adaptor/reversed.hpp>
16#include <boost/signals2/signal.hpp>
17#include <memory>
18#include <string>
19#include <vector>
20
21#ifdef SAWYER_HAVE_BOOST_SERIALIZATION
22#include <boost/serialization/shared_ptr.hpp>
23#include <boost/serialization/vector.hpp>
24#endif
25
26#ifdef SAWYER_HAVE_CEREAL
27#include <cereal/types/memory.hpp>
28#include <cereal/types/vector.hpp>
29#endif
30
31namespace Sawyer {
32
38namespace Tree {
39
44enum class TraversalEvent {
45 ENTER,
46 LEAVE
47};
48
124template<class B>
125class Vertex: public std::enable_shared_from_this<Vertex<B>> {
126public:
127
129 using UserBase = B;
130
132 using UserBasePtr = std::shared_ptr<UserBase>;
133
136
137public:
138 template<class T> class Edge;
139 template<class T> class EdgeVector;
140
142 // Errors and exceptions
144
147 public:
150
152 Exception(const std::string &mesg, const UserBasePtr &vertex)
154
155 ~Exception() {}
156 };
157
161 class InsertionError: public Exception {
162 public:
165 : Exception("vertex is already attached to a tree", vertex) {}
166 };
167
171 class CycleError: public Exception {
172 public:
175 : Exception("insertion of vertex would cause a cycle in the tree", vertex) {}
176 };
177
179 // Child-to-parent edges
181
192 private:
193 Vertex &child_; // required child vertex owning this edge
194
195 // The parent pointer is a raw pointer because it is safe to do so, and because we need to know the pointer before the
196 // parent is fully constructed.
197 //
198 // It is safe (never dangling) because the pointer can only be changed by a forward edge, which is always a member of a
199 // vertex, and the parent pointer is only set to point to that vertex. When the parent is deleted the edge is deleted and
200 // its destructor changes the parent pointer back to null.
201 //
202 // The parent pointer is needed during construction of the parent when the parent has some edge data members that are being
203 // initialized to point to non-null children. This happens during the parent's construction, before the parent has any
204 // shared or weak pointers.
205 UserBase *parent_ = nullptr; // optional parent to which this edge points
206
207 public:
208 // No default constructor and not copyable.
209 ReverseEdge() = delete;
210 explicit ReverseEdge(const ReverseEdge&) = delete;
211 ReverseEdge& operator=(const ReverseEdge&) = delete;
212
213 public:
214 ~ReverseEdge(); // internal use only
215 explicit ReverseEdge(Vertex &child); // internal use only
216
217 public:
228 bool operator==(const UserBasePtr&) const;
229 bool operator!=(const UserBasePtr&) const;
230 bool operator==(const ReverseEdge&) const;
231 bool operator!=(const ReverseEdge&) const;
232 template<class T> bool operator==(const Edge<T>&) const;
233 template<class T> bool operator!=(const Edge<T>&) const;
237 explicit operator bool() const {
238 return parent_ != nullptr;
239 }
240
241 private:
242 // Used internally through ReverseEdgeAccess when a Edge<T> adjusts the ReverseEdge
243 template<class T> friend class Edge;
244 void reset();
245 void set(UserBase &parent);
246 };
247
249 // Base class for parent-to-child edges
251private:
252 enum class Link { NO, YES };
253
254 // Used internally as the non-template abstract base class for all parent-to-child edge types.
255 class EdgeBase {
256 public:
257 // Previous edge in this object, including edges defined in base classes. Edges in this linked list are ordered so that
258 // if edge A was initialized before edge B, then edge A will appear earlier in the list. The "prev" pointers in the list
259 // point backward through the list.
260 EdgeBase *prev;
261
262 protected:
263 UserBase &parent_; // required parent owning this child edge
264
265 public:
266 virtual ~EdgeBase() {}
267 EdgeBase() = delete;
268 EdgeBase(const EdgeBase&) = delete;
269 EdgeBase& operator=(const EdgeBase&) = delete;
270 explicit EdgeBase(EdgeBase *prev, UserBase &parent)
271 : prev(prev), parent_(parent) {}
272
273 // Number of child pointers in this edge. Edges are either 1:1 or 1:N. Some of the child pointers could be null.
274 virtual size_t size() const = 0;
275
276 // Return the i'th pointer. The argument is expected to be in the domain.
277 virtual UserBasePtr pointer(size_t i) const = 0;
278
279 // Traverse through all the non-null children of appropriate type pointed to by all edges in the order that the edges were
280 // initialized. The visitor is invoked with two arguments: a non-null shared pointer to the child, and an indication of
281 // whether this is a pre- or post-order visit. The first visitor call that returns a value that is true in a Boolean context
282 // short circuits the traversal and that value becomes the return value of the traversal.
283 template<class T, class Visitor>
284 auto traverse(Visitor visitor) -> decltype(visitor(std::shared_ptr<T>(), TraversalEvent::ENTER)) {
285 if (prev) {
286 if (auto retval = prev->traverse<T>(visitor))
287 return retval;
288 }
289 for (size_t i = 0; i < size(); ++i) {
290 if (auto child = pointer(i)) {
291 if (auto retval = child->template traverse<T>(visitor))
292 return retval;
293 }
294 }
295 return decltype(visitor(std::shared_ptr<T>(), TraversalEvent::ENTER))();
296 }
297
298 // Return the list of child pointers for this edge. An `Edge` will have exactly one pointer, and an `EdgeVector` will
299 // have any number of pointers. The pointers may be null.
300 std::vector<UserBasePtr> immediateChildren() const {
301 std::vector<UserBasePtr> retval;
302 retval.reserve(size());
303 for (size_t i = 0; i < size(); ++i)
304 retval.push_back(pointer(i));
305 return retval;
306 }
307
308 protected:
309 // Return this edge and the previous edges in the order they were initialized. Each member is either a non-null pointer to
310 // an `Edge` or a non-null pointer to an `EdgeVector`.
311 std::vector<EdgeBase*> baseEdgeList() const {
312 std::vector<EdgeBase*> retval;
313 for (EdgeBase *child = this; child; child = prev)
314 retval.push_back(child);
315 std::reverse(retval.begin(), retval.end());
316 return retval;
317 }
318
319 };
320
322 // 1:1 parent-to-child edge
324public:
357 template<class T>
358 class Edge: public EdgeBase {
359 public:
361 using Child = T;
362
364 using ChildPtr = std::shared_ptr<Child>;
365
366 private:
367 using ChangeSignal = boost::signals2::signal<void(ChildPtr, ChildPtr)>;
368
369 private:
370 ChildPtr child_; // optional child to which this edge points
371 ChangeSignal beforeChange_; // signal emitted before the child pointer is changed
372 ChangeSignal afterChange_; // signal emitted after the child pointer is changed
373
374#ifdef SAWYER_HAVE_CEREAL
375 private:
376 friend class cereal::access;
377
378 template<class Archive>
379 void CEREAL_SERIALIZE_FUNCTION_NAME(Archive &archive) {
380 archive(cereal::make_nvp("child", child_));
381 }
382#endif
383
384#ifdef SAWYER_HAVE_BOOST_SERIALIZATION
385 private:
386 friend class boost::serialization::access;
387
388 template<class Archive>
389 void serialize(Archive &archive, const unsigned /*version*/) {
390 archive & boost::serialization::make_nvp("child", child_);
391 }
392#endif
393
394 public:
397
408 explicit Edge(UserBase &parent);
412 private:
413 template<class U> friend class EdgeVector;
414 // Used internally to initialize an edge without linking it to prior edges
415 Edge(Link, UserBase &parent, const ChildPtr &child);
416
417 public:
421 const ChildPtr& operator->() const;
422 const ChildPtr& operator()() const;
428 bool operator==(const UserBasePtr&) const;
429 bool operator!=(const UserBasePtr&) const;
430 bool operator==(const ReverseEdge&) const;
431 bool operator!=(const ReverseEdge&) const;
432 template<class U> bool operator==(const Edge<U>&) const;
433 template<class U> bool operator!=(const Edge<U>&) const;
452 Edge& operator=(const ChildPtr &newChild) {
453 if (newChild != child_) {
454 checkChildInsertion(newChild);
455
456 const ChildPtr oldChild = child_;
457 beforeChange_(oldChild, newChild);
458
459 // Unlink the child from the tree
460 if (child_) {
461 child_->parent.reset(); // child-to-parent edge
462 child_.reset(); // parent-to-child edge
463 }
464
465 // Link new child into the tree
466 if (newChild) {
467 newChild->parent.set(this->parent_);
468 child_ = newChild;
469 }
470
471 afterChange_(oldChild, newChild);
472 }
473 return *this;
474 }
475
477 return (*this) = parent();
478 }
482 explicit operator bool() const {
483 return child_ != nullptr;
484 }
485
491 boost::signals2::connection beforeChange(const typename ChangeSignal::slot_type &slot) {
492 return beforeChange_.connect(slot);
493 }
494
499 boost::signals2::connection afterChange(const typename ChangeSignal::slot_type &slot) {
500 return afterChange_.connect(slot);
501 }
502
503 private:
504 void checkChildInsertion(const ChildPtr &child) const;
505
506 size_t size() const override {
507 return 1;
508 }
509
510 UserBasePtr pointer(size_t i) const override {
511 ASSERT_always_require(0 == i);
512 return child_;
513 }
514 };
515
517 // 1:N parent-to-child edge
519public:
523 template<class T>
524 class EdgeVector: public EdgeBase {
525 public:
527 using Child = T;
528
530 using ChildPtr = std::shared_ptr<Child>;
531
532 private:
533 using Vector = std::vector<std::unique_ptr<Edge<Child>>>;
534 using ResizeSignal = boost::signals2::signal<void(int, ChildPtr)>;
535
536 public:
537 using value_type = Edge<Child>;
538 using size_type = typename Vector::size_type;
539 using difference_type = typename Vector::difference_type;
540 using reference = value_type&;
541 using const_reference = const value_type&;
542
543 public:
544 template<class BaseIterator>
545 class Iterator {
546 BaseIterator baseIterator_;
547
548 public:
549 Iterator() = delete;
550 Iterator(const BaseIterator &baseIterator)
551 : baseIterator_(baseIterator) {}
552
553 Iterator(const Iterator &other)
554 : baseIterator_(other.baseIterator_) {}
555
556 Iterator& operator=(const Iterator &other) {
557 baseIterator_ = other.baseIterator_;
558 return *this;
559 }
560
561 Iterator& operator++() {
562 ++baseIterator_;
563 return *this;
564 }
565
566 Iterator operator++(int) {
567 Iterator temp = *this;
568 ++baseIterator_;
569 return temp;
570 }
571
572 Iterator& operator--() {
573 --baseIterator_;
574 return *this;
575 }
576
577 Iterator operator--(int) {
578 Iterator temp = *this;
579 --baseIterator_;
580 return temp;
581 }
582
583 Iterator& operator+=(difference_type n) {
584 baseIterator_ += n;
585 return *this;
586 }
587
588 Iterator operator+(difference_type n) const {
589 Iterator retval = *this;
590 retval += n;
591 return retval;
592 }
593
594 Iterator& operator-=(difference_type n) {
595 baseIterator_ -= n;
596 return *this;
597 }
598
599 Iterator operator-(difference_type n) const {
600 Iterator retval = *this;
601 retval -= n;
602 return retval;
603 }
604
605 difference_type operator-(const Iterator &other) const {
606 return other.baseIterator_ - baseIterator_;
607 }
608
609 auto& operator*() const {
610 ASSERT_not_null(*baseIterator_);
611 return **baseIterator_;
612 }
613
614 auto& operator->() const {
615 ASSERT_not_null(*baseIterator_);
616 return &**baseIterator_;
617 }
618
619 auto& operator[](difference_type i) const {
620 ASSERT_not_null(baseIterator_[i]);
621 return *baseIterator_[i];
622 }
623
624 bool operator==(const Iterator &other) const {
625 return baseIterator_ == other.baseIterator_;
626 }
627
628 bool operator!=(const Iterator &other) const {
629 return baseIterator_ != other.baseIterator_;
630 }
631
632 bool operator<(const Iterator &other) const {
633 return baseIterator_ < other.baseIterator_;
634 }
635
636 bool operator<=(const Iterator &other) const {
637 return baseIterator_ <= other.baseIterator_;
638 }
639
640 bool operator>(const Iterator &other) const {
641 return baseIterator_ > other.baseIterator_;
642 }
643
644 bool operator>=(const Iterator &other) const {
645 return baseIterator_ >= other.baseIterator_;
646 }
647 };
648
649 public:
651
652 private:
653 Vector edges_;
654 ResizeSignal beforeResize_; // signal emitted before a resize operation
655 ResizeSignal afterResize_; // signal emitted after a resize operation
656
657#ifdef SAWYER_HAVE_CEREAL
658 private:
659 friend class cereal::access;
660
661 template<class Archive>
662 void CEREAL_SAVE_FUNCTION_NAME(Archive &archive) const {
663 const size_t nEdges = edges_.size();
664 archive(CEREAL_NVP(nEdges));
665 for (size_t i = 0; i < nEdges; ++i) {
666 ChildPtr child = at(i)();
667 archive(CEREAL_NVP(child));
668 }
669 }
670
671 template<class Archive>
672 void CEREAL_LOAD_FUNCTION_NAME(Archive &archive) {
673 size_t nEdges = 0;
674 archive(CEREAL_NVP(nEdges));
675 for (size_t i = 0; i < nEdges; ++i) {
677 archive(CEREAL_NVP(child));
679 }
680 }
681#endif
682
683#ifdef SAWYER_HAVE_BOOST_SERIALIZATION
684 private:
685 friend class boost::serialization::access;
686
687 template<class Archive>
688 void save(Archive &archive, const unsigned /*version*/) const {
689 const size_t nEdges = edges_.size();
690 archive <<BOOST_SERIALIZATION_NVP(nEdges);
691 for (size_t i = 0; i < nEdges; ++i) {
692 ChildPtr child = at(i)();
693 archive <<BOOST_SERIALIZATION_NVP(child);
694 }
695 }
696
697 template<class Archive>
698 void load(Archive &archive, const unsigned /*version*/) {
699 size_t nEdges = 0;
700 archive >>BOOST_SERIALIZATION_NVP(nEdges);
701 for (size_t i = 0; i < nEdges; ++i) {
703 archive >>BOOST_SERIALIZATION_NVP(child);
705 }
706 }
707
708 BOOST_SERIALIZATION_SPLIT_MEMBER();
709#endif
710
711 public:
714
720 explicit EdgeVector(UserBase &parent);
721
722 public:
726 bool empty() const {
727 return edges_.empty();
728 }
729
733 size_t size() const override {
734 return edges_.size();
735 }
736
738 void reserve(size_t n) {
739 edges_.reserve(n);
740 }
741
743 size_t capacity() const {
744 return edges_.capacity();
745 }
746
751 void push_back(const ChildPtr& elmt) {
752 beforeResize_(+1, elmt);
753 auto edge = std::unique_ptr<Edge<Child>>(new Edge<Child>(Link::NO, this->parent_, elmt));
754 edges_.push_back(std::move(edge));
755 afterResize_(+1, elmt);
756 }
757
761 void pop_back() {
762 ASSERT_forbid(edges_.empty());
763 ChildPtr removed = (*edges_.back())();
764 beforeResize_(-1, removed);
765 edges_.pop_back();
766 afterResize_(-1, removed);
767 }
768
772 const Edge<Child>& at(size_t i) const {
773 ASSERT_require(i < edges_.size());
774 return *edges_.at(i);
775 }
776 Edge<Child>& at(size_t i) {
777 ASSERT_require(i < edges_.size());
778 return *edges_.at(i);
779 }
780 const Edge<Child>& operator[](size_t i) const {
781 return at(i);
782 }
784 return at(i);
785 }
791 const Edge<Child>& front() const {
792 ASSERT_forbid(empty());
793 return at(0);
794 }
796 ASSERT_forbid(empty());
797 return at(0);
798 }
804 const Edge<Child>& back() const {
805 ASSERT_forbid(empty());
806 return at(size() - 1);
807 }
809 ASSERT_forbid(empty());
810 return at(size() - 1);
811 }
816 return iterator(edges_.begin());
817 }
818
821 return iterator(edges_.end());
822 }
823
829 boost::signals2::connection beforeResize(const typename ResizeSignal::slot_type &slot) {
830 return beforeResize_.connect(slot);
831 }
832
838 boost::signals2::connection afterResize(const typename ResizeSignal::slot_type &slot) {
839 return afterResize_.connect(slot);
840 }
841
842 protected:
843 UserBasePtr pointer(size_t i) const override {
844 return at(i)();
845 }
846 };
847
849 // Vertex
851public:
857
858private:
859 EdgeBase *treeEdges_ = nullptr;
860
861#ifdef SAWYER_HAVE_CEREAL
862private:
863 friend class cereal::access;
864
865 // This base class is responsible for serializing the parts of the EdgeBase data members pointed to by `treeEdges_`, but not
866 // their child pointers. The child pointers are serialized by the derived classes where those data members are defined.
867 template<class Archive>
868 void
869 CEREAL_SAVE_FUNCTION_NAME(Archive &archive) const {
870 const std::vector<EdgeBase*> baseEdgeList = [this]() {
871 if (treeEdges_) {
872 return treeEdges_->baseEdgeList();
873 } else {
874 return std::vector<EdgeBase*>();
875 }
876 }();
877
878 const size_t nBases = baseEdgeList.size();
879 archive(CEREAL_NVP(nBases));
880 for (const EdgeBase *baseEdge: baseEdgeList) {
881 const size_t baseOffset = (char*)baseEdge - (char*)this;
882 archive(CEREAL_NVP(baseOffset));
883 }
884 }
885
886 template<class Archive>
887 void
888 CEREAL_LOAD_FUNCTION_NAME(Archive &archive) const {
889 const size_t nBases = 0;
890 archive(CEREAL_NVP(nBases));
891 for (size_t i = 0; i < nBases; ++i) {
892 size_t baseOffset = 0;
893 archive(CEREAL_NVP(baseOffset));
894 EdgeBase *baseEdge = (EdgeBase*)((char*)this + baseOffset);
895 baseEdge->reset(treeEdges_);
896 treeEdges_ = baseEdge;
897 }
898 }
899#endif
900
901#ifdef SAWYER_HAVE_BOOST_SERIALIZATION
902private:
903 friend class boost::serialization::access;
904
905 // This base class is responsible for serializing the parts of the EdgeBase data members pointed to by `treeEdges_`, but not
906 // their child pointers. The child pointers are serialized by the derived classes where those data members are defined.
907 template<class Archive>
908 void
909 save(Archive &archive, const unsigned /*version*/) const {
910 const std::vector<EdgeBase*> baseEdgeList = [this]() {
911 if (treeEdges_) {
912 return treeEdges_->baseEdgeList();
913 } else {
914 return std::vector<EdgeBase*>();
915 }
916 }();
917
918 const size_t nBases = baseEdgeList.size();
919 archive <<BOOST_SERIALIZATION_NVP(nBases);
920 for (const EdgeBase *baseEdge: baseEdgeList) {
921 const size_t baseOffset = (char*)baseEdge - (char*)this;
922 archive <<BOOST_SERIALIZATION_NVP(baseOffset);
923 }
924 }
925
926 template<class Archive>
927 void
928 load(Archive &archive, const unsigned /*version*/) {
929 const size_t nBases = 0;
930 archive >>BOOST_SERIALIZATION_NVP(nBases);
931 for (size_t i = 0; i < nBases; ++i) {
932 size_t baseOffset = 0;
933 archive >>BOOST_SERIALIZATION_NVP(baseOffset);
934 EdgeBase *baseEdge = (EdgeBase*)((char*)this + baseOffset);
935 baseEdge->reset(treeEdges_);
936 treeEdges_ = baseEdge;
937 }
938 }
939
940 BOOST_SERIALIZATION_SPLIT_MEMBER();
941#endif
942
943public:
944 virtual ~Vertex() {}
945
946protected:
947 virtual void destructorHelper() {}
948 Vertex();
949
950public:
953
957 template<class T>
958 std::shared_ptr<T> isa();
959
991 template<class T, class Visitor>
992 auto traverseReverse(const Visitor &visitor) {
993 auto vertex = std::dynamic_pointer_cast<T>(this->pointer());
994 if (vertex) {
995 if (auto result = visitor(vertex, TraversalEvent::ENTER))
996 return result;
997 }
998
999 if (parent) {
1000 if (auto result = parent()->template traverseReverse<T>(visitor))
1001 return result;
1002 }
1003
1004 if (vertex) {
1005 return visitor(vertex, TraversalEvent::LEAVE);
1006 } else {
1007 return decltype(visitor(vertex, TraversalEvent::ENTER))();
1008 }
1009 }
1010
1019 template<class T, class Visitor>
1020 auto traverse(const Visitor &visitor) {
1021 auto vertex = std::dynamic_pointer_cast<T>(this->pointer());
1022 if (vertex) {
1023 if (auto retval = visitor(vertex, TraversalEvent::ENTER))
1024 return retval;
1025 }
1026 if (treeEdges_) {
1027 if (auto retval = treeEdges_->template traverse<T>(visitor))
1028 return retval;
1029 }
1030 if (vertex) {
1031 return visitor(vertex, TraversalEvent::LEAVE);
1032 } else {
1033 return decltype(visitor(vertex, TraversalEvent::ENTER))();
1034 }
1035 }
1036
1044 template<class T, class Visitor>
1045 auto traversePre(const Visitor &visitor) {
1046 return traverse<T>([&visitor] (const std::shared_ptr<T> &vertex, TraversalEvent event) {
1047 if (TraversalEvent::ENTER == event) {
1048 return visitor(vertex);
1049 } else {
1050 return decltype(visitor(vertex))();
1051 }
1052 });
1053 }
1054
1062 template<class T, class Visitor>
1063 auto traversePost(const Visitor &visitor) {
1064 return traverse<T>([&visitor] (const std::shared_ptr<T> &vertex, TraversalEvent event) {
1065 if (TraversalEvent::LEAVE == event) {
1066 return visitor(vertex);
1067 } else {
1068 return decltype(visitor(vertex))();
1069 }
1070 });
1071 }
1072
1074 template<class T>
1075 std::shared_ptr<T> findFirstAncestor() {
1076 return traverseReverse<T>([](const std::shared_ptr<T> &vertex, TraversalEvent event) {
1077 return TraversalEvent::ENTER == event ? vertex : nullptr;
1078 });
1079 };
1080
1082 template<class T>
1083 std::shared_ptr<T> findLastAncestor() {
1084 return traverseReverse<T>([](const std::shared_ptr<T> &vertex, TraversalEvent event) {
1085 return TraversalEvent::LEAVE == event ? vertex : nullptr;
1086 });
1087 };
1088
1093 template<class T>
1094 std::vector<std::shared_ptr<T>> findDescendants() {
1095 std::vector<std::shared_ptr<T>> retval;
1096 traverse<T>([&retval](const std::shared_ptr<T> &vertex, TraversalEvent event) {
1097 if (TraversalEvent::ENTER == event)
1098 retval.push_back(vertex);
1099 });
1100 return retval;
1101 }
1102
1107 UserBasePtr child(size_t i) const;
1108
1112 size_t nChildren() const;
1113};
1114
1116// Implementations for ReverseEdge
1118
1119template<class B>
1121 ASSERT_require(this->parent_ == nullptr);
1122}
1123
1124template<class B>
1126 : child_(child) {}
1127
1128template<class B>
1131 if (parent_) {
1132 return parent_->pointer();
1133 } else {
1134 return {};
1135 }
1136}
1137
1138template<class B>
1141 ASSERT_not_null(parent_);
1142 return parent_->pointer();
1143}
1144
1145template<class B>
1146bool
1148 return ptr.get() == parent_;
1149}
1150
1151template<class B>
1152bool
1154 return ptr.get() != parent_;
1155}
1156
1157template<class B>
1158bool
1160 return parent_ == other.parent_;
1161}
1162
1163template<class B>
1164bool
1166 return parent_ != other.parent_;
1167}
1168
1169template<class B>
1170template<class T>
1171bool
1173 return parent_ == other();
1174}
1175
1176template<class B>
1177template<class T>
1178bool
1180 return parent_ != other();
1181}
1182
1183template<class B>
1184void
1186 parent_ = nullptr;
1187}
1188
1189template<class B>
1190void
1191Vertex<B>::ReverseEdge::set(UserBase &parent) {
1192 parent_ = &parent;
1193}
1194
1196// Implementations for Edge<T>
1198
1199template<class B>
1200template<class T>
1202 if (child_)
1203 child_->parent.reset();
1204}
1205
1206template<class B>
1207template<class T>
1209 : EdgeBase(parent.treeEdges_, parent) {
1210 this->parent_.treeEdges_ = this;
1211}
1212
1213#ifndef DOCUMENTATION // doxygen has problems with this
1214template<class B>
1215template<class T>
1216Vertex<B>::Edge<T>::Edge(UserBase &parent, const std::shared_ptr<T> &child)
1217 : EdgeBase(parent.treeEdges_, parent), child_(child) {
1218 checkChildInsertion(child);
1219 this->parent_.treeEdges_ = this; // must be after checkChildInsertin for exception safety
1220 if (child)
1221 child->parent.set(parent);
1222}
1223#endif
1224
1225#ifndef DOCUMENTATION // doxygen has problems with this
1226template<class B>
1227template<class T>
1228Vertex<B>::Edge<T>::Edge(Link link, UserBase &parent, const std::shared_ptr<T> &child)
1229 : EdgeBase(Link::YES == link ? parent.treeEdges_ : nullptr, parent), child_(child) {
1230 checkChildInsertion(child);
1231 if (Link::YES == link)
1232 this->parent_.treeEdges_ = this; // must be after checkChildInsertin for exception safety
1233 if (child)
1234 child->parent.set(parent);
1235}
1236#endif
1237
1238template<class B>
1239template<class T>
1240void
1241Vertex<B>::Edge<T>::checkChildInsertion(const std::shared_ptr<T> &child) const {
1242 if (child) {
1243 if (child->parent)
1244 throw InsertionError(child);
1245#ifndef NDEBUG
1246 for (const UserBase *p = &this->parent_; p; p = p->parent().get()) {
1247 if (p == child.get())
1248 throw CycleError(child);
1249 }
1250#endif
1251 }
1252}
1253
1254template<class B>
1255template<class T>
1256const std::shared_ptr<T>&
1258 ASSERT_not_null(child_);
1259 return child_;
1260}
1261
1262template<class B>
1263template<class T>
1264const std::shared_ptr<T>&
1266 return child_;
1267}
1268
1269template<class B>
1270template<class T>
1271bool
1273 return child_ == ptr;
1274}
1275
1276template<class B>
1277template<class T>
1278bool
1280 return child_ != ptr;
1281}
1282
1283template<class B>
1284template<class T>
1285bool
1287 return child_ == other();
1288}
1289
1290template<class B>
1291template<class T>
1292bool
1294 return child_.get() != other();
1295}
1296
1297template<class B>
1298template<class T>
1299template<class U>
1300bool
1302 return child_.get() == other().get();
1303}
1304
1305template<class B>
1306template<class T>
1307template<class U>
1308bool
1310 return child_.get() != other().get();
1311}
1312
1314// Implementations for EdgeVector<T>
1316
1317template<class B>
1318template<class T>
1320 : EdgeBase(parent.treeEdges_, parent) {
1321 this->parent_.treeEdges_ = this;
1322}
1323
1325// Implementations for Vertex<B>
1327
1328template<class B>
1330 : parent(*this) {}
1331
1332template<class B>
1335 auto retval = std::dynamic_pointer_cast<UserBase>(this->shared_from_this());
1336 ASSERT_not_null(retval);
1337 return retval;
1338}
1339
1340template<class B>
1341template<class T>
1342std::shared_ptr<T>
1344 return std::dynamic_pointer_cast<T>(this->shared_from_this());
1345}
1346
1347template<class B>
1349Vertex<B>::child(size_t i) const {
1350 std::vector<EdgeBase*> edges;
1351 for (const EdgeBase *edge = treeEdges_; edge; edge = edge->prev)
1352 edges.push_back(edge);
1353 for (const EdgeBase *edge: boost::adaptors::reverse(edges)) {
1354 if (i < edge->size()) {
1355 return edge->pointer(i);
1356 } else {
1357 i -= edge->size();
1358 }
1359 }
1360 return {};
1361}
1362
1363template<class B>
1364size_t
1366 size_t n = 0;
1367 for (const EdgeBase *edge = treeEdges_; edge; edge = edge->prev)
1368 n += edge->size();
1369 return n;
1370}
1371
1372} // namespace
1373} // namespace
1374#endif
Base class for Sawyer runtime errors.
RuntimeError(const std::string &mesg)
Constructor taking a description of the error.
Error when attaching a vertex to a tree would cause a cycle.
Definition Tree.h:171
CycleError(const UserBasePtr &vertex)
Construct a new error with the vertex that caused the error.
Definition Tree.h:174
A 1:N tree edge from parent to children.
Definition Tree.h:524
size_t size() const override
Number of child edges.
Definition Tree.h:733
boost::signals2::connection beforeResize(const typename ResizeSignal::slot_type &slot)
Functors to call before the vector size is changed.
Definition Tree.h:829
void push_back(const ChildPtr &elmt)
Insert a child pointer at the end of this vertex.
Definition Tree.h:751
Edge< Child > & at(size_t i)
Return the i'th edge.
Definition Tree.h:776
const Edge< Child > & at(size_t i) const
Return the i'th edge.
Definition Tree.h:772
boost::signals2::connection afterResize(const typename ResizeSignal::slot_type &slot)
Functors to call after the vector size is changed.
Definition Tree.h:838
size_t capacity() const
Reserved capacity.
Definition Tree.h:743
const Edge< Child > & front() const
Return the first edge.
Definition Tree.h:791
Edge< Child > & operator[](size_t i)
Return the i'th edge.
Definition Tree.h:783
iterator begin()
Return an iterator to the first edge.
Definition Tree.h:815
Edge< Child > & front()
Return the first edge.
Definition Tree.h:795
const Edge< Child > & operator[](size_t i) const
Return the i'th edge.
Definition Tree.h:780
void reserve(size_t n)
Reserve space so the child edge vector can grow without being reallocated.
Definition Tree.h:738
bool empty() const
Test whether vector is empty.
Definition Tree.h:726
~EdgeVector()
Destructor clears children's parents.
Definition Tree.h:713
void pop_back()
Erase a child edge from the end of this vertex.
Definition Tree.h:761
std::shared_ptr< Child > ChildPtr
Type of pointers to children.
Definition Tree.h:530
T Child
Type of children being pointed to.
Definition Tree.h:527
const Edge< Child > & back() const
Return the last edge.
Definition Tree.h:804
Edge< Child > & back()
Return the last edge.
Definition Tree.h:808
iterator end()
Return an iterator to one past the last edge.
Definition Tree.h:820
A parent-to-child edge in a tree.
Definition Tree.h:358
T Child
Type of child being pointed to.
Definition Tree.h:361
Edge & operator=(const ChildPtr &newChild)
Assign a pointer to a child.
Definition Tree.h:452
std::shared_ptr< Child > ChildPtr
Type of pointer to the child.
Definition Tree.h:364
bool operator==(const UserBasePtr &) const
Compare the child pointer to another pointer.
Definition Tree.h:1272
bool operator!=(const UserBasePtr &) const
Compare the child pointer to another pointer.
Definition Tree.h:1279
boost::signals2::connection beforeChange(const typename ChangeSignal::slot_type &slot)
Functors to call before the child pointer is changed.
Definition Tree.h:491
const ChildPtr & operator()() const
Return the child if there is one, else null.
Definition Tree.h:1265
boost::signals2::connection afterChange(const typename ChangeSignal::slot_type &slot)
Functors to call after the child pointer is changed.
Definition Tree.h:499
Edge & operator=(const ReverseEdge &parent)
Assign a pointer to a child.
Definition Tree.h:476
~Edge()
Destructor clears child's parent.
Definition Tree.h:1201
const ChildPtr & operator->() const
Return the child if there is one, else null.
Definition Tree.h:1257
Edge(UserBase &parent, const ChildPtr &child)
Construct a child edge that belongs to the specified parent.
Base class for errors and exceptions for this vertex type.
Definition Tree.h:146
UserBasePtr vertex
Vertex that caused the error.
Definition Tree.h:149
Exception(const std::string &mesg, const UserBasePtr &vertex)
Construct a new error with the specified message and the causing vertex.
Definition Tree.h:152
Error when attaching a vertex to a tree and the vertex is already attached somewhere else.
Definition Tree.h:161
InsertionError(const UserBasePtr &vertex)
Construct a new error with the vertex that caused the error.
Definition Tree.h:164
Points from a child to a parent in the tree.
Definition Tree.h:191
UserBasePtr operator->() const
Return the parent if there is one, else null.
Definition Tree.h:1140
bool operator==(const UserBasePtr &) const
Compare the parent pointer to another pointer.
Definition Tree.h:1147
bool operator!=(const UserBasePtr &) const
Compare the parent pointer to another pointer.
Definition Tree.h:1153
UserBasePtr operator()() const
Return the parent if there is one, else null.
Definition Tree.h:1130
Base class for tree vertices.
Definition Tree.h:125
auto traversePost(const Visitor &visitor)
Post-order forward traversal.
Definition Tree.h:1063
std::shared_ptr< T > isa()
Tests whether this object is a certain type.
Definition Tree.h:1343
std::shared_ptr< T > findFirstAncestor()
Traversal that finds the closest ancestor of type T or derived from T.
Definition Tree.h:1075
auto traversePre(const Visitor &visitor)
Pre-order forward traversal.
Definition Tree.h:1045
ReverseEdge parent
Pointer to the parent in the tree.
Definition Tree.h:856
std::vector< std::shared_ptr< T > > findDescendants()
Traversal that finds all the descendants of a particular type.
Definition Tree.h:1094
auto traverseReverse(const Visitor &visitor)
Traverse in reverse direction from children to parents.
Definition Tree.h:992
std::shared_ptr< UserBase > UserBasePtr
Pointer to user's base class.
Definition Tree.h:132
UserBasePtr child(size_t i) const
Returns the pointer for a child.
Definition Tree.h:1349
UserBasePtr pointer()
Returns a shared pointer to this vertex.
Definition Tree.h:1334
B UserBase
User's base class.
Definition Tree.h:129
std::shared_ptr< T > findLastAncestor()
Traversal that finds the farthest ancestor of type T or derived from T.
Definition Tree.h:1083
auto traverse(const Visitor &visitor)
Traverse in forward direction from parents to children.
Definition Tree.h:1020
size_t nChildren() const
Returns the number of children.
Definition Tree.h:1365
TraversalEvent
Traversal event.
Definition Tree.h:44
@ ENTER
Pre-order visitation.
@ LEAVE
Post-order visitation.
Sawyer support library.