src/hugo/path.h
author alpar
Wed, 22 Sep 2004 09:58:17 +0000
changeset 900 fc7bc2dacee5
parent 852 d50d89b86870
child 906 17f31d280385
permissions -rw-r--r--
'iff' changed to 'if and only if'
     1 // -*- c++ -*- //
     2 
     3 /**
     4 @defgroup paths Path Structures
     5 @ingroup datas
     6 \brief Path structures implemented in Hugo.
     7 
     8 Hugolib provides flexible data structures
     9 to work with paths.
    10 
    11 All of them have the same interface, especially they can be built or extended
    12 using a standard Builder subclass. This make is easy to have e.g. the Dijkstra
    13 algorithm to store its result in any kind of path structure.
    14 
    15 \sa hugo::skeleton::Path
    16 
    17 */
    18 
    19 ///\ingroup paths
    20 ///\file
    21 ///\brief Classes for representing paths in graphs.
    22 
    23 #ifndef HUGO_PATH_H
    24 #define HUGO_PATH_H
    25 
    26 #include <deque>
    27 #include <vector>
    28 #include <algorithm>
    29 
    30 #include <hugo/invalid.h>
    31 
    32 namespace hugo {
    33 
    34   /// \addtogroup paths
    35   /// @{
    36 
    37 
    38   //! \brief A structure for representing directed paths in a graph.
    39   //!
    40   //! A structure for representing directed path in a graph.
    41   //! \param Graph The graph type in which the path is.
    42   //! \param DM DebugMode, defaults to DefaultDebugMode.
    43   //!
    44   //! In a sense, the path can be treated as a graph, for is has \c NodeIt
    45   //! and \c EdgeIt with the same usage. These types converts to the \c Node
    46   //! and \c Edge of the original graph.
    47   //!
    48   //! \todo Thoroughfully check all the range and consistency tests.
    49   template<typename Graph>
    50   class DirPath {
    51   public:
    52     /// Edge type of the underlying graph.
    53     typedef typename Graph::Edge GraphEdge;
    54     /// Node type of the underlying graph.
    55     typedef typename Graph::Node GraphNode;
    56     class NodeIt;
    57     class EdgeIt;
    58 
    59   protected:
    60     const Graph *gr;
    61     typedef std::vector<GraphEdge> Container;
    62     Container edges;
    63 
    64   public:
    65 
    66     /// \param _G The graph in which the path is.
    67     ///
    68     DirPath(const Graph &_G) : gr(&_G) {}
    69 
    70     /// \brief Subpath constructor.
    71     ///
    72     /// Subpath defined by two nodes.
    73     /// \warning It is an error if the two edges are not in order!
    74     DirPath(const DirPath &P, const NodeIt &a, const NodeIt &b) {
    75       gr = P.gr;
    76       edges.insert(edges.end(), P.edges.begin()+a.idx, P.edges.begin()+b.idx);
    77     }
    78 
    79     /// \brief Subpath constructor.
    80     ///
    81     /// Subpath defined by two edges. Contains edges in [a,b)
    82     /// \warning It is an error if the two edges are not in order!
    83     DirPath(const DirPath &P, const EdgeIt &a, const EdgeIt &b) {
    84       gr = P.gr;
    85       edges.insert(edges.end(), P.edges.begin()+a.idx, P.edges.begin()+b.idx);
    86     }
    87 
    88     /// Length of the path.
    89     size_t length() const { return edges.size(); }
    90     /// Returns whether the path is empty.
    91     bool empty() const { return edges.empty(); }
    92 
    93     /// Resets the path to an empty path.
    94     void clear() { edges.clear(); }
    95 
    96     /// \brief Starting point of the path.
    97     ///
    98     /// Starting point of the path.
    99     /// Returns INVALID if the path is empty.
   100     GraphNode tail() const {
   101       return empty() ? INVALID : gr->tail(edges[0]);
   102     }
   103     /// \brief End point of the path.
   104     ///
   105     /// End point of the path.
   106     /// Returns INVALID if the path is empty.
   107     GraphNode head() const {
   108       return empty() ? INVALID : gr->head(edges[length()-1]);
   109     }
   110 
   111     /// \brief Initializes node or edge iterator to point to the first
   112     /// node or edge.
   113     ///
   114     /// \sa nth
   115     template<typename It>
   116     It& first(It &i) const { return i=It(*this); }
   117 
   118     /// \brief Initializes node iterator to point to the node of a given index.
   119     NodeIt& nth(NodeIt &i, int n) const {
   120       return i=NodeIt(*this, n);
   121     }
   122 
   123     /// \brief Initializes edge iterator to point to the edge of a given index.
   124     EdgeIt& nth(EdgeIt &i, int n) const {
   125       return i=EdgeIt(*this, n);
   126     }
   127 
   128     /// \brief Returns node iterator pointing to the head node of the
   129     /// given edge iterator.
   130     NodeIt head(const EdgeIt& e) const {
   131       return NodeIt(*this, e.idx+1);
   132     }
   133 
   134     /// \brief Returns node iterator pointing to the tail node of the
   135     /// given edge iterator.
   136     NodeIt tail(const EdgeIt& e) const {
   137       return NodeIt(*this, e.idx);
   138     }
   139 
   140 
   141     /* Iterator classes */
   142 
   143     /**
   144      * \brief Iterator class to iterate on the edges of the paths
   145      *
   146      * \ingroup paths
   147      * This class is used to iterate on the edges of the paths
   148      *
   149      * Of course it converts to Graph::Edge
   150      *
   151      */
   152     class EdgeIt {
   153       friend class DirPath;
   154 
   155       int idx;
   156       const DirPath *p;
   157     public:
   158       /// Default constructor
   159       EdgeIt() {}
   160       /// Invalid constructor
   161       EdgeIt(Invalid) : idx(-1), p(0) {}
   162       /// Constructor with starting point
   163       EdgeIt(const DirPath &_p, int _idx = 0) :
   164 	idx(_idx), p(&_p) { validate(); }
   165 
   166       ///Validity check
   167       bool valid() const { return idx!=-1; }
   168 
   169       ///Conversion to Graph::Edge
   170       operator GraphEdge () const {
   171 	return valid() ? p->edges[idx] : INVALID;
   172       }
   173 
   174       /// Next edge
   175       EdgeIt& operator++() { ++idx; validate(); return *this; }
   176 
   177       /// Comparison operator
   178       bool operator==(const EdgeIt& e) const { return idx==e.idx; }
   179       /// Comparison operator
   180       bool operator!=(const EdgeIt& e) const { return idx!=e.idx; }
   181       /// Comparison operator
   182       bool operator<(const EdgeIt& e) const { return idx<e.idx; }
   183 
   184     private:
   185       // FIXME: comparison between signed and unsigned...
   186       // Jo ez igy? Vagy esetleg legyen a length() int?
   187       void validate() { if( size_t(idx) >= p->length() ) idx=-1; }
   188     };
   189 
   190     /**
   191      * \brief Iterator class to iterate on the nodes of the paths
   192      *
   193      * \ingroup paths
   194      * This class is used to iterate on the nodes of the paths
   195      *
   196      * Of course it converts to Graph::Node
   197      *
   198      */
   199     class NodeIt {
   200       friend class DirPath;
   201 
   202       int idx;
   203       const DirPath *p;
   204     public:
   205       /// Default constructor
   206       NodeIt() {}
   207       /// Invalid constructor
   208       NodeIt(Invalid) : idx(-1), p(0) {}
   209       /// Constructor with starting point
   210       NodeIt(const DirPath &_p, int _idx = 0) :
   211 	idx(_idx), p(&_p) { validate(); }
   212 
   213       ///Validity check
   214       bool valid() const { return idx!=-1; }
   215 
   216       ///Conversion to Graph::Node
   217       operator const GraphNode& () const {
   218 	if(idx >= p->length())
   219 	  return p->head();
   220 	else if(idx >= 0)
   221 	  return p->gr->tail(p->edges[idx]);
   222 	else
   223 	  return INVALID;
   224       }
   225       /// Next node
   226       NodeIt& operator++() { ++idx; validate(); return *this; }
   227 
   228       /// Comparison operator
   229       bool operator==(const NodeIt& e) const { return idx==e.idx; }
   230       /// Comparison operator
   231       bool operator!=(const NodeIt& e) const { return idx!=e.idx; }
   232       /// Comparison operator
   233       bool operator<(const NodeIt& e) const { return idx<e.idx; }
   234 
   235     private:
   236       void validate() { if( size_t(idx) > p->length() ) idx=-1; }
   237     };
   238 
   239     friend class Builder;
   240 
   241     /**
   242      * \brief Class to build paths
   243      *
   244      * \ingroup paths
   245      * This class is used to fill a path with edges.
   246      *
   247      * You can push new edges to the front and to the back of the path in
   248      * arbitrary order then you should commit these changes to the graph.
   249      *
   250      * Fundamentally, for most "Paths" (classes fulfilling the
   251      * PathConcept) while the builder is active (after the first modifying
   252      * operation and until the commit()) the original Path is in a
   253      * "transitional" state (operations on it have undefined result). But
   254      * in the case of DirPath the original path remains unchanged until the
   255      * commit. However we don't recomend that you use this feature.
   256      */
   257     class Builder {
   258       DirPath &P;
   259       Container front, back;
   260 
   261     public:
   262       ///\param _P the path you want to fill in.
   263       ///
   264       Builder(DirPath &_P) : P(_P) {}
   265 
   266       /// Sets the starting node of the path.
   267 
   268       /// Sets the starting node of the path. Edge added to the path
   269       /// afterwards have to be incident to this node.
   270       /// It should be called if and only if
   271       /// the path is empty and before any call to
   272       /// \ref pushFront() or \ref pushBack()
   273       void setStartNode(const GraphNode &) {}
   274 
   275       ///Push a new edge to the front of the path
   276 
   277       ///Push a new edge to the front of the path.
   278       ///\sa setStartNode
   279       void pushFront(const GraphEdge& e) {
   280 	front.push_back(e);
   281       }
   282 
   283       ///Push a new edge to the back of the path
   284 
   285       ///Push a new edge to the back of the path.
   286       ///\sa setStartNode
   287       void pushBack(const GraphEdge& e) {
   288 	back.push_back(e);
   289       }
   290 
   291       ///Commit the changes to the path.
   292       void commit() {
   293 	if( !front.empty() || !back.empty() ) {
   294 	  Container tmp;
   295 	  tmp.reserve(front.size()+back.size()+P.length());
   296 	  tmp.insert(tmp.end(), front.rbegin(), front.rend());
   297 	  tmp.insert(tmp.end(), P.edges.begin(), P.edges.end());
   298 	  tmp.insert(tmp.end(), back.begin(), back.end());
   299 	  P.edges.swap(tmp);
   300 	  front.clear();
   301 	  back.clear();
   302 	}
   303       }
   304 
   305       ///Reserve storage for the builder in advance.
   306 
   307       ///If you know a reasonable upper bound of the number of the edges
   308       ///to add to the front, using this function you can speed up the building.
   309 
   310       void reserveFront(size_t r) {front.reserve(r);}
   311 
   312       ///Reserve storage for the builder in advance.
   313 
   314       ///If you know a reasonable upper bound of the number of the edges
   315       ///to add to the back, using this function you can speed up the building.
   316 
   317       void reserveBack(size_t r) {back.reserve(r);}
   318 
   319     private:
   320       bool empty() {
   321 	return front.empty() && back.empty() && P.empty();
   322       }
   323 
   324       GraphNode tail() const {
   325 	if( ! front.empty() )
   326 	  return P.gr->tail(front[front.size()-1]);
   327 	else if( ! P.empty() )
   328 	  return P.gr->tail(P.edges[0]);
   329 	else if( ! back.empty() )
   330 	  return P.gr->tail(back[0]);
   331 	else
   332 	  return INVALID;
   333       }
   334       GraphNode head() const {
   335 	if( ! back.empty() )
   336 	  return P.gr->head(back[back.size()-1]);
   337 	else if( ! P.empty() )
   338 	  return P.gr->head(P.edges[P.length()-1]);
   339 	else if( ! front.empty() )
   340 	  return P.gr->head(front[0]);
   341 	else
   342 	  return INVALID;
   343       }
   344 
   345     };
   346 
   347   };
   348 
   349 
   350 
   351 
   352 
   353 
   354 
   355 
   356 
   357 
   358   /**********************************************************************/
   359 
   360 
   361   //! \brief A structure for representing undirected path in a graph.
   362   //!
   363   //! A structure for representing undirected path in a graph. Ie. this is
   364   //! a path in a \e directed graph but the edges should not be directed
   365   //! forward.
   366   //!
   367   //! \param Graph The graph type in which the path is.
   368   //! \param DM DebugMode, defaults to DefaultDebugMode.
   369   //!
   370   //! In a sense, the path can be treated as a graph, for is has \c NodeIt
   371   //! and \c EdgeIt with the same usage. These types converts to the \c Node
   372   //! and \c Edge of the original graph.
   373   //!
   374   //! \todo Thoroughfully check all the range and consistency tests.
   375   template<typename Graph>
   376   class UndirPath {
   377   public:
   378     /// Edge type of the underlying graph.
   379     typedef typename Graph::Edge GraphEdge;
   380      /// Node type of the underlying graph.
   381    typedef typename Graph::Node GraphNode;
   382     class NodeIt;
   383     class EdgeIt;
   384 
   385   protected:
   386     const Graph *gr;
   387     typedef std::vector<GraphEdge> Container;
   388     Container edges;
   389 
   390   public:
   391 
   392     /// \param _G The graph in which the path is.
   393     ///
   394     UndirPath(const Graph &_G) : gr(&_G) {}
   395 
   396     /// \brief Subpath constructor.
   397     ///
   398     /// Subpath defined by two nodes.
   399     /// \warning It is an error if the two edges are not in order!
   400     UndirPath(const UndirPath &P, const NodeIt &a, const NodeIt &b) {
   401       gr = P.gr;
   402       edges.insert(edges.end(), P.edges.begin()+a.idx, P.edges.begin()+b.idx);
   403     }
   404 
   405     /// \brief Subpath constructor.
   406     ///
   407     /// Subpath defined by two edges. Contains edges in [a,b)
   408     /// \warning It is an error if the two edges are not in order!
   409     UndirPath(const UndirPath &P, const EdgeIt &a, const EdgeIt &b) {
   410       gr = P.gr;
   411       edges.insert(edges.end(), P.edges.begin()+a.idx, P.edges.begin()+b.idx);
   412     }
   413 
   414     /// Length of the path.
   415     size_t length() const { return edges.size(); }
   416     /// Returns whether the path is empty.
   417     bool empty() const { return edges.empty(); }
   418 
   419     /// Resets the path to an empty path.
   420     void clear() { edges.clear(); }
   421 
   422     /// \brief Starting point of the path.
   423     ///
   424     /// Starting point of the path.
   425     /// Returns INVALID if the path is empty.
   426     GraphNode tail() const {
   427       return empty() ? INVALID : gr->tail(edges[0]);
   428     }
   429     /// \brief End point of the path.
   430     ///
   431     /// End point of the path.
   432     /// Returns INVALID if the path is empty.
   433     GraphNode head() const {
   434       return empty() ? INVALID : gr->head(edges[length()-1]);
   435     }
   436 
   437     /// \brief Initializes node or edge iterator to point to the first
   438     /// node or edge.
   439     ///
   440     /// \sa nth
   441     template<typename It>
   442     It& first(It &i) const { return i=It(*this); }
   443 
   444     /// \brief Initializes node iterator to point to the node of a given index.
   445     NodeIt& nth(NodeIt &i, int n) const {
   446       return i=NodeIt(*this, n);
   447     }
   448 
   449     /// \brief Initializes edge iterator to point to the edge of a given index.
   450     EdgeIt& nth(EdgeIt &i, int n) const {
   451       return i=EdgeIt(*this, n);
   452     }
   453 
   454     /// Checks validity of a node or edge iterator.
   455     template<typename It>
   456     static
   457     bool valid(const It &i) { return i.valid(); }
   458 
   459     /// Steps the given node or edge iterator.
   460     template<typename It>
   461     static
   462     It& next(It &e) {
   463       return ++e;
   464     }
   465 
   466     /// \brief Returns node iterator pointing to the head node of the
   467     /// given edge iterator.
   468     NodeIt head(const EdgeIt& e) const {
   469       return NodeIt(*this, e.idx+1);
   470     }
   471 
   472     /// \brief Returns node iterator pointing to the tail node of the
   473     /// given edge iterator.
   474     NodeIt tail(const EdgeIt& e) const {
   475       return NodeIt(*this, e.idx);
   476     }
   477 
   478 
   479 
   480     /**
   481      * \brief Iterator class to iterate on the edges of the paths
   482      *
   483      * \ingroup paths
   484      * This class is used to iterate on the edges of the paths
   485      *
   486      * Of course it converts to Graph::Edge
   487      *
   488      * \todo Its interface differs from the standard edge iterator.
   489      * Yes, it shouldn't.
   490      */
   491     class EdgeIt {
   492       friend class UndirPath;
   493 
   494       int idx;
   495       const UndirPath *p;
   496     public:
   497       /// Default constructor
   498       EdgeIt() {}
   499       /// Invalid constructor
   500       EdgeIt(Invalid) : idx(-1), p(0) {}
   501       /// Constructor with starting point
   502       EdgeIt(const UndirPath &_p, int _idx = 0) :
   503 	idx(_idx), p(&_p) { validate(); }
   504 
   505       ///Validity check
   506       bool valid() const { return idx!=-1; }
   507 
   508       ///Conversion to Graph::Edge
   509       operator GraphEdge () const {
   510 	return valid() ? p->edges[idx] : INVALID;
   511       }
   512       /// Next edge
   513      EdgeIt& operator++() { ++idx; validate(); return *this; }
   514 
   515       /// Comparison operator
   516       bool operator==(const EdgeIt& e) const { return idx==e.idx; }
   517       /// Comparison operator
   518       bool operator!=(const EdgeIt& e) const { return idx!=e.idx; }
   519       /// Comparison operator
   520       bool operator<(const EdgeIt& e) const { return idx<e.idx; }
   521 
   522     private:
   523       // FIXME: comparison between signed and unsigned...
   524       // Jo ez igy? Vagy esetleg legyen a length() int?
   525       void validate() { if( size_t(idx) >= p->length() ) idx=-1; }
   526     };
   527 
   528     /**
   529      * \brief Iterator class to iterate on the nodes of the paths
   530      *
   531      * \ingroup paths
   532      * This class is used to iterate on the nodes of the paths
   533      *
   534      * Of course it converts to Graph::Node
   535      *
   536      * \todo Its interface differs from the standard node iterator.
   537      * Yes, it shouldn't.
   538      */
   539     class NodeIt {
   540       friend class UndirPath;
   541 
   542       int idx;
   543       const UndirPath *p;
   544     public:
   545       /// Default constructor
   546       NodeIt() {}
   547       /// Invalid constructor
   548       NodeIt(Invalid) : idx(-1), p(0) {}
   549       /// Constructor with starting point
   550       NodeIt(const UndirPath &_p, int _idx = 0) :
   551 	idx(_idx), p(&_p) { validate(); }
   552 
   553       ///Validity check
   554       bool valid() const { return idx!=-1; }
   555 
   556       ///Conversion to Graph::Node
   557       operator const GraphNode& () const {
   558 	if(idx >= p->length())
   559 	  return p->head();
   560 	else if(idx >= 0)
   561 	  return p->gr->tail(p->edges[idx]);
   562 	else
   563 	  return INVALID;
   564       }
   565       /// Next node
   566       NodeIt& operator++() { ++idx; validate(); return *this; }
   567 
   568       /// Comparison operator
   569       bool operator==(const NodeIt& e) const { return idx==e.idx; }
   570       /// Comparison operator
   571       bool operator!=(const NodeIt& e) const { return idx!=e.idx; }
   572        /// Comparison operator
   573      bool operator<(const NodeIt& e) const { return idx<e.idx; }
   574 
   575     private:
   576       void validate() { if( size_t(idx) > p->length() ) idx=-1; }
   577     };
   578 
   579     friend class Builder;
   580 
   581     /**
   582      * \brief Class to build paths
   583      *
   584      * \ingroup paths
   585      * This class is used to fill a path with edges.
   586      *
   587      * You can push new edges to the front and to the back of the path in
   588      * arbitrary order then you should commit these changes to the graph.
   589      *
   590      * Fundamentally, for most "Paths" (classes fulfilling the
   591      * PathConcept) while the builder is active (after the first modifying
   592      * operation and until the commit()) the original Path is in a
   593      * "transitional" state (operations ot it have undefined result). But
   594      * in the case of UndirPath the original path is unchanged until the
   595      * commit. However we don't recomend that you use this feature.
   596      */
   597     class Builder {
   598       UndirPath &P;
   599       Container front, back;
   600 
   601     public:
   602       ///\param _P the path you want to fill in.
   603       ///
   604       Builder(UndirPath &_P) : P(_P) {}
   605 
   606       /// Sets the starting node of the path.
   607 
   608       /// Sets the starting node of the path. Edge added to the path
   609       /// afterwards have to be incident to this node.
   610       /// It should be called if and only if
   611       /// the path is empty and before any call to
   612       /// \ref pushFront() or \ref pushBack()
   613       void setStartNode(const GraphNode &) {}
   614 
   615       ///Push a new edge to the front of the path
   616 
   617       ///Push a new edge to the front of the path.
   618       ///\sa setStartNode
   619       void pushFront(const GraphEdge& e) {
   620 	front.push_back(e);
   621       }
   622 
   623       ///Push a new edge to the back of the path
   624 
   625       ///Push a new edge to the back of the path.
   626       ///\sa setStartNode
   627       void pushBack(const GraphEdge& e) {
   628 	back.push_back(e);
   629       }
   630 
   631       ///Commit the changes to the path.
   632       void commit() {
   633 	if( !(front.empty() && back.empty()) ) {
   634 	  Container tmp;
   635 	  tmp.reserve(front.size()+back.size()+P.length());
   636 	  tmp.insert(tmp.end(), front.rbegin(), front.rend());
   637 	  tmp.insert(tmp.end(), P.edges.begin(), P.edges.end());
   638 	  tmp.insert(tmp.end(), back.begin(), back.end());
   639 	  P.edges.swap(tmp);
   640 	  front.clear();
   641 	  back.clear();
   642 	}
   643       }
   644 
   645 
   646       ///Reserve storage for the builder in advance.
   647 
   648       ///If you know a reasonable upper bound of the number of the edges
   649       ///to add to the front, using this function you can speed up the building.
   650 
   651       void reserveFront(size_t r) {front.reserve(r);}
   652 
   653       ///Reserve storage for the builder in advance.
   654 
   655       ///If you know a reasonable upper bound of the number of the edges
   656       ///to add to the back, using this function you can speed up the building.
   657 
   658       void reserveBack(size_t r) {back.reserve(r);}
   659 
   660     private:
   661       bool empty() {
   662 	return front.empty() && back.empty() && P.empty();
   663       }
   664 
   665       GraphNode tail() const {
   666 	if( ! front.empty() )
   667 	  return P.gr->tail(front[front.size()-1]);
   668 	else if( ! P.empty() )
   669 	  return P.gr->tail(P.edges[0]);
   670 	else if( ! back.empty() )
   671 	  return P.gr->tail(back[0]);
   672 	else
   673 	  return INVALID;
   674       }
   675       GraphNode head() const {
   676 	if( ! back.empty() )
   677 	  return P.gr->head(back[back.size()-1]);
   678 	else if( ! P.empty() )
   679 	  return P.gr->head(P.edges[P.length()-1]);
   680 	else if( ! front.empty() )
   681 	  return P.gr->head(front[0]);
   682 	else
   683 	  return INVALID;
   684       }
   685 
   686     };
   687 
   688   };
   689 
   690 
   691   ///@}
   692 
   693 } // namespace hugo
   694 
   695 #endif // HUGO_PATH_H