8#ifndef Sawyer_TreeVertex_H 
    9#define Sawyer_TreeVertex_H 
   11#include <Sawyer/Assert.h> 
   12#include <Sawyer/Exception.h> 
   14#include <boost/lexical_cast.hpp> 
   15#include <boost/range/adaptor/reversed.hpp> 
   16#include <boost/signals2/signal.hpp> 
   21#ifdef SAWYER_HAVE_BOOST_SERIALIZATION 
   22#include <boost/serialization/shared_ptr.hpp> 
   23#include <boost/serialization/vector.hpp> 
   26#ifdef SAWYER_HAVE_CEREAL 
   27#include <cereal/types/memory.hpp> 
   28#include <cereal/types/vector.hpp> 
  125class Vertex: 
public std::enable_shared_from_this<Vertex<B>> {
 
  138    template<
class T> 
class Edge;
 
  175            : 
Exception(
"insertion of vertex would cause a cycle in the tree", 
vertex) {}
 
 
 
  237        explicit operator bool()
 const {
 
  238            return parent_ != 
nullptr;
 
 
  243        template<
class T> 
friend class Edge;
 
  252    enum class Link { NO, YES };
 
  266        virtual ~EdgeBase() {}
 
  268        EdgeBase(
const EdgeBase&) = 
delete;
 
  269        EdgeBase& operator=(
const EdgeBase&) = 
delete;
 
  271            : prev(prev), parent_(
parent) {}
 
  274        virtual size_t size() 
const = 0;
 
  283        template<
class T, 
class Visitor>
 
  286                if (
auto retval = prev->traverse<T>(visitor))
 
  289            for (
size_t i = 0; i < size(); ++i) {
 
  291                    if (
auto retval = 
child->template traverse<T>(visitor))
 
  300        std::vector<UserBasePtr> immediateChildren()
 const {
 
  301            std::vector<UserBasePtr> retval;
 
  302            retval.reserve(size());
 
  303            for (
size_t i = 0; i < size(); ++i)
 
  311        std::vector<const EdgeBase*> baseEdgeList()
 const {
 
  312            std::vector<const EdgeBase*> retval;
 
  314                retval.push_back(
child);
 
  315            std::reverse(retval.begin(), retval.end());
 
  371        ChangeSignal beforeChange_;                     
 
  372        ChangeSignal afterChange_;                      
 
  374#ifdef SAWYER_HAVE_CEREAL 
  376        friend class cereal::access;
 
  378        template<
class Archive>
 
  379        void CEREAL_SERIALIZE_FUNCTION_NAME(Archive &archive) {
 
  380            archive(cereal::make_nvp(
"child", child_));
 
  384#ifdef SAWYER_HAVE_BOOST_SERIALIZATION 
  386        friend class boost::serialization::access;
 
  388        template<
class Archive>
 
  389        void serialize(Archive &archive, 
const unsigned ) {
 
  390            archive & boost::serialization::make_nvp(
"child", child_);
 
  453            if (newChild != child_) {
 
  454                checkChildInsertion(newChild);
 
  457                beforeChange_(oldChild, newChild);
 
  461                    child_->parent.reset();                     
 
  467                    newChild->parent.set(this->parent_);
 
  471                afterChange_(oldChild, newChild);
 
 
  477            return (*
this) = 
parent();
 
 
  482        explicit operator bool()
 const {
 
  483            return child_ != 
nullptr;
 
 
  491        boost::signals2::connection 
beforeChange(
const typename ChangeSignal::slot_type &slot) {
 
  492            return beforeChange_.connect(slot);
 
 
  499        boost::signals2::connection 
afterChange(
const typename ChangeSignal::slot_type &slot) {
 
  500            return afterChange_.connect(slot);
 
 
  506        size_t size()
 const override {
 
  511            ASSERT_always_require(0 == i);
 
  533        using Vector = std::vector<std::unique_ptr<Edge<Child>>>;
 
  534        using ResizeSignal = boost::signals2::signal<void(
int, 
ChildPtr)>;
 
  538        using size_type = 
typename Vector::size_type;
 
  539        using difference_type = 
typename Vector::difference_type;
 
  544        template<
class BaseIterator>
 
  546            BaseIterator baseIterator_;
 
  550            Iterator(
const BaseIterator &baseIterator)
 
  551                : baseIterator_(baseIterator) {}
 
  554                : baseIterator_(other.baseIterator_) {}
 
  557                baseIterator_ = other.baseIterator_;
 
  583            Iterator& operator+=(difference_type n) {
 
  588            Iterator operator+(difference_type n)
 const {
 
  594            Iterator& operator-=(difference_type n) {
 
  599            Iterator operator-(difference_type n)
 const {
 
  605            difference_type operator-(
const Iterator &other)
 const {
 
  606                return other.baseIterator_ - baseIterator_;
 
  609            auto& operator*()
 const {
 
  610                ASSERT_not_null(*baseIterator_);
 
  611                return **baseIterator_;
 
  614            auto& operator->()
 const {
 
  615                ASSERT_not_null(*baseIterator_);
 
  616                return &**baseIterator_;
 
  619            auto& operator[](difference_type i)
 const {
 
  620                ASSERT_not_null(baseIterator_[i]);
 
  621                return *baseIterator_[i];
 
  624            bool operator==(
const Iterator &other)
 const {
 
  625                return baseIterator_ == other.baseIterator_;
 
  628            bool operator!=(
const Iterator &other)
 const {
 
  629                return baseIterator_ != other.baseIterator_;
 
  632            bool operator<(
const Iterator &other)
 const {
 
  633                return baseIterator_ < other.baseIterator_;
 
  636            bool operator<=(
const Iterator &other)
 const {
 
  637                return baseIterator_ <= other.baseIterator_;
 
  640            bool operator>(
const Iterator &other)
 const {
 
  641                return baseIterator_ > other.baseIterator_;
 
  644            bool operator>=(
const Iterator &other)
 const {
 
  645                return baseIterator_ >= other.baseIterator_;
 
 
  654        ResizeSignal beforeResize_;                     
 
  655        ResizeSignal afterResize_;                      
 
  657#ifdef SAWYER_HAVE_CEREAL 
  659        friend class cereal::access;
 
  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) {
 
  667                archive(CEREAL_NVP(
child));
 
  671        template<
class Archive>
 
  672        void CEREAL_LOAD_FUNCTION_NAME(Archive &archive) {
 
  674            archive(CEREAL_NVP(nEdges));
 
  675            for (
size_t i = 0; i < nEdges; ++i) {
 
  677                archive(CEREAL_NVP(
child));
 
  683#ifdef SAWYER_HAVE_BOOST_SERIALIZATION 
  685        friend class boost::serialization::access;
 
  687        template<
class Archive>
 
  688        void save(Archive &archive, 
const unsigned )
 const {
 
  689            const size_t nEdges = edges_.size();
 
  690            archive <<BOOST_SERIALIZATION_NVP(nEdges);
 
  691            for (
size_t i = 0; i < nEdges; ++i) {
 
  693                archive <<BOOST_SERIALIZATION_NVP(
child);
 
  697        template<
class Archive>
 
  698        void load(Archive &archive, 
const unsigned ) {
 
  700            archive >>BOOST_SERIALIZATION_NVP(nEdges);
 
  701            for (
size_t i = 0; i < nEdges; ++i) {
 
  703                archive >>BOOST_SERIALIZATION_NVP(
child);
 
  708        BOOST_SERIALIZATION_SPLIT_MEMBER();
 
  727            return edges_.empty();
 
 
  734            return edges_.size();
 
 
  744            return edges_.capacity();
 
 
  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);
 
 
  762            ASSERT_forbid(edges_.empty());
 
  763            ChildPtr removed = (*edges_.back())();
 
  764            beforeResize_(-1, removed);
 
  766            afterResize_(-1, removed);
 
 
  773            ASSERT_require(i < edges_.size());
 
  774            return *edges_.at(i);
 
 
  777            ASSERT_require(i < edges_.size());
 
  778            return *edges_.at(i);
 
 
  792            ASSERT_forbid(
empty());
 
 
  796            ASSERT_forbid(
empty());
 
 
  805            ASSERT_forbid(
empty());
 
 
  809            ASSERT_forbid(
empty());
 
 
  829        boost::signals2::connection 
beforeResize(
const typename ResizeSignal::slot_type &slot) {
 
  830            return beforeResize_.connect(slot);
 
 
  838        boost::signals2::connection 
afterResize(
const typename ResizeSignal::slot_type &slot) {
 
  839            return afterResize_.connect(slot);
 
 
  859    EdgeBase *treeEdges_ = 
nullptr;
 
  861#ifdef SAWYER_HAVE_CEREAL 
  863    friend class cereal::access;
 
  867    template<
class Archive>
 
  869    CEREAL_SAVE_FUNCTION_NAME(Archive &archive)
 const {
 
  870        const std::vector<EdgeBase*> baseEdgeList = [
this]() {
 
  872                return treeEdges_->baseEdgeList();
 
  874                return std::vector<EdgeBase*>();
 
  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));
 
  886    template<
class Archive>
 
  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;
 
  901#ifdef SAWYER_HAVE_BOOST_SERIALIZATION 
  903    friend class boost::serialization::access;
 
  907    template<
class Archive>
 
  909    save(Archive &archive, 
const unsigned )
 const {
 
  910        const std::vector<EdgeBase*> baseEdgeList = [
this]() {
 
  912                return treeEdges_->baseEdgeList();
 
  914                return std::vector<EdgeBase*>();
 
  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);
 
  926    template<
class Archive>
 
  928    load(Archive &archive, 
const unsigned ) {
 
  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;
 
  940    BOOST_SERIALIZATION_SPLIT_MEMBER();
 
  947    virtual void destructorHelper() {}
 
  991    template<
class T, 
class Visitor>
 
  993        auto vertex = std::dynamic_pointer_cast<T>(this->
pointer());
 
 1000            if (
auto result = 
parent()->
template traverseReverse<T>(visitor))
 
 
 1019    template<
class T, 
class Visitor>
 
 1021        auto vertex = std::dynamic_pointer_cast<T>(this->
pointer());
 
 1027            if (
auto retval = treeEdges_->template traverse<T>(visitor))
 
 
 1044    template<
class T, 
class Visitor>
 
 1046        return traverse<T>([&visitor] (
const std::shared_ptr<T> &vertex, 
TraversalEvent event) {
 
 1048                return visitor(vertex);
 
 1050                return decltype(visitor(vertex))();
 
 
 1062    template<
class T, 
class Visitor>
 
 1064        return traverse<T>([&visitor] (
const std::shared_ptr<T> &vertex, 
TraversalEvent event) {
 
 1066                return visitor(vertex);
 
 1068                return decltype(visitor(vertex))();
 
 
 1076        return traverseReverse<T>([](
const std::shared_ptr<T> &vertex, 
TraversalEvent event) {
 
 
 1084        return traverseReverse<T>([](
const std::shared_ptr<T> &vertex, 
TraversalEvent event) {
 
 
 1095        std::vector<std::shared_ptr<T>> retval;
 
 1096        traverse<T>([&retval](
const std::shared_ptr<T> &vertex, 
TraversalEvent event) {
 
 1098                retval.push_back(vertex);
 
 
 1121    ASSERT_require(this->parent_ == 
nullptr);
 
 1141    ASSERT_not_null(parent_);
 
 1142    return parent_->pointer();
 
 
 1148    return ptr.get() == parent_;
 
 
 1154    return ptr.get() != parent_;
 
 
 1160    return parent_ == other.parent_;
 
 
 1166    return parent_ != other.parent_;
 
 
 1173    return parent_ == other();
 
 
 1180    return parent_ != other();
 
 
 1209    : EdgeBase(parent.treeEdges_, parent) {
 
 1210    this->parent_.treeEdges_ = 
this;
 
 
 1213#ifndef DOCUMENTATION                                    
 1218    checkChildInsertion(
child);
 
 1219    this->parent_.treeEdges_ = 
this;                    
 
 1225#ifndef DOCUMENTATION                                    
 1229    : EdgeBase(Link::YES == link ? 
parent.treeEdges_ : nullptr, 
parent), child_(
child) {
 
 1230    checkChildInsertion(
child);
 
 1231    if (Link::YES == link)
 
 1232        this->parent_.treeEdges_ = 
this;                
 
 1244            throw InsertionError(
child);
 
 1246        for (
const UserBase *p = &this->parent_; p; p = p->parent().get()) {
 
 1247            if (p == 
child.get())
 
 1248                throw CycleError(
child);
 
 1256const std::shared_ptr<T>&
 
 1258    ASSERT_not_null(child_);
 
 
 1264const std::shared_ptr<T>&
 
 1273    return child_ == ptr;
 
 
 1280    return child_ != ptr;
 
 
 1287    return child_ == other();
 
 
 1294    return child_.get() != other();
 
 
 1302    return child_.get() == other().get();
 
 
 1310    return child_.get() != other().get();
 
 
 1321    this->parent_.treeEdges_ = 
this;
 
 
 1335    auto retval = std::dynamic_pointer_cast<UserBase>(this->shared_from_this());
 
 1336    ASSERT_not_null(retval);
 
 
 1344    return std::dynamic_pointer_cast<T>(this->shared_from_this());
 
 
 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);
 
 
 1367    for (
const EdgeBase *edge = treeEdges_; edge; edge = edge->prev)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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.
 
CycleError(const UserBasePtr &vertex)
Construct a new error with the vertex that caused the error.
 
A 1:N tree edge from parent to children.
 
size_t size() const override
Number of child edges.
 
boost::signals2::connection beforeResize(const typename ResizeSignal::slot_type &slot)
Functors to call before the vector size is changed.
 
void push_back(const ChildPtr &elmt)
Insert a child pointer at the end of this vertex.
 
Edge< Child > & at(size_t i)
Return the i'th edge.
 
const Edge< Child > & at(size_t i) const
Return the i'th edge.
 
boost::signals2::connection afterResize(const typename ResizeSignal::slot_type &slot)
Functors to call after the vector size is changed.
 
size_t capacity() const
Reserved capacity.
 
const Edge< Child > & front() const
Return the first edge.
 
Edge< Child > & operator[](size_t i)
Return the i'th edge.
 
iterator begin()
Return an iterator to the first edge.
 
Edge< Child > & front()
Return the first edge.
 
const Edge< Child > & operator[](size_t i) const
Return the i'th edge.
 
void reserve(size_t n)
Reserve space so the child edge vector can grow without being reallocated.
 
bool empty() const
Test whether vector is empty.
 
~EdgeVector()
Destructor clears children's parents.
 
void pop_back()
Erase a child edge from the end of this vertex.
 
std::shared_ptr< Child > ChildPtr
Type of pointers to children.
 
T Child
Type of children being pointed to.
 
const Edge< Child > & back() const
Return the last edge.
 
Edge< Child > & back()
Return the last edge.
 
iterator end()
Return an iterator to one past the last edge.
 
A parent-to-child edge in a tree.
 
T Child
Type of child being pointed to.
 
Edge & operator=(const ChildPtr &newChild)
Assign a pointer to a child.
 
std::shared_ptr< Child > ChildPtr
Type of pointer to the child.
 
bool operator==(const UserBasePtr &) const
Compare the child pointer to another pointer.
 
bool operator!=(const UserBasePtr &) const
Compare the child pointer to another pointer.
 
boost::signals2::connection beforeChange(const typename ChangeSignal::slot_type &slot)
Functors to call before the child pointer is changed.
 
const ChildPtr & operator()() const
Return the child if there is one, else null.
 
boost::signals2::connection afterChange(const typename ChangeSignal::slot_type &slot)
Functors to call after the child pointer is changed.
 
Edge & operator=(const ReverseEdge &parent)
Assign a pointer to a child.
 
~Edge()
Destructor clears child's parent.
 
const ChildPtr & operator->() const
Return the child if there is one, else null.
 
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.
 
UserBasePtr vertex
Vertex that caused the error.
 
Exception(const std::string &mesg, const UserBasePtr &vertex)
Construct a new error with the specified message and the causing vertex.
 
Error when attaching a vertex to a tree and the vertex is already attached somewhere else.
 
InsertionError(const UserBasePtr &vertex)
Construct a new error with the vertex that caused the error.
 
Points from a child to a parent in the tree.
 
UserBasePtr operator->() const
Return the parent if there is one, else null.
 
bool operator==(const UserBasePtr &) const
Compare the parent pointer to another pointer.
 
bool operator!=(const UserBasePtr &) const
Compare the parent pointer to another pointer.
 
UserBasePtr operator()() const
Return the parent if there is one, else null.
 
Base class for tree vertices.
 
auto traversePost(const Visitor &visitor)
Post-order forward traversal.
 
std::shared_ptr< T > isa()
Tests whether this object is a certain type.
 
std::shared_ptr< T > findFirstAncestor()
Traversal that finds the closest ancestor of type T or derived from T.
 
auto traversePre(const Visitor &visitor)
Pre-order forward traversal.
 
ReverseEdge parent
Pointer to the parent in the tree.
 
std::vector< std::shared_ptr< T > > findDescendants()
Traversal that finds all the descendants of a particular type.
 
auto traverseReverse(const Visitor &visitor)
Traverse in reverse direction from children to parents.
 
std::shared_ptr< UserBase > UserBasePtr
Pointer to user's base class.
 
UserBasePtr child(size_t i) const
Returns the pointer for a child.
 
UserBasePtr pointer()
Returns a shared pointer to this vertex.
 
B UserBase
User's base class.
 
std::shared_ptr< T > findLastAncestor()
Traversal that finds the farthest ancestor of type T or derived from T.
 
auto traverse(const Visitor &visitor)
Traverse in forward direction from parents to children.
 
size_t nChildren() const
Returns the number of children.
 
TraversalEvent
Traversal event.
 
@ ENTER
Pre-order visitation.
 
@ LEAVE
Post-order visitation.