ROSE  0.11.125.0
Tree/Base.h
1 #ifndef ROSE_Tree_Base_H
2 #define ROSE_Tree_Base_H
3 #include <Rose/Tree/Exception.h>
4 
5 #include <Sawyer/Assert.h>
6 
7 #include <boost/lexical_cast.hpp>
8 #include <memory>
9 #include <string>
10 #include <vector>
11 
12 namespace Rose {
13 namespace Tree {
14 
16 // ReverseEdge
18 
19 // Internal. The only purpose of this class is so that the a forward edge has permission to change the parent pointer in an
20 // reverse edge.
22 protected:
23  void resetParent(ReverseEdge&);
24  void setParent(ReverseEdge&, Base&);
25 };
26 
36 class ReverseEdge {
37  Base &child_; // required child vertex owning this edge
38 
39  // The parent pointer is a raw pointer because it is safe to do so, and because we need to know the pointer before the parent is
40  // fully constructed.
41  //
42  // It is safe (never dangling) because the pointer can only be changed by a forward edge, which is always a member of a vertex,
43  // and the parent pointer is only set to point to that vertex. When the parent is deleted the edge is deleted and its destructor
44  // changes the parent pointer back to null.
45  //
46  // The parent pointer is needed during construction of the parent when the parent has some edge data members that are being
47  // initialized to point to non-null children. This happens during the parent's construction, before the parent has any shared or
48  // weak pointers.
49  Base *parent_ = nullptr; // optional parent to which this edge points
50 
51 public:
52  // No default constructor and not copyable.
53  ReverseEdge() = delete;
54  explicit ReverseEdge(const ReverseEdge&) = delete;
55  ReverseEdge& operator=(const ReverseEdge&) = delete;
56 
57 public:
58  ~ReverseEdge(); // internal use only
59  explicit ReverseEdge(Base &child); // internal use only
60 
61 public:
65  BasePtr operator()() const;
66  BasePtr operator->() const;
72  bool operator==(const BasePtr&) const;
73  bool operator!=(const BasePtr&) const;
74  bool operator==(const ReverseEdge&) const;
75  bool operator!=(const ReverseEdge&) const;
76  template<class T> bool operator==(const Edge<T>&) const;
77  template<class T> bool operator!=(const Edge<T>&) const;
81  explicit operator bool() const {
82  return parent_ != nullptr;
83  }
84 
85 private:
86  // Used internally through ReverseEdgeAccess when a Edge<T> adjusts the ReverseEdge
87  friend class ReverseEdgeAccess;
88  void reset();
89  void set(Base&);
90 };
91 
93 // Edge
95 
128 template<class T>
129 class Edge: protected ReverseEdgeAccess {
130 public:
132  using Child = T;
133 
135  using ChildPtr = std::shared_ptr<T>;
136 
137 private:
138  Base &parent_; // required parent owning this child edge
139  ChildPtr child_; // optional child to which this edge points
140 
141 public:
142  // No default constructor and not copyable.
143  Edge() = delete;
144  Edge(const Edge&) = delete;
145  Edge& operator=(const Edge&) = delete;
146 
147 public:
148  ~Edge();
149 
159  explicit Edge(Base &parent);
160  Edge(Base &parent, const ChildPtr &child);
166  const ChildPtr& operator->() const;
167  const ChildPtr& operator()() const;
173  bool operator==(const std::shared_ptr<Base>&) const;
174  bool operator!=(const std::shared_ptr<Base>&) const;
175  bool operator==(const ReverseEdge&) const;
176  bool operator!=(const ReverseEdge&) const;
177  template<class U> bool operator==(const Edge<U>&) const;
178  template<class U> bool operator!=(const Edge<U>&) const;
197  Edge& operator=(const ChildPtr &child);
198  Edge& operator=(const ReverseEdge&);
202  explicit operator bool() const {
203  return child_ != nullptr;
204  }
205 };
206 
208 // Base
210 
212 class Base: public std::enable_shared_from_this<Base> {
213 public:
215  using Ptr = BasePtr;
216 
218  enum class Traversal {
219  ENTER,
220  LEAVE
221  };
222 
223 protected:
226  size_t i;
227  std::string name;
229  };
230 
231 public:
237 
238 public:
239  virtual ~Base() {}
240 
241 protected:
242  virtual void destructorHelper() {}
243 
244 protected:
245  Base();
246 
247 public:
249  Ptr pointer();
250 
256  template<class Visitor>
257  auto traverseReverse(const Visitor &visitor) {
258  for (auto node = pointer(); node; node = node->parent()) {
259  if (auto result = visitor(node))
260  return result;
261  }
262  return decltype(visitor(BasePtr()))();
263  }
264 
273  template<class Visitor>
274  auto traverse(const Visitor &visitor) {
275  if (auto retval = visitor(this->pointer(), Traversal::ENTER))
276  return retval;
277  for (size_t i = 0; true; ++i) {
278  const ChildDescriptor child = findChild(i);
279  if (child.i < i) {
280  break;
281  } else if (child.value) {
282  if (auto retval = child.value->traverse(visitor))
283  return retval;
284  }
285  }
286  return visitor(this->pointer(), Traversal::LEAVE);
287  }
288 
290  template<class T>
291  std::shared_ptr<T> findAncestor() {
292  return visitParents([](const BasePtr &vertex) -> std::shared_ptr<T> {
293  return std::dynamic_pointer_cast<T>(vertex);
294  });
295  };
296 
301  template<class T>
302  std::vector<std::shared_ptr<T>> findDescendants() {
303  std::vector<std::shared_ptr<T>> retval;
304  traverse([&retval](const BasePtr &vertex, Traversal event) {
305  if (Traversal::ENTER == event) {
306  if (auto found = std::dynamic_pointer_cast<T>(vertex))
307  retval.push_back(found);
308  }
309  });
310  return retval;
311  }
312 
316  std::string childName(size_t i);
317 
322  Ptr child(size_t i);
323 
327  size_t nChildren(size_t i);
328 
329 protected:
338  virtual ChildDescriptor findChild(size_t i) const;
339 };
340 
342 // Template implementations
344 
345 template<class T>
346 bool
347 ReverseEdge::operator==(const Edge<T> &other) const {
348  return parent_ == other();
349 }
350 
351 template<class T>
352 bool
353 ReverseEdge::operator!=(const Edge<T> &other) const {
354  return parent_ != other();
355 }
356 
357 template<class T>
358 Edge<T>::~Edge() {
359  if (child_)
360  resetParent(child_->parent);
361 }
362 
363 template<class T>
365  : parent_(parent) {}
366 
367 template<class T>
368 Edge<T>::Edge(Base &parent, const std::shared_ptr<T> &child)
369  : parent_(parent), child_(child) {
370  if (child) {
371  if (child->parent)
372  throw InsertionError(child);
373  setParent(child->parent, parent);
374  }
375 }
376 
377 template<class T>
378 const std::shared_ptr<T>&
380  ASSERT_not_null(child_);
381  return child_;
382 }
383 
384 template<class T>
385 const std::shared_ptr<T>&
387  return child_;
388 }
389 
390 template<class T>
391 bool
392 Edge<T>::operator==(const BasePtr &ptr) const {
393  return child_ == ptr;
394 }
395 
396 template<class T>
397 bool
398 Edge<T>::operator!=(const BasePtr &ptr) const {
399  return child_ != ptr;
400 }
401 
402 template<class T>
403 bool
404 Edge<T>::operator==(const ReverseEdge &other) const {
405  return child_ == other();
406 }
407 
408 template<class T>
409 bool
410 Edge<T>::operator!=(const ReverseEdge &other) const {
411  return child_.get() != other();
412 }
413 
414 template<class T>
415 template<class U>
416 bool
417 Edge<T>::operator==(const Edge<U> &other) const {
418  return child_.get() == other.get();
419 }
420 
421 template<class T>
422 template<class U>
423 bool
424 Edge<T>::operator!=(const Edge<U> &other) const {
425  return child_.get() != other.get();
426 }
427 
428 template<class T>
429 Edge<T>&
430 Edge<T>::operator=(const std::shared_ptr<T> &child) {
431  if (child != child_) {
432  // Check for errors
433  if (child) {
434  if (child->parent)
435  throw InsertionError(child);
436 #ifndef NDEBUG
437  parent_.traverseReverse([&child](const BasePtr &node) {
438  if (child == node) {
439  throw CycleError(child);
440  } else {
441  return false;
442  }
443  });
444 #endif
445  }
446 
447  // Unlink the child from the tree
448  if (child_) {
449  resetParent(child_->parent);
450  child_.reset(); // parent-to-child edge
451  }
452 
453  // Link new child into the tree
454  if (child) {
455  setParent(child->parent, parent_);
456  child_ = child;
457  }
458  }
459  return *this;
460 }
461 
462 template<class T>
463 Edge<T>&
465  return (*this) = parent();
466 }
467 
468 } // namespace
469 } // namespace
470 #endif
BasePtr operator->() const
Return the parent if there is one, else null.
std::shared_ptr< T > ChildPtr
Type of pointer to the child.
Definition: Tree/Base.h:135
Error when attaching a vertex to a tree and the vertex is already attached somewhere else...
auto traverseReverse(const Visitor &visitor)
Traverse in reverse direction from children to parents.
Definition: Tree/Base.h:257
Traversal
Traversal direction.
Definition: Tree/Base.h:218
Ptr pointer()
Returns a shared pointer to this vertex.
std::shared_ptr< T > findAncestor()
Traversal that finds an ancestor of a particular type.
Definition: Tree/Base.h:291
Main namespace for the ROSE library.
Points from a child to a parent in the tree.
Definition: Tree/Base.h:36
std::string childName(size_t i)
Returns the property name for a child.
BasePtr operator()() const
Return the parent if there is one, else null.
Post-order visitation.
bool operator==(const BasePtr &) const
Compare the parent pointer to another pointer.
const ChildPtr & operator()() const
Return the child if there is one, else null.
Definition: Tree/Base.h:386
std::string name
Property name of the child.
Definition: Tree/Base.h:227
bool operator!=(const BasePtr &) const
Compare the parent pointer to another pointer.
size_t i
Index of the child counted across all inherited child edges.
Definition: Tree/Base.h:226
virtual ChildDescriptor findChild(size_t i) const
Finds information about an indexed child.
Ptr value
Child pointer value.
Definition: Tree/Base.h:228
Information about a child.
Definition: Tree/Base.h:225
bool operator!=(const std::shared_ptr< Base > &) const
Compare the child pointer to another pointer.
size_t nChildren(size_t i)
Returns the number of children.
std::shared_ptr< Base > BasePtr
Shared-ownership pointer for Base.
A parent-to-child edge in a tree.
Definition: Tree/Base.h:129
ReverseEdge parent
Pointer to the parent in the tree.
Definition: Tree/Base.h:236
std::vector< std::shared_ptr< T > > findDescendants()
Traversal that finds all the descendants of a particular type.
Definition: Tree/Base.h:302
auto traverse(const Visitor &visitor)
Traverse in forward direction from parents to children.
Definition: Tree/Base.h:274
bool operator==(const std::shared_ptr< Base > &) const
Compare the child pointer to another pointer.
Base class for tree vertices.
Definition: Tree/Base.h:212
Error when attaching a vertex to a tree would cause a cycle.
Ptr child(size_t i)
Returns the pointer for a child.
const ChildPtr & operator->() const
Return the child if there is one, else null.
Definition: Tree/Base.h:379
BasePtr Ptr
Shared-ownership pointer to a Base.
Definition: Tree/Base.h:215
T Child
Type of child being pointed to.
Definition: Tree/Base.h:132