ocra-recipes
Doxygen documentation for the ocra-recipes repository
Composite.h
Go to the documentation of this file.
1 
15 #ifndef _OCRA_COMPOSITE_H_
16 #define _OCRA_COMPOSITE_H_
17 
18 #ifdef _MSC_VER
19 # pragma once
20 #endif
21 
22 #include "ocra/optim/ocra_assert.h"
23 
24 #include <boost/noncopyable.hpp>
25 #include <boost/static_assert.hpp>
26 #include <boost/type_traits/is_base_of.hpp>
27 #include <boost/type_traits/is_convertible.hpp>
28 #include <boost/type_traits/has_nothrow_constructor.hpp>
29 
30 #include <vector>
31 #include <algorithm>
32 #include <iosfwd>
33 #include <stdexcept>
34 
35 namespace ocra
36 {
37  template<class ComponentDerived, class CompositeDerived, class ParenthoodInfo> class Component;
38  template<class ComponentDerived, class CompositeDerived, class ParenthoodInfo> class Composite;
39 
41 
45  struct NoInfo {};
46 
47 
48  // ------------------------------------------------------------
49  // --- PARENTHOOD ---------------------------------------------
50  // ------------------------------------------------------------
51 
53 
93  template<class ComponentDerived, class CompositeDerived, class ParenthoodInfo = NoInfo>
94  class Parenthood
95  : boost::noncopyable
96  {
97  public:
99  typedef ComponentDerived component_t;
100  typedef CompositeDerived parent_t;
101 
102  private:
103  // Composite objects can create and destroy parenthood bonds to attach children.
104  // To keep this operation private, Composite has been made friend of Parenthood.
105  friend class Composite<ComponentDerived, CompositeDerived, ParenthoodInfo>;
106 
108 
121  Parenthood(parent_t& parent, component_t& child)
122  : parent_(parent), child_(child)
123  , rankOfParent_(child.parents_.size()), rankOfChild_(parent.children_.size())
124  , info_()
125  {
126  // Check preconditions
127  ocra_assert(!parent.isAncestorOf(child) && "Parent is already an ancestor of child!");
128  ocra_assert(!child.isAncestorOf(parent) && "Parent is already a descendant of child!");
129  ocra_assert(&child != &parent && "Cannot attach a node to itself!");
130 
131  parent_.children_.push_back(this);
132  child_.parents_.push_back(this);
133 
134  // Call the callbacks to inform the parent and child about their new bond.
135  child_.onAttachedParentI(*this);
136  parent_.onAttachedChildI(*this);
137 
138  // Check post-conditions.
139  ocra_assert(&parent.getChildhood(getRankOfChild()) == &child.getParenthood(getRankOfParent()) &&
140  &parent.getChildhood(getRankOfChild()) == this &&
141  "The same bond is supposed to be registered in both the parent and the child");
142  ocra_assert(parent_.isAncestorOf(child_) && "Parent-child relationship not acknowledged");
143  ocra_assert(!child_.isAncestorOf(parent_) && "Reversed parent-child relationship");
144  }
145 
147 
175  ~Parenthood()
176  {
177  typename std::vector<parenthood_t*>::iterator itChild = parent_.children_.begin() + rankOfChild_;
178  typename std::vector<parenthood_t*>::iterator itParent = child_.parents_.begin() + rankOfParent_;
179 
180  // Check invariants.
181  ocra_assert(this == *itChild && this == *itParent && "Class invariant broken: the bond is not properly registered in the parent and the child.");
182  ocra_assert(parent_.isAncestorOf_impl(child_) && "Class invariant broken");
183  // !child_.isAncestorOf(parent_) cannot be tested here since it is a virtual function, so we use a special version.
184  ocra_assert(!childIsAncestorOfParent_forDestructor() && "Class invariant broken");
185 
186  // Inform child and parents they are no longer bound to each other.
187  child_.onDetachedParentI(*this);
188  parent_.onDetachedChildI(*this);
189 
190  parent_.children_.erase(parent_.children_.begin() + rankOfChild_);
191  child_.parents_.erase(child_.parents_.begin() + rankOfParent_);
192 
193  // Update rank of all younger brothers of child.
194  for(itChild = parent_.children_.begin() + rankOfChild_; itChild != parent_.children_.end(); ++itChild)
195  {
196  ocra_assert((*itChild)->rankOfChild_ && "rankOfChild_ is not supposed to be decreased when already 0");
197  --(*itChild)->rankOfChild_;
198  }
199 
200  // Update rank of all child's parents younger than parent_.
201  for(itParent = child_.parents_.begin() + rankOfParent_; itParent != child_.parents_.end(); ++itParent)
202  {
203  ocra_assert((*itParent)->rankOfParent_ && "rankOfParent_ is not supposed to be decreased when already 0");
204  --(*itParent)->rankOfParent_;
205  }
206  }
207 
208  int childIsAncestorOfParent_forDestructor() // see invariants check in destructor for explanation
209  {
210  parent_t* child_or_null = dynamic_cast<parent_t*>(&child_);
211 
212  if(child_or_null) // we have a composite, just check using the static isAncestorOf_impl!
213  return child_or_null->isAncestorOf_impl(parent_);
214 
215  return false; // we have a leaf, so of course it's no ancestor!
216  }
217 
218  public:
220  CompositeDerived& getParent() const { return static_cast<CompositeDerived&>(parent_); }
222  size_t getRankOfParent() const { return rankOfParent_; }
223 
224  ComponentDerived& getChild() const { return static_cast<ComponentDerived&>(child_); }
225  size_t getRankOfChild() const { return rankOfChild_; }
226 
227  ParenthoodInfo& getInfo() const { return info_; }
229 
231 
235  Parenthood* getPreviousParent() const
236  {
237  ocra_assert(rankOfParent_ < child_.parents_.size() && "rankOfParent_ >= child_->parents_.size() should never happen");
238  ocra_assert(*(child_.parents_.begin() + rankOfParent_) == this && "Class invariant broken: parenthood not in the expected place in child's parents");
239 
240  if(!rankOfParent_)
241  return 0x0;
242  return child_.parents_[rankOfParent_ - 1];
243  }
244 
245  Parenthood* getNextParent() const
246  {
247  ocra_assert(rankOfParent_ < child_.parents_.size() && "rankOfParent_ >= child_->parents_.size() should never happen");
248  ocra_assert(*(child_.parents_.begin() + rankOfParent_) == this && "Class invariant broken: parenthood not in the expected place in child's parents");
249 
250  size_t rankOfNextParent = rankOfParent_ + 1;
251  if(rankOfNextParent >= child_.parents_.size())
252  return 0x0;
253  return child_.parents_[rankOfNextParent];
254  }
256 
258  Parenthood* getPreviousChild() const
260  {
261  ocra_assert(rankOfChild_ < parent_.children_.size() && "rankOfChild_ >= parent_->children_.size() should never happen");
262  ocra_assert(*(parent_.children_.begin() + rankOfChild_) == this && "Class invariant broken: parenthood not in the expected place in parent's children");
263 
264  if(!rankOfChild_)
265  return 0x0;
266  return parent_.children_[rankOfChild_ - 1];
267  }
268 
269  Parenthood* getNextChild() const
270  {
271  ocra_assert(rankOfChild_ < parent_.children_.size() && "rankOfChild_ >= parent_->children_.size() should never happen");
272  ocra_assert(*(parent_.children_.begin() + rankOfChild_) == this && "Class invariant broken: parenthood not in the expected place in parent's children");
273 
274  size_t rankOfNextChild = rankOfChild_ + 1;
275  if(rankOfNextChild >= parent_.children_.size())
276  return 0x0;
277  return parent_.children_[rankOfNextChild];
278  }
280 
281  public:
283 
300  struct parentIs
301  {
302  bool operator()(const parenthood_t* p) const { ocra_assert(p && "null pointer refused here"); return &p->getParent() == parent_; }
303  parentIs(const parent_t* parent): parent_(parent) {}
304  const parent_t* parent_;
305  };
306 
307  struct childIs
308  {
309  bool operator()(const parenthood_t* p) const { ocra_assert(p && "null pointer refused here"); return &p->getChild() == child_; }
310  childIs(const component_t* child): child_(child) {}
311  const component_t* child_;
312  };
314 
315  private:
316  // The state of a parenthood is represented by which instances are the child and parent, and by
317  // their ranks. The states of the child and parent as well as the additional info are nor part of
318  // the parenthood's state and are therefore mutable.
319  // Note that the only methods which can change the state of a parenthood are decreaseRankOfChild
320  // and decreaseRankOfParent, which are private and only accessible in ocra::detach. All other methods
321  // will preserve the state of the class.
322 
323  /*mutable*/ parent_t& parent_;
324  /*mutable*/ component_t& child_;
325  size_t rankOfParent_;
326  size_t rankOfChild_;
327  mutable ParenthoodInfo info_;
328 
329  private: // enforce preconditions
330  typedef boost::is_base_of<ComponentDerived, CompositeDerived>
331  ComponentDerived_must_be_base_of_CompositeDerived;
332 
333  typedef boost::is_convertible<CompositeDerived*, ComponentDerived*>
334  CompositeDerived_must_publicly_derive_ComponentDerived;
335 
336  typedef boost::has_nothrow_default_constructor<ParenthoodInfo>
337  ParenthoodInfo_must_have_default_nothrow_constructor;
338 
340 
341  typedef boost::is_base_of<component_base_t_, ComponentDerived>
342  component_base_t_must_be_base_of_ComponentDerived;
343 
344  typedef boost::is_convertible<ComponentDerived*, component_base_t_*>
345  ComponentDerived_must_publicly_derive_component_base_t_;
346 
348 
349  typedef boost::is_base_of<composite_base_t_, CompositeDerived>
350  composite_base_t_must_be_base_of_CompositeDerived;
351 
352  typedef boost::is_convertible<CompositeDerived*, composite_base_t_*>
353  CompositeDerived_must_publicly_derive_composite_base_t_;
354 
355  BOOST_STATIC_ASSERT( ComponentDerived_must_be_base_of_CompositeDerived ::value );
356  BOOST_STATIC_ASSERT( CompositeDerived_must_publicly_derive_ComponentDerived ::value );
357  //BOOST_STATIC_ASSERT( ParenthoodInfo_must_have_default_nothrow_constructor ::value );
358  BOOST_STATIC_ASSERT( component_base_t_must_be_base_of_ComponentDerived ::value );
359  BOOST_STATIC_ASSERT( ComponentDerived_must_publicly_derive_component_base_t_ ::value );
360  BOOST_STATIC_ASSERT( composite_base_t_must_be_base_of_CompositeDerived ::value );
361  BOOST_STATIC_ASSERT( CompositeDerived_must_publicly_derive_composite_base_t_ ::value );
362  };
363 
364 
365  // ------------------------------------------------------------
366  // --- COMPONENT ----------------------------------------------
367  // ------------------------------------------------------------
368 
370 
450  template<class ComponentDerived, class CompositeDerived, class ParenthoodInfo = NoInfo>
451  class Component
452  {
453  public:
455  typedef ComponentDerived component_t;
457  typedef CompositeDerived parent_t;
459  typedef typename std::vector<parenthood_t*>::const_iterator const_iterator;
460  typedef typename std::vector<parenthood_t*>::iterator iterator;
462 
463  public:
465  size_t getNumParenthoods() const { return parents_.size(); }
467  const parenthood_t& getParenthood(size_t i) const { return *parents_[i]; }
469 
471  const_iterator parents_begin() const { return parents_.begin(); }
473  iterator parents_begin() { return parents_.begin(); }
474 
475  const_iterator parents_end() const { return parents_.end(); }
476  iterator parents_end() { return parents_.end(); }
478 
480 
485  int isDescendantOf(const CompositeDerived& node) const { return isDescendantOf(node, 1); }
486  int isDescendantOf(const ComponentDerived& node) const { return node.isAncestorOf(*static_cast<const ComponentDerived*>(this)); }
488 
489  bool isChildOf(const CompositeDerived& node)
490  {
491  for(const_iterator it = parents_begin(); it != parents_end(); ++it)
492  if(&(*it)->getParent() == &node)
493  return true;
494  return false;
495  }
496 
497  void printTree(std::ostream& os) { printSubTree(0, os); }
498 
499  // --- To implement in CompositeDerived and LeafDerived -------
500  public:
502  /*
503  If the object is not a ancestor of node, returns 0. If it is a parent of node, returns 1.
504  If it is a grand-parent, returns 2, and so on...
505  You must overload this method in the two concrete classes that derive Leaf and Composite (see the
506  documentation of the class). Let's call these classes MyLeaf and MyComposite.
507  - MyComposite::isAncesterOf must implement the behavior just described. simple way to do it is to forward
508  the call to Composite::isAncestorOf_impl, as shown in the example in the class documentation.
509  - MyLeaf::isAncesterOf must always return 0.
510  \sa class Component.
511  */
512  virtual int isAncestorOf(const ComponentDerived& node) const = 0;
513 
515 
519  virtual void printSubTree(int depth, std::ostream& os) const = 0;
520 
522 
527  virtual void printNode(int depth, std::ostream& os) const = 0;
528 
529  // --- To overload if derived class (optional) ----------------
530  protected:
532 
538  virtual void onAttachedParent(const parenthood_t& parent) {}
539  virtual void onDetachedParent(const parenthood_t& parent) {}
541 
542  protected:
544 
548  Component(): componentBeingDestroyed_(false) // this boolean is to avoid CRTP virtual calls in the destructor.
549  {}
550 
552  {
553  componentBeingDestroyed_ = true; // therefore, no (CRTP) virtual call is possible!
554  while(parents_.size())
555  parents_.back()->getParent().Composite<ComponentDerived, CompositeDerived, ParenthoodInfo>::remove(*static_cast<ComponentDerived*>(this));
556  }
558 
559  private:
567  int isDescendantOf(const CompositeDerived& node, int level) const
568  {
569  int result = 0;
570 
571  for(size_t i = 0; !result && (i < parents_.size()); ++i)
572  {
573  const parent_t& parent = parents_[i]->getParent();
574  if(&node == &parent)
575  return level;
576 
577  result = parent.isDescendantOf(node, level + 1);
578  }
579 
580  return result;
581  }
582 
584  void onAttachedParentI(const parenthood_t& parent)
586  {
587  if(!componentBeingDestroyed_) // If entered destructor, do not forward the call to the derived class (already destructed!).
588  onAttachedParent(parent);
589  }
590 
591  void onDetachedParentI(const parenthood_t& parent)
592  {
593  if(!componentBeingDestroyed_)
594  onDetachedParent(parent);
595  }
597 
598  private:
599  std::vector<parenthood_t*> parents_;
600  bool componentBeingDestroyed_;
601 
602  // http://stackoverflow.com/questions/392120/why-cant-i-declare-a-friend-through-a-typedef
603  // friend class parenthood_t; // Rather make the mediator a friend rather than open the internals!
604  friend class Parenthood<ComponentDerived, CompositeDerived, ParenthoodInfo>;
605  };
606 
607 
608  // ------------------------------------------------------------
609  // --- COMPOSITE ----------------------------------------------
610  // ------------------------------------------------------------
611 
613 
636  template<class ComponentDerived, class CompositeDerived, class ParenthoodInfo = NoInfo>
637  class Composite
638  {
639  private:
643  typedef typename std::vector<parenthood_t_*>::const_iterator const_iterator_;
644  typedef typename std::vector<parenthood_t_*>::iterator iterator_;
645 
646  public:
647  bool isParentOf(const ComponentDerived& node)
648  {
649  for(const_iterator_ it = children_begin(); it != children_end(); ++it)
650  if(&(*it)->getChild() == &node)
651  return true;
652  return false;
653  }
654 
656  size_t getNumChildhoods() const { return children_.size(); }
658  const parenthood_t_& getChildhood(size_t i) const { return *children_[i]; }
660 
662  const_iterator_ children_begin() const { return children_.begin(); }
664  iterator_ children_begin() { return children_.begin(); }
665 
666  const_iterator_ children_end() const { return children_.end(); }
667  iterator_ children_end() { return children_.end(); }
669 
671 
677  virtual CompositeDerived& add(ComponentDerived& child) { attach(child); return *static_cast<CompositeDerived*>(this); }
678  virtual CompositeDerived& remove(ComponentDerived& child) { detach(child); return *static_cast<CompositeDerived*>(this); }
680 
681  protected:
683 
689  virtual void onAttachedChild(const parenthood_t_& child) {}
690  virtual void onDetachedChild(const parenthood_t_& child) {}
692 
693  protected:
694  Composite(): compositeBeingDestroyed_(false) // see Component for an explanation about this bool
695  {}
696 
698  {
699  compositeBeingDestroyed_ = true;
700  while(children_.size())
701  detach(children_.back()->getChild());
702  }
703 
704  protected:
706  void attach(ComponentDerived& child)
707  {
708  new parenthood_t_(*static_cast<CompositeDerived*>(this), child);
709  }
710 
712  void detach(ComponentDerived& child)
713  {
714  typename std::vector<parenthood_t_*>::iterator itParent =
715  std::find_if(child.parents_begin(), child.parents_end(), typename parenthood_t_::parentIs(static_cast<CompositeDerived*>(this)));
716 
717  if(itParent == child.parents_end())
718  throw std::runtime_error("[ocra::Composite::detach]: parent not found in child's parents... Are the nodes really bound together?");
719 
720  delete *itParent;
721  }
722 
723  int isAncestorOf_impl(const ComponentDerived& node) const { return node.isDescendantOf(*static_cast<const CompositeDerived*>(this)); }
724 
725  void printTree_impl(int depth, std::ostream& os) const
726  {
727  static_cast<const CompositeDerived*>(this)->printNode(depth, os);
728  for(size_t i = 0; i < children_.size(); ++i)
729  static_cast<ComponentDerived*>(&children_[i]->getChild())->printSubTree(depth + 1, os);
730  }
731 
732  private:
734  void onAttachedChildI(const parenthood_t_& child)
736  {
737  if(!compositeBeingDestroyed_)
738  onAttachedChild(child);
739  }
740 
741  void onDetachedChildI(const parenthood_t_& child)
742  {
743  if(!compositeBeingDestroyed_)
744  onDetachedChild(child);
745  }
747 
748  private:
749  std::vector<parenthood_t_*> children_;
750  bool compositeBeingDestroyed_;
751 
752  // see line 603 (why-cant-i-declare-a-friend-through-a-typedef)
753  friend class Parenthood<ComponentDerived, CompositeDerived, ParenthoodInfo>;
754  };
755 
756 
757  // ------------------------------------------------------------
758  // --- LEAF ---------------------------------------------------
759  // ------------------------------------------------------------
760 
762 
773  template<class LeafDerived>
774  class Leaf
775  {
776  public:
777  typedef LeafDerived leaf_t;
778 
779  protected:
781  {
782  // enforce preconditions
783  typedef Leaf<LeafDerived> leaf_base_t_;
784 
785  typedef boost::is_base_of<leaf_base_t_, LeafDerived>
786  leaf_base_t_must_be_base_of_LeafDerived;
787 
788  typedef boost::is_convertible<LeafDerived*, leaf_base_t_*>
789  LeafDerived_must_publicly_derive_leaf_base_t_;
790 
791  BOOST_STATIC_ASSERT( leaf_base_t_must_be_base_of_LeafDerived ::value );
792  BOOST_STATIC_ASSERT( LeafDerived_must_publicly_derive_leaf_base_t_ ::value );
793  }
794 
795  ~Leaf() {}
796 
797  void printTree_impl(int depth, std::ostream& os) const
798  {
799  static_cast<const LeafDerived*>(this)->printNode(depth, os);
800  }
801  };
802 }
803 
804 #endif // _OCRA_COMPOSITE_H_
805 
806 // cmake:sourcegroup=utils
childIs(const component_t *child)
Definition: Composite.h:310
Parenthood< ComponentDerived, CompositeDerived, ParenthoodInfo > parenthood_t
Definition: Composite.h:98
int isDescendantOf(const CompositeDerived &node) const
Returns the number of levels that separates the component from a potential parent.
Definition: Composite.h:485
virtual void onDetachedParent(const parenthood_t &parent)
Definition: Composite.h:539
void detach(ComponentDerived &child)
Erases a Parenthood bond between a Composite and a Component.
Definition: Composite.h:712
std::vector< parenthood_t * >::const_iterator const_iterator
Definition: Composite.h:459
Parenthood * getNextParent() const
Definition: Composite.h:245
int isAncestorOf_impl(const ComponentDerived &node) const
Definition: Composite.h:723
CompositeDerived parent_t
Definition: Composite.h:100
iterator_ children_begin()
Definition: Composite.h:664
Empty information block to attach to a parenthood relationship between a Composite and a Component...
Definition: Composite.h:45
bool operator()(const parenthood_t *p) const
Definition: Composite.h:309
const_iterator parents_end() const
Definition: Composite.h:475
void printTree_impl(int depth, std::ostream &os) const
Definition: Composite.h:797
CompositeDerived & getParent() const
Access to parenthood info, parent, child and their ranks, see constructor postconditions and class de...
Definition: Composite.h:221
ComponentDerived component_t
Definition: Composite.h:99
size_t getRankOfChild() const
Definition: Composite.h:225
virtual void onDetachedChild(const parenthood_t_ &child)
Definition: Composite.h:690
Parenthood * getPreviousParent() const
These methods return the parent of this->getChild() at position this->getRankOfParent()-1 (+1 respect...
Definition: Composite.h:235
const parenthood_t_ & getChildhood(size_t i) const
Definition: Composite.h:658
bool operator()(const parenthood_t *p) const
Definition: Composite.h:302
const parent_t * parent_
Definition: Composite.h:304
Optimization-based Robot Controller namespace. a library of classes to write and solve optimization p...
virtual void onAttachedParent(const parenthood_t &parent)
Default implementation of the callbacks, to overload in class ComponentDerived.
Definition: Composite.h:538
void attach(ComponentDerived &child)
Attaches a Component to a Composite by simply creating a Parenthood bond between them.
Definition: Composite.h:706
iterator parents_begin()
Definition: Composite.h:473
bool isParentOf(const ComponentDerived &node)
Definition: Composite.h:647
Base class for the Composite class of the Composite pattern.
Definition: Composite.h:38
Parenthood< ComponentDerived, CompositeDerived, ParenthoodInfo > parenthood_t
Definition: Composite.h:458
virtual void onAttachedChild(const parenthood_t_ &child)
Default implementation of the callbacks, to overload in the private part of class CompositeDerived...
Definition: Composite.h:689
ComponentDerived component_t
Inherited typedefs.
Definition: Composite.h:456
size_t getRankOfParent() const
Definition: Composite.h:222
Stores information about a Parent/Child relationship in the Composite design pattern.
Definition: Composite.h:94
CompositeDerived parent_t
Definition: Composite.h:457
int isDescendantOf(const ComponentDerived &node) const
Definition: Composite.h:486
const parenthood_t & getParenthood(size_t i) const
Definition: Composite.h:467
Parenthood * getNextChild() const
Definition: Composite.h:269
LeafDerived leaf_t
Definition: Composite.h:777
Base class for the Component class of the Composite pattern.
Definition: Composite.h:37
ParenthoodInfo & getInfo() const
Definition: Composite.h:227
Base class for the Leaf class of the Composite pattern.
Definition: Composite.h:774
std::vector< parenthood_t * >::iterator iterator
Definition: Composite.h:460
iterator_ children_end()
Definition: Composite.h:667
parentIs(const parent_t *parent)
Definition: Composite.h:303
iterator parents_end()
Definition: Composite.h:476
void printTree(std::ostream &os)
Definition: Composite.h:497
ComponentDerived & getChild() const
Definition: Composite.h:224
bool isChildOf(const CompositeDerived &node)
Definition: Composite.h:489
#define ocra_assert(ocra_expression)
Definition: ocra_assert.h:45
const_iterator_ children_end() const
Definition: Composite.h:666
virtual CompositeDerived & add(ComponentDerived &child)
Append and detach a child.
Definition: Composite.h:677
const component_t * child_
Definition: Composite.h:311
void printTree_impl(int depth, std::ostream &os) const
Definition: Composite.h:725
Functors to locate a parent or a child.
Definition: Composite.h:300