klao@225: // -*- c++ -*- // klao@225: klao@225: /** klao@225: * klao@225: * Class for representing paths in graphs. klao@225: * klao@225: */ klao@225: klao@225: #ifndef HUGO_PATH_H klao@225: #define HUGO_PATH_H klao@225: klao@225: #include klao@226: #include klao@225: klao@225: #include klao@225: klao@225: namespace hugo { klao@225: klao@225: /* Ennek az allocatorosdinak sokkal jobban utana kene nezni a hasznalata klao@225: elott. Eleg bonyinak nez ki, ahogyan azokat az STL-ben hasznaljak. */ klao@225: klao@225: template klao@225: class Path { klao@225: klao@225: public: klao@225: typedef typename Graph::Edge GraphEdge; klao@225: typedef typename Graph::Node GraphNode; klao@225: class NodeIt; klao@225: class EdgeIt; klao@225: klao@225: protected: klao@225: Graph& G; klao@225: // FIXME: ehelyett eleg lenne tarolni ket boolt: a ket szelso el klao@225: // iranyitasat: klao@225: GraphNode _first, _last; klao@225: typedef std::deque Container; klao@225: Container edges; klao@225: klao@225: public: klao@225: klao@225: Path(Graph &_G) : G(_G), _first(INVALID), _last(INVALID) {} klao@225: klao@226: /// Subpath defined by two nodes. klao@226: /// Nodes may be in reversed order, then klao@226: /// we contstruct the reversed path. klao@226: Path(const Path &P, const NodeIt &a, const NodeIt &b); klao@226: /// Subpath defined by two edges. Contains edges in [a,b) klao@226: /// It is an error if the two edges are not in order! klao@226: Path(const Path &P, const EdgeIt &a, const EdgeIt &b); klao@225: klao@225: size_t length() const { return edges.size(); } klao@225: GraphNode from() const { return _first; } klao@225: GraphNode to() const { return _last; } klao@225: klao@225: NodeIt& first(NodeIt &n) const { return nth(n, 0); } klao@225: EdgeIt& first(EdgeIt &e) const { return nth(e, 0); } klao@225: template klao@225: It first() const { klao@225: It e; klao@225: first(e); klao@225: return e; klao@225: } klao@225: klao@225: NodeIt& nth(NodeIt &, size_t) const; klao@225: EdgeIt& nth(EdgeIt &, size_t) const; klao@225: template klao@225: It nth(size_t n) const { klao@225: It e; klao@225: nth(e, n); klao@225: return e; klao@225: } klao@225: klao@225: bool valid(const NodeIt &n) const { return n.idx <= length(); } klao@225: bool valid(const EdgeIt &e) const { return e.it < edges.end(); } klao@225: klao@225: bool isForward(const EdgeIt &e) const { return e.forw; } klao@225: klao@226: /// index of a node on the path. Returns length+2 for the invalid NodeIt klao@226: int index(const NodeIt &n) const { return n.idx; } klao@226: /// index of an edge on the path. Returns length+1 for the invalid EdgeIt klao@226: int index(const EdgeIt &e) const { return e.it - edges.begin(); } klao@226: klao@225: EdgeIt& next(EdgeIt &e) const; klao@225: NodeIt& next(NodeIt &n) const; klao@225: template klao@225: It getNext(It it) const { klao@225: It tmp(it); return next(tmp); klao@225: } klao@225: klao@225: // A path is constructed using the following four functions. klao@225: // They return false if the requested operation is inconsistent klao@225: // with the path constructed so far. klao@225: // If your path has only one edge you MUST set either "from" or "to"! klao@225: // So you probably SHOULD call it in any case to be safe (and check the klao@225: // returned value to check if your path is consistent with your idea). klao@225: bool pushFront(const GraphEdge &e); klao@225: bool pushBack(const GraphEdge &e); klao@225: bool setFrom(const GraphNode &n); klao@225: bool setTo(const GraphNode &n); klao@225: klao@225: // WARNING: these two functions return the head/tail of an edge with klao@225: // respect to the direction of the path! klao@225: // So G.head(P.graphEdge(e)) == P.graphNode(P.head(e)) holds only if klao@225: // P.forward(e) is true (or the edge is a loop)! klao@225: NodeIt head(const EdgeIt& e) const; klao@225: NodeIt tail(const EdgeIt& e) const; klao@225: klao@225: // FIXME: ezeknek valami jobb nev kellene!!! klao@225: GraphEdge graphEdge(const EdgeIt& e) const; klao@225: GraphNode graphNode(const NodeIt& n) const; klao@225: klao@225: klao@225: /*** Iterator classes ***/ klao@225: class EdgeIt { klao@225: friend class Path; klao@225: klao@225: typename Container::const_iterator it; klao@225: bool forw; klao@225: public: klao@225: // FIXME: jarna neki ilyen is... klao@225: // EdgeIt(Invalid); klao@225: klao@225: bool forward() const { return forw; } klao@225: klao@225: bool operator==(const EdgeIt& e) const { return it==e.it; } klao@225: bool operator!=(const EdgeIt& e) const { return it!=e.it; } klao@225: bool operator<(const EdgeIt& e) const { return it klao@225: typename Path::EdgeIt& klao@225: Path::next(Path::EdgeIt &e) const { klao@225: if( e.it == edges.end() ) klao@225: return e; klao@225: klao@225: GraphNode common_node = ( e.forw ? G.head(*e.it) : G.tail(*e.it) ); klao@225: ++e.it; klao@225: klao@225: // Invalid edgeit is always forward :) klao@225: if( e.it == edges.end() ) { klao@225: e.forw = true; klao@225: return e; klao@225: } klao@225: klao@225: e.forw = ( G.tail(*e.it) == common_node ); klao@225: return e; klao@225: } klao@225: klao@225: template klao@225: typename Path::NodeIt& Path::next(NodeIt &n) const { klao@225: if( n.idx >= length() ) { klao@225: // FIXME: invalid klao@225: n.idx = length()+1; klao@225: return n; klao@225: } klao@225: klao@225: klao@225: GraphNode next_node = ( n.tail ? G.head(edges[n.idx]) : klao@225: G.tail(edges[n.idx]) ); klao@225: ++n.idx; klao@225: if( n.idx < length() ) { klao@225: n.tail = ( next_node == G.tail(edges[n.idx]) ); klao@225: } klao@225: else { klao@225: n.tail = true; klao@225: } klao@225: klao@225: return n; klao@225: } klao@225: klao@225: template klao@225: bool Path::edgeIncident(const GraphEdge &e, const GraphNode &a, klao@225: GraphNode &b) { klao@225: if( G.tail(e) == a ) { klao@225: b=G.head(e); klao@225: return true; klao@225: } klao@225: if( G.head(e) == a ) { klao@225: b=G.tail(e); klao@225: return true; klao@225: } klao@225: return false; klao@225: } klao@225: klao@225: template klao@225: bool Path::connectTwoEdges(const GraphEdge &e, klao@225: const GraphEdge &f) { klao@225: if( edgeIncident(f, G.tail(e), _last) ) { klao@225: _first = G.head(e); klao@225: return true; klao@225: } klao@225: if( edgeIncident(f, G.head(e), _last) ) { klao@225: _first = G.tail(e); klao@225: return true; klao@225: } klao@225: return false; klao@225: } klao@225: klao@225: template klao@225: bool Path::pushFront(const GraphEdge &e) { klao@225: if( G.valid(_first) ) { klao@225: if( edgeIncident(e, _first, _first) ) { klao@225: edges.push_front(e); klao@225: return true; klao@225: } klao@225: else klao@225: return false; klao@225: } klao@225: else if( length() < 1 || connectTwoEdges(e, edges[0]) ) { klao@225: edges.push_front(e); klao@225: return true; klao@225: } klao@225: else klao@225: return false; klao@225: } klao@225: klao@225: template klao@225: bool Path::pushBack(const GraphEdge &e) { klao@225: if( G.valid(_last) ) { klao@225: if( edgeIncident(e, _last, _last) ) { klao@225: edges.push_back(e); klao@225: return true; klao@225: } klao@225: else klao@225: return false; klao@225: } klao@225: else if( length() < 1 || connectTwoEdges(edges[0], e) ) { klao@225: edges.push_back(e); klao@225: return true; klao@225: } klao@225: else klao@225: return false; klao@225: } klao@225: klao@225: klao@225: template klao@225: bool Path::setFrom(const GraphNode &n) { klao@225: if( G.valid(_first) ) { klao@225: return _first == n; klao@225: } klao@225: else { klao@225: if( length() > 0) { klao@225: if( edgeIncident(edges[0], n, _last) ) { klao@225: _first = n; klao@225: return true; klao@225: } klao@225: else return false; klao@225: } klao@225: else { klao@225: _first = _last = n; klao@225: return true; klao@225: } klao@225: } klao@225: } klao@225: klao@225: template klao@225: bool Path::setTo(const GraphNode &n) { klao@225: if( G.valid(_last) ) { klao@225: return _last == n; klao@225: } klao@225: else { klao@225: if( length() > 0) { klao@225: if( edgeIncident(edges[0], n, _first) ) { klao@225: _last = n; klao@225: return true; klao@225: } klao@225: else return false; klao@225: } klao@225: else { klao@225: _first = _last = n; klao@225: return true; klao@225: } klao@225: } klao@225: } klao@225: klao@225: klao@225: template klao@225: typename Path::NodeIt klao@225: Path::tail(const EdgeIt& e) const { klao@225: NodeIt n; klao@225: klao@225: if( e.it == edges.end() ) { klao@225: // FIXME: invalid-> invalid klao@225: n.idx = length() + 1; klao@225: n.tail = true; klao@225: return n; klao@225: } klao@225: klao@225: n.idx = e.it-edges.begin(); klao@225: n.tail = e.forw; klao@226: return n; klao@225: } klao@225: klao@225: template klao@225: typename Path::NodeIt klao@225: Path::head(const EdgeIt& e) const { klao@225: if( e.it == edges.end()-1 ) { klao@225: return _last; klao@225: } klao@225: klao@225: EdgeIt next_edge = e; klao@225: next(next_edge); klao@225: return tail(next_edge); klao@225: } klao@225: klao@225: template klao@225: typename Path::GraphEdge klao@225: Path::graphEdge(const EdgeIt& e) const { klao@225: if( e.it != edges.end() ) { klao@225: return *e.it; klao@225: } klao@225: else { klao@225: return INVALID; klao@225: } klao@225: } klao@225: klao@225: template klao@225: typename Path::GraphNode klao@225: Path::graphNode(const NodeIt& n) const { klao@225: if( n.idx < length() ) { klao@225: return n.tail ? G.tail(edges[n.idx]) : G.head(edges[n.idx]); klao@225: } klao@225: else if( n.idx == length() ) { klao@225: return _last; klao@225: } klao@225: else { klao@225: return INVALID; klao@225: } klao@225: } klao@225: klao@225: template klao@225: typename Path::EdgeIt& Path::nth(EdgeIt &e, size_t k) const { klao@225: if( k<0 || k>=length() ) { klao@225: // FIXME: invalid EdgeIt klao@225: e.it = edges.end(); klao@225: e.forw = true; klao@225: return e; klao@225: } klao@225: klao@225: e.it = edges.begin()+k; klao@225: if(k==0) { klao@225: e.forw = ( G.tail(*e.it) == _first ); klao@225: } klao@225: else { klao@225: e.forw = ( G.tail(*e.it) == G.tail(edges[k-1]) || klao@225: G.tail(*e.it) == G.head(edges[k-1]) ); klao@225: } klao@225: return e; klao@225: } klao@225: klao@225: template klao@225: typename Path::NodeIt& Path::nth(NodeIt &n, size_t k) const { klao@225: if( k<0 || k>length() ) { klao@225: // FIXME: invalid NodeIt klao@225: n.idx = length()+1; klao@225: n.tail = true; klao@225: return n; klao@225: } klao@225: if( k==length() ) { klao@225: n.idx = length(); klao@225: n.tail = true; klao@225: return n; klao@225: } klao@225: n = tail(nth(k)); klao@225: return n; klao@225: } klao@225: klao@226: // Reszut konstruktorok: klao@226: klao@226: klao@226: template klao@226: Path::Path(const Path &P, const EdgeIt &a, const EdgeIt &b) : klao@226: G(P.G), edges(a.it, b.it) // WARNING: if b.it < a.it this will blow up! klao@226: { klao@226: if( G.valid(P._first) && a.it < P.edges.end() ) { klao@226: _first = ( a.forw ? G.tail(*a.it) : G.head(*a.it) ); klao@226: if( b.it < P.edges.end() ) { klao@226: _last = ( b.forw ? G.tail(*b.it) : G.head(*b.it) ); klao@226: } klao@226: else { klao@226: _last = P._last; klao@226: } klao@226: } klao@226: } klao@226: klao@226: template klao@226: Path::Path(const Path &P, const NodeIt &a, const NodeIt &b) : klao@226: G(P.G) klao@226: { klao@226: if( !P.valid(a) || !P.valid(b) ) klao@226: return; klao@226: klao@226: int ai = a.idx, bi = b.idx; klao@226: if( bi