ROSE 0.11.145.147
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
943protected:
944 virtual void destructorHelper() {}
945 Vertex();
946
947public:
950
954 template<class T>
955 std::shared_ptr<T> isa();
956
988 template<class T, class Visitor>
989 auto traverseReverse(const Visitor &visitor) {
990 auto vertex = std::dynamic_pointer_cast<T>(this->pointer());
991 if (vertex) {
992 if (auto result = visitor(vertex, TraversalEvent::ENTER))
993 return result;
994 }
995
996 if (parent) {
997 if (auto result = parent()->template traverseReverse<T>(visitor))
998 return result;
999 }
1000
1001 if (vertex) {
1002 return visitor(vertex, TraversalEvent::LEAVE);
1003 } else {
1004 return decltype(visitor(vertex, TraversalEvent::ENTER))();
1005 }
1006 }
1007
1016 template<class T, class Visitor>
1017 auto traverse(const Visitor &visitor) {
1018 auto vertex = std::dynamic_pointer_cast<T>(this->pointer());
1019 if (vertex) {
1020 if (auto retval = visitor(vertex, TraversalEvent::ENTER))
1021 return retval;
1022 }
1023 if (treeEdges_) {
1024 if (auto retval = treeEdges_->template traverse<T>(visitor))
1025 return retval;
1026 }
1027 if (vertex) {
1028 return visitor(vertex, TraversalEvent::LEAVE);
1029 } else {
1030 return decltype(visitor(vertex, TraversalEvent::ENTER))();
1031 }
1032 }
1033
1041 template<class T, class Visitor>
1042 auto traversePre(const Visitor &visitor) {
1043 return traverse<T>([&visitor] (const std::shared_ptr<T> &vertex, TraversalEvent event) {
1044 if (TraversalEvent::ENTER == event) {
1045 return visitor(vertex);
1046 } else {
1047 return decltype(visitor(vertex))();
1048 }
1049 });
1050 }
1051
1059 template<class T, class Visitor>
1060 auto traversePost(const Visitor &visitor) {
1061 return traverse<T>([&visitor] (const std::shared_ptr<T> &vertex, TraversalEvent event) {
1062 if (TraversalEvent::LEAVE == event) {
1063 return visitor(vertex);
1064 } else {
1065 return decltype(visitor(vertex))();
1066 }
1067 });
1068 }
1069
1071 template<class T>
1072 std::shared_ptr<T> findFirstAncestor() {
1073 return traverseReverse<T>([](const std::shared_ptr<T> &vertex, TraversalEvent event) {
1074 return TraversalEvent::ENTER == event ? vertex : nullptr;
1075 });
1076 };
1077
1079 template<class T>
1080 std::shared_ptr<T> findLastAncestor() {
1081 return traverseReverse<T>([](const std::shared_ptr<T> &vertex, TraversalEvent event) {
1082 return TraversalEvent::LEAVE == event ? vertex : nullptr;
1083 });
1084 };
1085
1090 template<class T>
1091 std::vector<std::shared_ptr<T>> findDescendants() {
1092 std::vector<std::shared_ptr<T>> retval;
1093 traverse<T>([&retval](const std::shared_ptr<T> &vertex, TraversalEvent event) {
1094 if (TraversalEvent::ENTER == event)
1095 retval.push_back(vertex);
1096 });
1097 return retval;
1098 }
1099
1104 UserBasePtr child(size_t i) const;
1105
1109 size_t nChildren() const;
1110};
1111
1113// Implementations for ReverseEdge
1115
1116template<class B>
1118 ASSERT_require(this->parent_ == nullptr);
1119}
1120
1121template<class B>
1123 : child_(child) {}
1124
1125template<class B>
1128 if (parent_) {
1129 return parent_->pointer();
1130 } else {
1131 return {};
1132 }
1133}
1134
1135template<class B>
1138 ASSERT_not_null(parent_);
1139 return parent_->pointer();
1140}
1141
1142template<class B>
1143bool
1145 return ptr.get() == parent_;
1146}
1147
1148template<class B>
1149bool
1151 return ptr.get() != parent_;
1152}
1153
1154template<class B>
1155bool
1157 return parent_ == other.parent_;
1158}
1159
1160template<class B>
1161bool
1163 return parent_ != other.parent_;
1164}
1165
1166template<class B>
1167template<class T>
1168bool
1170 return parent_ == other();
1171}
1172
1173template<class B>
1174template<class T>
1175bool
1177 return parent_ != other();
1178}
1179
1180template<class B>
1181void
1183 parent_ = nullptr;
1184}
1185
1186template<class B>
1187void
1188Vertex<B>::ReverseEdge::set(UserBase &parent) {
1189 parent_ = &parent;
1190}
1191
1193// Implementations for Edge<T>
1195
1196template<class B>
1197template<class T>
1199 if (child_)
1200 child_->parent.reset();
1201}
1202
1203template<class B>
1204template<class T>
1206 : EdgeBase(parent.treeEdges_, parent) {
1207 this->parent_.treeEdges_ = this;
1208}
1209
1210#ifndef DOCUMENTATION // doxygen has problems with this
1211template<class B>
1212template<class T>
1213Vertex<B>::Edge<T>::Edge(UserBase &parent, const std::shared_ptr<T> &child)
1214 : EdgeBase(parent.treeEdges_, parent), child_(child) {
1215 checkChildInsertion(child);
1216 this->parent_.treeEdges_ = this; // must be after checkChildInsertin for exception safety
1217 if (child)
1218 child->parent.set(parent);
1219}
1220#endif
1221
1222#ifndef DOCUMENTATION // doxygen has problems with this
1223template<class B>
1224template<class T>
1225Vertex<B>::Edge<T>::Edge(Link link, UserBase &parent, const std::shared_ptr<T> &child)
1226 : EdgeBase(Link::YES == link ? parent.treeEdges_ : nullptr, parent), child_(child) {
1227 checkChildInsertion(child);
1228 if (Link::YES == link)
1229 this->parent_.treeEdges_ = this; // must be after checkChildInsertin for exception safety
1230 if (child)
1231 child->parent.set(parent);
1232}
1233#endif
1234
1235template<class B>
1236template<class T>
1237void
1238Vertex<B>::Edge<T>::checkChildInsertion(const std::shared_ptr<T> &child) const {
1239 if (child) {
1240 if (child->parent)
1241 throw InsertionError(child);
1242#ifndef NDEBUG
1243 for (const UserBase *p = &this->parent_; p; p = p->parent().get()) {
1244 if (p == child.get())
1245 throw CycleError(child);
1246 }
1247#endif
1248 }
1249}
1250
1251template<class B>
1252template<class T>
1253const std::shared_ptr<T>&
1255 ASSERT_not_null(child_);
1256 return child_;
1257}
1258
1259template<class B>
1260template<class T>
1261const std::shared_ptr<T>&
1263 return child_;
1264}
1265
1266template<class B>
1267template<class T>
1268bool
1270 return child_ == ptr;
1271}
1272
1273template<class B>
1274template<class T>
1275bool
1277 return child_ != ptr;
1278}
1279
1280template<class B>
1281template<class T>
1282bool
1284 return child_ == other();
1285}
1286
1287template<class B>
1288template<class T>
1289bool
1291 return child_.get() != other();
1292}
1293
1294template<class B>
1295template<class T>
1296template<class U>
1297bool
1299 return child_.get() == other().get();
1300}
1301
1302template<class B>
1303template<class T>
1304template<class U>
1305bool
1307 return child_.get() != other().get();
1308}
1309
1311// Implementations for EdgeVector<T>
1313
1314template<class B>
1315template<class T>
1317 : EdgeBase(parent.treeEdges_, parent) {
1318 this->parent_.treeEdges_ = this;
1319}
1320
1322// Implementations for Vertex<B>
1324
1325template<class B>
1327 : parent(*this) {}
1328
1329template<class B>
1332 auto retval = std::dynamic_pointer_cast<UserBase>(this->shared_from_this());
1333 ASSERT_not_null(retval);
1334 return retval;
1335}
1336
1337template<class B>
1338template<class T>
1339std::shared_ptr<T>
1341 return std::dynamic_pointer_cast<T>(this->shared_from_this());
1342}
1343
1344template<class B>
1346Vertex<B>::child(size_t i) const {
1347 std::vector<EdgeBase*> edges;
1348 for (const EdgeBase *edge = treeEdges_; edge; edge = edge->prev)
1349 edges.push_back(edge);
1350 for (const EdgeBase *edge: boost::adaptors::reverse(edges)) {
1351 if (i < edge->size()) {
1352 return edge->pointer(i);
1353 } else {
1354 i -= edge->size();
1355 }
1356 }
1357 return {};
1358}
1359
1360template<class B>
1361size_t
1363 size_t n = 0;
1364 for (const EdgeBase *edge = treeEdges_; edge; edge = edge->prev)
1365 n += edge->size();
1366 return n;
1367}
1368
1369} // namespace
1370} // namespace
1371#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:1269
bool operator!=(const UserBasePtr &) const
Compare the child pointer to another pointer.
Definition Tree.h:1276
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:1262
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:1198
const ChildPtr & operator->() const
Return the child if there is one, else null.
Definition Tree.h:1254
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:1137
bool operator==(const UserBasePtr &) const
Compare the parent pointer to another pointer.
Definition Tree.h:1144
bool operator!=(const UserBasePtr &) const
Compare the parent pointer to another pointer.
Definition Tree.h:1150
UserBasePtr operator()() const
Return the parent if there is one, else null.
Definition Tree.h:1127
Base class for tree vertices.
Definition Tree.h:125
auto traversePost(const Visitor &visitor)
Post-order forward traversal.
Definition Tree.h:1060
std::shared_ptr< T > isa()
Tests whether this object is a certain type.
Definition Tree.h:1340
std::shared_ptr< T > findFirstAncestor()
Traversal that finds the closest ancestor of type T or derived from T.
Definition Tree.h:1072
auto traversePre(const Visitor &visitor)
Pre-order forward traversal.
Definition Tree.h:1042
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:1091
auto traverseReverse(const Visitor &visitor)
Traverse in reverse direction from children to parents.
Definition Tree.h:989
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:1346
UserBasePtr pointer()
Returns a shared pointer to this vertex.
Definition Tree.h:1331
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:1080
auto traverse(const Visitor &visitor)
Traverse in forward direction from parents to children.
Definition Tree.h:1017
size_t nChildren() const
Returns the number of children.
Definition Tree.h:1362
TraversalEvent
Traversal event.
Definition Tree.h:44
@ ENTER
Pre-order visitation.
@ LEAVE
Post-order visitation.
Sawyer support library.