alpar@209: /* -*- mode: C++; indent-tabs-mode: nil; -*- alpar@39: * alpar@209: * This file is a part of LEMON, a generic C++ optimization library. alpar@39: * alpar@39: * Copyright (C) 2003-2008 alpar@39: * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport alpar@39: * (Egervary Research Group on Combinatorial Optimization, EGRES). alpar@39: * alpar@39: * Permission to use, modify and distribute this software is granted alpar@39: * provided that this copyright notice appears in all copies. For alpar@39: * precise terms see the accompanying LICENSE file. alpar@39: * alpar@39: * This software is provided "AS IS" with no warranty of any kind, alpar@39: * express or implied, and with no claim as to its suitability for any alpar@39: * purpose. alpar@39: * alpar@39: */ alpar@39: deba@57: #ifndef LEMON_LIST_GRAPH_H deba@57: #define LEMON_LIST_GRAPH_H deba@57: deba@57: ///\ingroup graphs deba@57: ///\file deba@57: ///\brief ListDigraph, ListGraph classes. deba@57: deba@220: #include deba@220: #include deba@57: #include deba@57: deba@57: #include deba@57: #include deba@57: deba@57: namespace lemon { deba@57: deba@57: class ListDigraphBase { deba@57: deba@57: protected: deba@57: struct NodeT { deba@57: int first_in, first_out; deba@57: int prev, next; deba@57: }; alpar@209: deba@57: struct ArcT { deba@57: int target, source; deba@57: int prev_in, prev_out; deba@57: int next_in, next_out; deba@57: }; deba@57: deba@57: std::vector nodes; deba@57: deba@57: int first_node; deba@57: deba@57: int first_free_node; deba@57: deba@57: std::vector arcs; deba@57: deba@57: int first_free_arc; alpar@209: deba@57: public: alpar@209: deba@57: typedef ListDigraphBase Digraph; alpar@209: deba@57: class Node { deba@57: friend class ListDigraphBase; deba@57: protected: deba@57: deba@57: int id; deba@57: explicit Node(int pid) { id = pid;} deba@57: deba@57: public: deba@57: Node() {} deba@57: Node (Invalid) { id = -1; } deba@57: bool operator==(const Node& node) const {return id == node.id;} deba@57: bool operator!=(const Node& node) const {return id != node.id;} deba@57: bool operator<(const Node& node) const {return id < node.id;} deba@57: }; deba@57: deba@57: class Arc { deba@57: friend class ListDigraphBase; deba@57: protected: deba@57: deba@57: int id; deba@57: explicit Arc(int pid) { id = pid;} deba@57: deba@57: public: deba@57: Arc() {} deba@57: Arc (Invalid) { id = -1; } deba@57: bool operator==(const Arc& arc) const {return id == arc.id;} deba@57: bool operator!=(const Arc& arc) const {return id != arc.id;} deba@57: bool operator<(const Arc& arc) const {return id < arc.id;} deba@57: }; deba@57: deba@57: deba@57: deba@57: ListDigraphBase() deba@57: : nodes(), first_node(-1), alpar@209: first_free_node(-1), arcs(), first_free_arc(-1) {} deba@57: alpar@209: alpar@209: int maxNodeId() const { return nodes.size()-1; } deba@57: int maxArcId() const { return arcs.size()-1; } deba@57: deba@57: Node source(Arc e) const { return Node(arcs[e.id].source); } deba@57: Node target(Arc e) const { return Node(arcs[e.id].target); } deba@57: deba@57: alpar@209: void first(Node& node) const { deba@57: node.id = first_node; deba@57: } deba@57: deba@57: void next(Node& node) const { deba@57: node.id = nodes[node.id].next; deba@57: } deba@57: deba@57: alpar@209: void first(Arc& arc) const { deba@57: int n; alpar@209: for(n = first_node; alpar@209: n!=-1 && nodes[n].first_in == -1; alpar@209: n = nodes[n].next) {} kpeter@73: arc.id = (n == -1) ? -1 : nodes[n].first_in; deba@57: } deba@57: deba@57: void next(Arc& arc) const { deba@57: if (arcs[arc.id].next_in != -1) { alpar@209: arc.id = arcs[arc.id].next_in; deba@57: } else { alpar@209: int n; alpar@209: for(n = nodes[arcs[arc.id].target].next; alpar@209: n!=-1 && nodes[n].first_in == -1; alpar@209: n = nodes[n].next) {} alpar@209: arc.id = (n == -1) ? -1 : nodes[n].first_in; alpar@209: } deba@57: } deba@57: deba@57: void firstOut(Arc &e, const Node& v) const { deba@57: e.id = nodes[v.id].first_out; deba@57: } deba@57: void nextOut(Arc &e) const { deba@57: e.id=arcs[e.id].next_out; deba@57: } deba@57: deba@57: void firstIn(Arc &e, const Node& v) const { deba@57: e.id = nodes[v.id].first_in; deba@57: } deba@57: void nextIn(Arc &e) const { deba@57: e.id=arcs[e.id].next_in; deba@57: } deba@57: alpar@209: deba@57: static int id(Node v) { return v.id; } deba@57: static int id(Arc e) { return e.id; } deba@57: deba@57: static Node nodeFromId(int id) { return Node(id);} deba@57: static Arc arcFromId(int id) { return Arc(id);} deba@57: alpar@209: bool valid(Node n) const { alpar@209: return n.id >= 0 && n.id < static_cast(nodes.size()) && alpar@209: nodes[n.id].prev != -2; deba@149: } deba@149: alpar@209: bool valid(Arc a) const { alpar@209: return a.id >= 0 && a.id < static_cast(arcs.size()) && alpar@209: arcs[a.id].prev_in != -2; deba@149: } deba@149: alpar@209: Node addNode() { deba@57: int n; alpar@209: deba@57: if(first_free_node==-1) { alpar@209: n = nodes.size(); alpar@209: nodes.push_back(NodeT()); deba@57: } else { alpar@209: n = first_free_node; alpar@209: first_free_node = nodes[n].next; deba@57: } alpar@209: deba@57: nodes[n].next = first_node; deba@57: if(first_node != -1) nodes[first_node].prev = n; deba@57: first_node = n; deba@57: nodes[n].prev = -1; alpar@209: deba@57: nodes[n].first_in = nodes[n].first_out = -1; alpar@209: deba@57: return Node(n); deba@57: } alpar@209: deba@57: Arc addArc(Node u, Node v) { alpar@209: int n; deba@57: deba@57: if (first_free_arc == -1) { alpar@209: n = arcs.size(); alpar@209: arcs.push_back(ArcT()); deba@57: } else { alpar@209: n = first_free_arc; alpar@209: first_free_arc = arcs[n].next_in; deba@57: } alpar@209: alpar@209: arcs[n].source = u.id; deba@57: arcs[n].target = v.id; deba@57: deba@57: arcs[n].next_out = nodes[u.id].first_out; deba@57: if(nodes[u.id].first_out != -1) { alpar@209: arcs[nodes[u.id].first_out].prev_out = n; deba@57: } alpar@209: deba@57: arcs[n].next_in = nodes[v.id].first_in; deba@57: if(nodes[v.id].first_in != -1) { alpar@209: arcs[nodes[v.id].first_in].prev_in = n; deba@57: } alpar@209: deba@57: arcs[n].prev_in = arcs[n].prev_out = -1; alpar@209: deba@57: nodes[u.id].first_out = nodes[v.id].first_in = n; deba@57: deba@57: return Arc(n); deba@57: } alpar@209: deba@57: void erase(const Node& node) { deba@57: int n = node.id; alpar@209: deba@57: if(nodes[n].next != -1) { alpar@209: nodes[nodes[n].next].prev = nodes[n].prev; deba@57: } alpar@209: deba@57: if(nodes[n].prev != -1) { alpar@209: nodes[nodes[n].prev].next = nodes[n].next; deba@57: } else { alpar@209: first_node = nodes[n].next; deba@57: } alpar@209: deba@57: nodes[n].next = first_free_node; deba@57: first_free_node = n; deba@149: nodes[n].prev = -2; deba@57: deba@57: } alpar@209: deba@57: void erase(const Arc& arc) { deba@57: int n = arc.id; alpar@209: deba@57: if(arcs[n].next_in!=-1) { alpar@209: arcs[arcs[n].next_in].prev_in = arcs[n].prev_in; deba@57: } deba@57: deba@57: if(arcs[n].prev_in!=-1) { alpar@209: arcs[arcs[n].prev_in].next_in = arcs[n].next_in; deba@57: } else { alpar@209: nodes[arcs[n].target].first_in = arcs[n].next_in; deba@57: } deba@57: alpar@209: deba@57: if(arcs[n].next_out!=-1) { alpar@209: arcs[arcs[n].next_out].prev_out = arcs[n].prev_out; alpar@209: } deba@57: deba@57: if(arcs[n].prev_out!=-1) { alpar@209: arcs[arcs[n].prev_out].next_out = arcs[n].next_out; deba@57: } else { alpar@209: nodes[arcs[n].source].first_out = arcs[n].next_out; deba@57: } alpar@209: deba@57: arcs[n].next_in = first_free_arc; deba@149: first_free_arc = n; deba@149: arcs[n].prev_in = -2; deba@57: } deba@57: deba@57: void clear() { deba@57: arcs.clear(); deba@57: nodes.clear(); deba@57: first_node = first_free_node = first_free_arc = -1; deba@57: } deba@57: deba@57: protected: alpar@209: void changeTarget(Arc e, Node n) deba@57: { deba@57: if(arcs[e.id].next_in != -1) alpar@209: arcs[arcs[e.id].next_in].prev_in = arcs[e.id].prev_in; deba@57: if(arcs[e.id].prev_in != -1) alpar@209: arcs[arcs[e.id].prev_in].next_in = arcs[e.id].next_in; deba@57: else nodes[arcs[e.id].target].first_in = arcs[e.id].next_in; deba@57: if (nodes[n.id].first_in != -1) { alpar@209: arcs[nodes[n.id].first_in].prev_in = e.id; deba@57: } deba@57: arcs[e.id].target = n.id; deba@57: arcs[e.id].prev_in = -1; deba@57: arcs[e.id].next_in = nodes[n.id].first_in; deba@57: nodes[n.id].first_in = e.id; deba@57: } alpar@209: void changeSource(Arc e, Node n) deba@57: { deba@57: if(arcs[e.id].next_out != -1) alpar@209: arcs[arcs[e.id].next_out].prev_out = arcs[e.id].prev_out; deba@57: if(arcs[e.id].prev_out != -1) alpar@209: arcs[arcs[e.id].prev_out].next_out = arcs[e.id].next_out; deba@57: else nodes[arcs[e.id].source].first_out = arcs[e.id].next_out; deba@57: if (nodes[n.id].first_out != -1) { alpar@209: arcs[nodes[n.id].first_out].prev_out = e.id; deba@57: } deba@57: arcs[e.id].source = n.id; deba@57: arcs[e.id].prev_out = -1; deba@57: arcs[e.id].next_out = nodes[n.id].first_out; deba@57: nodes[n.id].first_out = e.id; deba@57: } deba@57: deba@57: }; deba@57: deba@57: typedef DigraphExtender ExtendedListDigraphBase; deba@57: kpeter@73: /// \addtogroup graphs deba@57: /// @{ deba@57: alpar@209: ///A general directed graph structure. deba@57: alpar@209: ///\ref ListDigraph is a simple and fast directed graph alpar@209: ///implementation based on static linked lists that are stored in alpar@209: ///\c std::vector structures. deba@57: /// deba@57: ///It conforms to the \ref concepts::Digraph "Digraph concept" and it kpeter@73: ///also provides several useful additional functionalities. kpeter@73: ///Most of the member functions and nested classes are documented kpeter@73: ///only in the concept class. deba@57: /// deba@57: ///An important extra feature of this digraph implementation is that deba@57: ///its maps are real \ref concepts::ReferenceMap "reference map"s. deba@57: /// kpeter@73: ///\sa concepts::Digraph deba@57: deba@57: class ListDigraph : public ExtendedListDigraphBase { deba@57: private: kpeter@73: ///ListDigraph is \e not copy constructible. Use copyDigraph() instead. alpar@209: kpeter@73: ///ListDigraph is \e not copy constructible. Use copyDigraph() instead. deba@57: /// deba@57: ListDigraph(const ListDigraph &) :ExtendedListDigraphBase() {}; deba@57: ///\brief Assignment of ListDigraph to another one is \e not allowed. kpeter@73: ///Use copyDigraph() instead. deba@57: deba@57: ///Assignment of ListDigraph to another one is \e not allowed. kpeter@73: ///Use copyDigraph() instead. deba@57: void operator=(const ListDigraph &) {} deba@57: public: deba@57: deba@57: typedef ExtendedListDigraphBase Parent; deba@57: deba@57: /// Constructor alpar@209: deba@57: /// Constructor. deba@57: /// deba@57: ListDigraph() {} deba@57: deba@57: ///Add a new node to the digraph. alpar@209: kpeter@73: ///Add a new node to the digraph. kpeter@73: ///\return the new node. deba@57: Node addNode() { return Parent::addNode(); } deba@57: deba@57: ///Add a new arc to the digraph. alpar@209: deba@57: ///Add a new arc to the digraph with source node \c s deba@57: ///and target node \c t. deba@57: ///\return the new arc. alpar@209: Arc addArc(const Node& s, const Node& t) { alpar@209: return Parent::addArc(s, t); deba@57: } deba@57: deba@234: ///\brief Erase a node from the digraph. deba@234: /// deba@234: ///Erase a node from the digraph. deba@234: /// deba@234: void erase(const Node& n) { Parent::erase(n); } deba@234: deba@234: ///\brief Erase an arc from the digraph. deba@234: /// deba@234: ///Erase an arc from the digraph. deba@234: /// deba@234: void erase(const Arc& a) { Parent::erase(a); } deba@234: deba@149: /// Node validity check deba@149: deba@149: /// This function gives back true if the given node is valid, alpar@209: /// ie. it is a real node of the graph. deba@149: /// deba@149: /// \warning A Node pointing to a removed item deba@149: /// could become valid again later if new nodes are deba@149: /// added to the graph. deba@149: bool valid(Node n) const { return Parent::valid(n); } deba@149: deba@149: /// Arc validity check deba@149: deba@149: /// This function gives back true if the given arc is valid, alpar@209: /// ie. it is a real arc of the graph. deba@149: /// deba@149: /// \warning An Arc pointing to a removed item deba@149: /// could become valid again later if new nodes are deba@149: /// added to the graph. deba@149: bool valid(Arc a) const { return Parent::valid(a); } deba@149: deba@235: /// Change the target of \c a to \c n deba@57: deba@235: /// Change the target of \c a to \c n deba@57: /// deba@57: ///\note The ArcIts and OutArcIts referencing deba@57: ///the changed arc remain valid. However InArcIts are deba@57: ///invalidated. kpeter@73: /// deba@57: ///\warning This functionality cannot be used together with the Snapshot deba@57: ///feature. deba@235: void changeTarget(Arc a, Node n) { deba@235: Parent::changeTarget(a,n); deba@57: } deba@235: /// Change the source of \c a to \c n deba@57: deba@235: /// Change the source of \c a to \c n deba@57: /// deba@235: ///\note The InArcIts referencing the changed arc remain deba@235: ///valid. However the ArcIts and OutArcIts are deba@57: ///invalidated. kpeter@73: /// deba@57: ///\warning This functionality cannot be used together with the Snapshot deba@57: ///feature. deba@235: void changeSource(Arc a, Node n) { deba@235: Parent::changeSource(a,n); deba@57: } deba@57: deba@57: /// Invert the direction of an arc. deba@57: deba@57: ///\note The ArcIts referencing the changed arc remain deba@57: ///valid. However OutArcIts and InArcIts are deba@57: ///invalidated. kpeter@73: /// deba@57: ///\warning This functionality cannot be used together with the Snapshot deba@57: ///feature. deba@57: void reverseArc(Arc e) { deba@57: Node t=target(e); deba@57: changeTarget(e,source(e)); deba@57: changeSource(e,t); deba@57: } deba@57: kpeter@73: /// Reserve memory for nodes. kpeter@73: kpeter@73: /// Using this function it is possible to avoid the superfluous memory deba@57: /// allocation: if you know that the digraph you want to build will deba@57: /// be very large (e.g. it will contain millions of nodes and/or arcs) deba@57: /// then it is worth reserving space for this amount before starting deba@57: /// to build the digraph. deba@57: /// \sa reserveArc deba@57: void reserveNode(int n) { nodes.reserve(n); }; deba@57: kpeter@73: /// Reserve memory for arcs. deba@57: kpeter@73: /// Using this function it is possible to avoid the superfluous memory deba@57: /// allocation: if you know that the digraph you want to build will deba@57: /// be very large (e.g. it will contain millions of nodes and/or arcs) deba@57: /// then it is worth reserving space for this amount before starting deba@57: /// to build the digraph. deba@57: /// \sa reserveNode deba@57: void reserveArc(int m) { arcs.reserve(m); }; deba@57: deba@57: ///Contract two nodes. deba@57: deba@57: ///This function contracts two nodes. deba@57: ///Node \p b will be removed but instead of deleting deba@57: ///incident arcs, they will be joined to \p a. deba@57: ///The last parameter \p r controls whether to remove loops. \c true deba@57: ///means that loops will be removed. deba@57: /// kpeter@73: ///\note The ArcIts referencing a moved arc remain deba@57: ///valid. However InArcIts and OutArcIts deba@57: ///may be invalidated. kpeter@73: /// deba@57: ///\warning This functionality cannot be used together with the Snapshot deba@57: ///feature. alpar@209: void contract(Node a, Node b, bool r = true) deba@57: { deba@57: for(OutArcIt e(*this,b);e!=INVALID;) { alpar@209: OutArcIt f=e; alpar@209: ++f; alpar@209: if(r && target(e)==a) erase(e); alpar@209: else changeSource(e,a); alpar@209: e=f; deba@57: } deba@57: for(InArcIt e(*this,b);e!=INVALID;) { alpar@209: InArcIt f=e; alpar@209: ++f; alpar@209: if(r && source(e)==a) erase(e); alpar@209: else changeTarget(e,a); alpar@209: e=f; deba@57: } deba@57: erase(b); deba@57: } deba@57: deba@57: ///Split a node. deba@57: deba@57: ///This function splits a node. First a new node is added to the digraph, deba@57: ///then the source of each outgoing arc of \c n is moved to this new node. deba@57: ///If \c connect is \c true (this is the default value), then a new arc deba@57: ///from \c n to the newly created node is also added. deba@57: ///\return The newly created node. deba@57: /// deba@57: ///\note The ArcIts referencing a moved arc remain deba@57: ///valid. However InArcIts and OutArcIts may alpar@209: ///be invalidated. deba@57: /// deba@57: ///\warning This functionality cannot be used together with the kpeter@73: ///Snapshot feature. kpeter@73: /// kpeter@73: ///\todo It could be implemented in a bit faster way. deba@57: Node split(Node n, bool connect = true) { deba@57: Node b = addNode(); deba@57: for(OutArcIt e(*this,n);e!=INVALID;) { kpeter@212: OutArcIt f=e; alpar@209: ++f; alpar@209: changeSource(e,b); alpar@209: e=f; deba@57: } deba@57: if (connect) addArc(n,b); deba@57: return b; deba@57: } alpar@209: deba@57: ///Split an arc. deba@57: deba@57: ///This function splits an arc. First a new node \c b is added to deba@57: ///the digraph, then the original arc is re-targeted to \c deba@57: ///b. Finally an arc from \c b to the original target is added. kpeter@73: /// kpeter@73: ///\return The newly created node. kpeter@73: /// kpeter@73: ///\warning This functionality cannot be used together with the kpeter@73: ///Snapshot feature. deba@57: Node split(Arc e) { deba@57: Node b = addNode(); deba@57: addArc(b,target(e)); deba@57: changeTarget(e,b); deba@57: return b; deba@57: } alpar@209: deba@57: /// \brief Class to make a snapshot of the digraph and restore kpeter@73: /// it later. deba@57: /// kpeter@73: /// Class to make a snapshot of the digraph and restore it later. deba@57: /// deba@57: /// The newly added nodes and arcs can be removed using the deba@57: /// restore() function. deba@57: /// kpeter@73: /// \warning Arc and node deletions and other modifications (e.g. alpar@209: /// contracting, splitting, reversing arcs or nodes) cannot be alpar@209: /// restored. These events invalidate the snapshot. deba@57: class Snapshot { deba@57: protected: deba@57: deba@57: typedef Parent::NodeNotifier NodeNotifier; deba@57: deba@57: class NodeObserverProxy : public NodeNotifier::ObserverBase { deba@57: public: deba@57: deba@57: NodeObserverProxy(Snapshot& _snapshot) deba@57: : snapshot(_snapshot) {} deba@57: deba@57: using NodeNotifier::ObserverBase::attach; deba@57: using NodeNotifier::ObserverBase::detach; deba@57: using NodeNotifier::ObserverBase::attached; alpar@209: deba@57: protected: alpar@209: deba@57: virtual void add(const Node& node) { deba@57: snapshot.addNode(node); deba@57: } deba@57: virtual void add(const std::vector& nodes) { deba@57: for (int i = nodes.size() - 1; i >= 0; ++i) { deba@57: snapshot.addNode(nodes[i]); deba@57: } deba@57: } deba@57: virtual void erase(const Node& node) { deba@57: snapshot.eraseNode(node); deba@57: } deba@57: virtual void erase(const std::vector& nodes) { deba@57: for (int i = 0; i < int(nodes.size()); ++i) { deba@57: snapshot.eraseNode(nodes[i]); deba@57: } deba@57: } deba@57: virtual void build() { deba@57: Node node; deba@57: std::vector nodes; alpar@209: for (notifier()->first(node); node != INVALID; deba@57: notifier()->next(node)) { deba@57: nodes.push_back(node); deba@57: } deba@57: for (int i = nodes.size() - 1; i >= 0; --i) { deba@57: snapshot.addNode(nodes[i]); deba@57: } deba@57: } deba@57: virtual void clear() { deba@57: Node node; alpar@209: for (notifier()->first(node); node != INVALID; deba@57: notifier()->next(node)) { deba@57: snapshot.eraseNode(node); deba@57: } deba@57: } deba@57: deba@57: Snapshot& snapshot; deba@57: }; deba@57: deba@57: class ArcObserverProxy : public ArcNotifier::ObserverBase { deba@57: public: deba@57: deba@57: ArcObserverProxy(Snapshot& _snapshot) deba@57: : snapshot(_snapshot) {} deba@57: deba@57: using ArcNotifier::ObserverBase::attach; deba@57: using ArcNotifier::ObserverBase::detach; deba@57: using ArcNotifier::ObserverBase::attached; alpar@209: deba@57: protected: deba@57: deba@57: virtual void add(const Arc& arc) { deba@57: snapshot.addArc(arc); deba@57: } deba@57: virtual void add(const std::vector& arcs) { deba@57: for (int i = arcs.size() - 1; i >= 0; ++i) { deba@57: snapshot.addArc(arcs[i]); deba@57: } deba@57: } deba@57: virtual void erase(const Arc& arc) { deba@57: snapshot.eraseArc(arc); deba@57: } deba@57: virtual void erase(const std::vector& arcs) { deba@57: for (int i = 0; i < int(arcs.size()); ++i) { deba@57: snapshot.eraseArc(arcs[i]); deba@57: } deba@57: } deba@57: virtual void build() { deba@57: Arc arc; deba@57: std::vector arcs; alpar@209: for (notifier()->first(arc); arc != INVALID; deba@57: notifier()->next(arc)) { deba@57: arcs.push_back(arc); deba@57: } deba@57: for (int i = arcs.size() - 1; i >= 0; --i) { deba@57: snapshot.addArc(arcs[i]); deba@57: } deba@57: } deba@57: virtual void clear() { deba@57: Arc arc; alpar@209: for (notifier()->first(arc); arc != INVALID; deba@57: notifier()->next(arc)) { deba@57: snapshot.eraseArc(arc); deba@57: } deba@57: } deba@57: deba@57: Snapshot& snapshot; deba@57: }; alpar@209: deba@57: ListDigraph *digraph; deba@57: deba@57: NodeObserverProxy node_observer_proxy; deba@57: ArcObserverProxy arc_observer_proxy; deba@57: deba@57: std::list added_nodes; deba@57: std::list added_arcs; deba@57: deba@57: deba@57: void addNode(const Node& node) { alpar@209: added_nodes.push_front(node); deba@57: } deba@57: void eraseNode(const Node& node) { alpar@209: std::list::iterator it = deba@57: std::find(added_nodes.begin(), added_nodes.end(), node); deba@57: if (it == added_nodes.end()) { deba@57: clear(); deba@57: arc_observer_proxy.detach(); deba@57: throw NodeNotifier::ImmediateDetach(); deba@57: } else { deba@57: added_nodes.erase(it); deba@57: } deba@57: } deba@57: deba@57: void addArc(const Arc& arc) { alpar@209: added_arcs.push_front(arc); deba@57: } deba@57: void eraseArc(const Arc& arc) { alpar@209: std::list::iterator it = deba@57: std::find(added_arcs.begin(), added_arcs.end(), arc); deba@57: if (it == added_arcs.end()) { deba@57: clear(); alpar@209: node_observer_proxy.detach(); deba@57: throw ArcNotifier::ImmediateDetach(); deba@57: } else { deba@57: added_arcs.erase(it); alpar@209: } deba@57: } deba@57: deba@57: void attach(ListDigraph &_digraph) { alpar@209: digraph = &_digraph; alpar@209: node_observer_proxy.attach(digraph->notifier(Node())); deba@57: arc_observer_proxy.attach(digraph->notifier(Arc())); deba@57: } alpar@209: deba@57: void detach() { alpar@209: node_observer_proxy.detach(); alpar@209: arc_observer_proxy.detach(); deba@57: } deba@57: deba@57: bool attached() const { deba@57: return node_observer_proxy.attached(); deba@57: } deba@57: deba@57: void clear() { deba@57: added_nodes.clear(); alpar@209: added_arcs.clear(); deba@57: } deba@57: deba@57: public: deba@57: deba@57: /// \brief Default constructor. deba@57: /// deba@57: /// Default constructor. deba@57: /// To actually make a snapshot you must call save(). alpar@209: Snapshot() alpar@209: : digraph(0), node_observer_proxy(*this), deba@57: arc_observer_proxy(*this) {} alpar@209: deba@57: /// \brief Constructor that immediately makes a snapshot. alpar@209: /// deba@57: /// This constructor immediately makes a snapshot of the digraph. deba@57: /// \param _digraph The digraph we make a snapshot of. alpar@209: Snapshot(ListDigraph &_digraph) alpar@209: : node_observer_proxy(*this), deba@57: arc_observer_proxy(*this) { alpar@209: attach(_digraph); deba@57: } alpar@209: deba@57: /// \brief Make a snapshot. deba@57: /// deba@57: /// Make a snapshot of the digraph. deba@57: /// deba@57: /// This function can be called more than once. In case of a repeated deba@57: /// call, the previous snapshot gets lost. deba@57: /// \param _digraph The digraph we make the snapshot of. deba@57: void save(ListDigraph &_digraph) { deba@57: if (attached()) { deba@57: detach(); deba@57: clear(); deba@57: } deba@57: attach(_digraph); deba@57: } alpar@209: deba@57: /// \brief Undo the changes until the last snapshot. alpar@209: // deba@57: /// Undo the changes until the last snapshot created by save(). deba@57: void restore() { alpar@209: detach(); alpar@209: for(std::list::iterator it = added_arcs.begin(); deba@57: it != added_arcs.end(); ++it) { alpar@209: digraph->erase(*it); alpar@209: } alpar@209: for(std::list::iterator it = added_nodes.begin(); deba@57: it != added_nodes.end(); ++it) { alpar@209: digraph->erase(*it); alpar@209: } deba@57: clear(); deba@57: } deba@57: deba@57: /// \brief Gives back true when the snapshot is valid. deba@57: /// deba@57: /// Gives back true when the snapshot is valid. deba@57: bool valid() const { deba@57: return attached(); deba@57: } deba@57: }; alpar@209: deba@57: }; deba@57: deba@57: ///@} deba@57: deba@57: class ListGraphBase { deba@57: deba@57: protected: deba@57: deba@57: struct NodeT { deba@57: int first_out; deba@57: int prev, next; deba@57: }; alpar@209: deba@57: struct ArcT { deba@57: int target; deba@57: int prev_out, next_out; deba@57: }; deba@57: deba@57: std::vector nodes; deba@57: deba@57: int first_node; deba@57: deba@57: int first_free_node; deba@57: deba@57: std::vector arcs; deba@57: deba@57: int first_free_arc; alpar@209: deba@57: public: alpar@209: deba@57: typedef ListGraphBase Digraph; deba@57: deba@57: class Node; deba@57: class Arc; deba@57: class Edge; alpar@209: deba@57: class Node { deba@57: friend class ListGraphBase; deba@57: protected: deba@57: deba@57: int id; deba@57: explicit Node(int pid) { id = pid;} deba@57: deba@57: public: deba@57: Node() {} deba@57: Node (Invalid) { id = -1; } deba@57: bool operator==(const Node& node) const {return id == node.id;} deba@57: bool operator!=(const Node& node) const {return id != node.id;} deba@57: bool operator<(const Node& node) const {return id < node.id;} deba@57: }; deba@57: deba@57: class Edge { deba@57: friend class ListGraphBase; deba@57: protected: deba@57: deba@57: int id; deba@57: explicit Edge(int pid) { id = pid;} deba@57: deba@57: public: deba@57: Edge() {} deba@57: Edge (Invalid) { id = -1; } kpeter@73: bool operator==(const Edge& edge) const {return id == edge.id;} kpeter@73: bool operator!=(const Edge& edge) const {return id != edge.id;} kpeter@73: bool operator<(const Edge& edge) const {return id < edge.id;} deba@57: }; deba@57: deba@57: class Arc { deba@57: friend class ListGraphBase; deba@57: protected: deba@57: deba@57: int id; deba@57: explicit Arc(int pid) { id = pid;} deba@57: deba@57: public: deba@238: operator Edge() const { deba@238: return id != -1 ? edgeFromId(id / 2) : INVALID; deba@238: } deba@57: deba@57: Arc() {} deba@57: Arc (Invalid) { id = -1; } deba@57: bool operator==(const Arc& arc) const {return id == arc.id;} deba@57: bool operator!=(const Arc& arc) const {return id != arc.id;} deba@57: bool operator<(const Arc& arc) const {return id < arc.id;} deba@57: }; deba@57: deba@57: deba@57: deba@57: ListGraphBase() deba@57: : nodes(), first_node(-1), alpar@209: first_free_node(-1), arcs(), first_free_arc(-1) {} deba@57: alpar@209: alpar@209: int maxNodeId() const { return nodes.size()-1; } deba@57: int maxEdgeId() const { return arcs.size() / 2 - 1; } deba@57: int maxArcId() const { return arcs.size()-1; } deba@57: deba@57: Node source(Arc e) const { return Node(arcs[e.id ^ 1].target); } deba@57: Node target(Arc e) const { return Node(arcs[e.id].target); } deba@57: deba@57: Node u(Edge e) const { return Node(arcs[2 * e.id].target); } deba@57: Node v(Edge e) const { return Node(arcs[2 * e.id + 1].target); } deba@57: deba@57: static bool direction(Arc e) { deba@57: return (e.id & 1) == 1; deba@57: } deba@57: deba@57: static Arc direct(Edge e, bool d) { deba@57: return Arc(e.id * 2 + (d ? 1 : 0)); deba@57: } deba@57: alpar@209: void first(Node& node) const { deba@57: node.id = first_node; deba@57: } deba@57: deba@57: void next(Node& node) const { deba@57: node.id = nodes[node.id].next; deba@57: } deba@57: alpar@209: void first(Arc& e) const { deba@57: int n = first_node; deba@57: while (n != -1 && nodes[n].first_out == -1) { deba@57: n = nodes[n].next; deba@57: } deba@57: e.id = (n == -1) ? -1 : nodes[n].first_out; deba@57: } deba@57: deba@57: void next(Arc& e) const { deba@57: if (arcs[e.id].next_out != -1) { alpar@209: e.id = arcs[e.id].next_out; deba@57: } else { alpar@209: int n = nodes[arcs[e.id ^ 1].target].next; deba@57: while(n != -1 && nodes[n].first_out == -1) { deba@57: n = nodes[n].next; deba@57: } alpar@209: e.id = (n == -1) ? -1 : nodes[n].first_out; alpar@209: } deba@57: } deba@57: alpar@209: void first(Edge& e) const { deba@57: int n = first_node; deba@57: while (n != -1) { deba@57: e.id = nodes[n].first_out; deba@57: while ((e.id & 1) != 1) { deba@57: e.id = arcs[e.id].next_out; deba@57: } deba@57: if (e.id != -1) { deba@57: e.id /= 2; deba@57: return; alpar@209: } deba@57: n = nodes[n].next; deba@57: } deba@57: e.id = -1; deba@57: } deba@57: deba@57: void next(Edge& e) const { deba@57: int n = arcs[e.id * 2].target; deba@57: e.id = arcs[(e.id * 2) | 1].next_out; deba@57: while ((e.id & 1) != 1) { deba@57: e.id = arcs[e.id].next_out; deba@57: } deba@57: if (e.id != -1) { deba@57: e.id /= 2; deba@57: return; alpar@209: } deba@57: n = nodes[n].next; deba@57: while (n != -1) { deba@57: e.id = nodes[n].first_out; deba@57: while ((e.id & 1) != 1) { deba@57: e.id = arcs[e.id].next_out; deba@57: } deba@57: if (e.id != -1) { deba@57: e.id /= 2; deba@57: return; alpar@209: } deba@57: n = nodes[n].next; deba@57: } deba@57: e.id = -1; deba@57: } deba@57: deba@57: void firstOut(Arc &e, const Node& v) const { deba@57: e.id = nodes[v.id].first_out; deba@57: } deba@57: void nextOut(Arc &e) const { deba@57: e.id = arcs[e.id].next_out; deba@57: } deba@57: deba@57: void firstIn(Arc &e, const Node& v) const { deba@57: e.id = ((nodes[v.id].first_out) ^ 1); deba@57: if (e.id == -2) e.id = -1; deba@57: } deba@57: void nextIn(Arc &e) const { deba@57: e.id = ((arcs[e.id ^ 1].next_out) ^ 1); deba@57: if (e.id == -2) e.id = -1; deba@57: } deba@57: deba@57: void firstInc(Edge &e, bool& d, const Node& v) const { kpeter@73: int a = nodes[v.id].first_out; kpeter@73: if (a != -1 ) { kpeter@73: e.id = a / 2; kpeter@73: d = ((a & 1) == 1); deba@57: } else { deba@57: e.id = -1; deba@57: d = true; deba@57: } deba@57: } deba@57: void nextInc(Edge &e, bool& d) const { kpeter@73: int a = (arcs[(e.id * 2) | (d ? 1 : 0)].next_out); kpeter@73: if (a != -1 ) { kpeter@73: e.id = a / 2; kpeter@73: d = ((a & 1) == 1); deba@57: } else { deba@57: e.id = -1; deba@57: d = true; deba@57: } deba@57: } alpar@209: deba@57: static int id(Node v) { return v.id; } deba@57: static int id(Arc e) { return e.id; } deba@57: static int id(Edge e) { return e.id; } deba@57: deba@57: static Node nodeFromId(int id) { return Node(id);} deba@57: static Arc arcFromId(int id) { return Arc(id);} deba@57: static Edge edgeFromId(int id) { return Edge(id);} deba@57: alpar@209: bool valid(Node n) const { alpar@209: return n.id >= 0 && n.id < static_cast(nodes.size()) && alpar@209: nodes[n.id].prev != -2; deba@149: } deba@149: alpar@209: bool valid(Arc a) const { alpar@209: return a.id >= 0 && a.id < static_cast(arcs.size()) && alpar@209: arcs[a.id].prev_out != -2; deba@149: } deba@149: alpar@209: bool valid(Edge e) const { alpar@209: return e.id >= 0 && 2 * e.id < static_cast(arcs.size()) && alpar@209: arcs[2 * e.id].prev_out != -2; deba@149: } deba@149: alpar@209: Node addNode() { deba@57: int n; alpar@209: deba@57: if(first_free_node==-1) { alpar@209: n = nodes.size(); alpar@209: nodes.push_back(NodeT()); deba@57: } else { alpar@209: n = first_free_node; alpar@209: first_free_node = nodes[n].next; deba@57: } alpar@209: deba@57: nodes[n].next = first_node; deba@57: if (first_node != -1) nodes[first_node].prev = n; deba@57: first_node = n; deba@57: nodes[n].prev = -1; alpar@209: deba@57: nodes[n].first_out = -1; alpar@209: deba@57: return Node(n); deba@57: } alpar@209: deba@57: Edge addEdge(Node u, Node v) { alpar@209: int n; deba@57: deba@57: if (first_free_arc == -1) { alpar@209: n = arcs.size(); alpar@209: arcs.push_back(ArcT()); alpar@209: arcs.push_back(ArcT()); deba@57: } else { alpar@209: n = first_free_arc; alpar@209: first_free_arc = arcs[n].next_out; deba@57: } alpar@209: deba@57: arcs[n].target = u.id; deba@57: arcs[n | 1].target = v.id; deba@57: deba@57: arcs[n].next_out = nodes[v.id].first_out; deba@57: if (nodes[v.id].first_out != -1) { alpar@209: arcs[nodes[v.id].first_out].prev_out = n; alpar@209: } deba@57: arcs[n].prev_out = -1; deba@57: nodes[v.id].first_out = n; alpar@209: deba@57: arcs[n | 1].next_out = nodes[u.id].first_out; deba@57: if (nodes[u.id].first_out != -1) { alpar@209: arcs[nodes[u.id].first_out].prev_out = (n | 1); deba@57: } alpar@209: arcs[n | 1].prev_out = -1; deba@57: nodes[u.id].first_out = (n | 1); deba@57: deba@57: return Edge(n / 2); deba@57: } alpar@209: deba@57: void erase(const Node& node) { deba@57: int n = node.id; alpar@209: deba@57: if(nodes[n].next != -1) { alpar@209: nodes[nodes[n].next].prev = nodes[n].prev; deba@57: } alpar@209: deba@57: if(nodes[n].prev != -1) { alpar@209: nodes[nodes[n].prev].next = nodes[n].next; deba@57: } else { alpar@209: first_node = nodes[n].next; deba@57: } alpar@209: deba@57: nodes[n].next = first_free_node; deba@57: first_free_node = n; deba@149: nodes[n].prev = -2; deba@57: } alpar@209: kpeter@73: void erase(const Edge& edge) { kpeter@73: int n = edge.id * 2; alpar@209: deba@57: if (arcs[n].next_out != -1) { alpar@209: arcs[arcs[n].next_out].prev_out = arcs[n].prev_out; alpar@209: } deba@57: deba@57: if (arcs[n].prev_out != -1) { alpar@209: arcs[arcs[n].prev_out].next_out = arcs[n].next_out; deba@57: } else { alpar@209: nodes[arcs[n | 1].target].first_out = arcs[n].next_out; deba@57: } deba@57: deba@57: if (arcs[n | 1].next_out != -1) { alpar@209: arcs[arcs[n | 1].next_out].prev_out = arcs[n | 1].prev_out; alpar@209: } deba@57: deba@57: if (arcs[n | 1].prev_out != -1) { alpar@209: arcs[arcs[n | 1].prev_out].next_out = arcs[n | 1].next_out; deba@57: } else { alpar@209: nodes[arcs[n].target].first_out = arcs[n | 1].next_out; deba@57: } alpar@209: deba@57: arcs[n].next_out = first_free_arc; alpar@209: first_free_arc = n; deba@149: arcs[n].prev_out = -2; deba@149: arcs[n | 1].prev_out = -2; deba@57: deba@57: } deba@57: deba@57: void clear() { deba@57: arcs.clear(); deba@57: nodes.clear(); deba@57: first_node = first_free_node = first_free_arc = -1; deba@57: } deba@57: deba@57: protected: deba@57: deba@235: void changeV(Edge e, Node n) { deba@57: if(arcs[2 * e.id].next_out != -1) { alpar@209: arcs[arcs[2 * e.id].next_out].prev_out = arcs[2 * e.id].prev_out; deba@57: } deba@57: if(arcs[2 * e.id].prev_out != -1) { alpar@209: arcs[arcs[2 * e.id].prev_out].next_out = deba@57: arcs[2 * e.id].next_out; deba@57: } else { alpar@209: nodes[arcs[(2 * e.id) | 1].target].first_out = deba@57: arcs[2 * e.id].next_out; deba@57: } deba@57: deba@57: if (nodes[n.id].first_out != -1) { alpar@209: arcs[nodes[n.id].first_out].prev_out = 2 * e.id; deba@57: } deba@57: arcs[(2 * e.id) | 1].target = n.id; deba@57: arcs[2 * e.id].prev_out = -1; deba@57: arcs[2 * e.id].next_out = nodes[n.id].first_out; deba@57: nodes[n.id].first_out = 2 * e.id; deba@57: } deba@57: deba@235: void changeU(Edge e, Node n) { deba@57: if(arcs[(2 * e.id) | 1].next_out != -1) { alpar@209: arcs[arcs[(2 * e.id) | 1].next_out].prev_out = deba@57: arcs[(2 * e.id) | 1].prev_out; deba@57: } deba@57: if(arcs[(2 * e.id) | 1].prev_out != -1) { alpar@209: arcs[arcs[(2 * e.id) | 1].prev_out].next_out = deba@57: arcs[(2 * e.id) | 1].next_out; deba@57: } else { alpar@209: nodes[arcs[2 * e.id].target].first_out = deba@57: arcs[(2 * e.id) | 1].next_out; deba@57: } deba@57: deba@57: if (nodes[n.id].first_out != -1) { alpar@209: arcs[nodes[n.id].first_out].prev_out = ((2 * e.id) | 1); deba@57: } deba@57: arcs[2 * e.id].target = n.id; deba@57: arcs[(2 * e.id) | 1].prev_out = -1; deba@57: arcs[(2 * e.id) | 1].next_out = nodes[n.id].first_out; deba@57: nodes[n.id].first_out = ((2 * e.id) | 1); deba@57: } deba@57: deba@57: }; deba@57: deba@57: typedef GraphExtender ExtendedListGraphBase; deba@57: deba@57: kpeter@73: /// \addtogroup graphs deba@57: /// @{ deba@57: kpeter@73: ///A general undirected graph structure. deba@57: alpar@209: ///\ref ListGraph is a simple and fast undirected graph alpar@209: ///implementation based on static linked lists that are stored in alpar@209: ///\c std::vector structures. deba@57: /// kpeter@73: ///It conforms to the \ref concepts::Graph "Graph concept" and it kpeter@73: ///also provides several useful additional functionalities. kpeter@73: ///Most of the member functions and nested classes are documented kpeter@73: ///only in the concept class. kpeter@73: /// kpeter@73: ///An important extra feature of this graph implementation is that deba@57: ///its maps are real \ref concepts::ReferenceMap "reference map"s. deba@57: /// kpeter@73: ///\sa concepts::Graph kpeter@73: deba@57: class ListGraph : public ExtendedListGraphBase { deba@57: private: kpeter@73: ///ListGraph is \e not copy constructible. Use copyGraph() instead. deba@57: kpeter@73: ///ListGraph is \e not copy constructible. Use copyGraph() instead. deba@57: /// deba@57: ListGraph(const ListGraph &) :ExtendedListGraphBase() {}; deba@57: ///\brief Assignment of ListGraph to another one is \e not allowed. kpeter@73: ///Use copyGraph() instead. deba@57: deba@57: ///Assignment of ListGraph to another one is \e not allowed. kpeter@73: ///Use copyGraph() instead. deba@57: void operator=(const ListGraph &) {} deba@57: public: deba@57: /// Constructor alpar@209: deba@57: /// Constructor. deba@57: /// deba@57: ListGraph() {} deba@57: deba@57: typedef ExtendedListGraphBase Parent; deba@57: kpeter@73: typedef Parent::OutArcIt IncEdgeIt; deba@57: kpeter@73: /// \brief Add a new node to the graph. deba@57: /// kpeter@73: /// Add a new node to the graph. deba@57: /// \return the new node. deba@57: Node addNode() { return Parent::addNode(); } deba@57: kpeter@73: /// \brief Add a new edge to the graph. deba@57: /// kpeter@73: /// Add a new edge to the graph with source node \c s deba@57: /// and target node \c t. deba@57: /// \return the new edge. alpar@209: Edge addEdge(const Node& s, const Node& t) { alpar@209: return Parent::addEdge(s, t); deba@57: } deba@234: deba@234: /// \brief Erase a node from the graph. deba@234: /// deba@234: /// Erase a node from the graph. deba@234: /// deba@234: void erase(const Node& n) { Parent::erase(n); } deba@234: deba@234: /// \brief Erase an edge from the graph. deba@234: /// deba@234: /// Erase an edge from the graph. deba@234: /// deba@234: void erase(const Edge& e) { Parent::erase(e); } deba@149: /// Node validity check deba@149: deba@149: /// This function gives back true if the given node is valid, alpar@209: /// ie. it is a real node of the graph. deba@149: /// deba@149: /// \warning A Node pointing to a removed item deba@149: /// could become valid again later if new nodes are deba@149: /// added to the graph. deba@149: bool valid(Node n) const { return Parent::valid(n); } deba@149: /// Arc validity check deba@149: deba@149: /// This function gives back true if the given arc is valid, alpar@209: /// ie. it is a real arc of the graph. deba@149: /// deba@149: /// \warning An Arc pointing to a removed item deba@149: /// could become valid again later if new edges are deba@149: /// added to the graph. deba@149: bool valid(Arc a) const { return Parent::valid(a); } deba@149: /// Edge validity check deba@149: deba@149: /// This function gives back true if the given edge is valid, alpar@209: /// ie. it is a real arc of the graph. deba@149: /// deba@149: /// \warning A Edge pointing to a removed item deba@149: /// could become valid again later if new edges are deba@149: /// added to the graph. deba@149: bool valid(Edge e) const { return Parent::valid(e); } deba@235: /// \brief Change the end \c u of \c e to \c n deba@57: /// deba@235: /// This function changes the end \c u of \c e to node \c n. deba@57: /// deba@235: ///\note The EdgeIts and ArcIts referencing the deba@235: ///changed edge are invalidated and if the changed node is the deba@235: ///base node of an iterator then this iterator is also deba@235: ///invalidated. kpeter@73: /// kpeter@73: ///\warning This functionality cannot be used together with the kpeter@73: ///Snapshot feature. deba@235: void changeU(Edge e, Node n) { deba@235: Parent::changeU(e,n); alpar@209: } deba@235: /// \brief Change the end \c v of \c e to \c n deba@57: /// deba@235: /// This function changes the end \c v of \c e to \c n. deba@57: /// deba@235: ///\note The EdgeIts referencing the changed edge remain deba@235: ///valid, however ArcIts and if the changed node is the deba@235: ///base node of an iterator then this iterator is invalidated. kpeter@73: /// kpeter@73: ///\warning This functionality cannot be used together with the kpeter@73: ///Snapshot feature. deba@235: void changeV(Edge e, Node n) { deba@235: Parent::changeV(e,n); deba@57: } deba@57: /// \brief Contract two nodes. deba@57: /// deba@57: /// This function contracts two nodes. deba@57: /// Node \p b will be removed but instead of deleting deba@57: /// its neighboring arcs, they will be joined to \p a. deba@57: /// The last parameter \p r controls whether to remove loops. \c true deba@57: /// means that loops will be removed. deba@57: /// deba@57: /// \note The ArcIts referencing a moved arc remain deba@57: /// valid. kpeter@73: /// kpeter@73: ///\warning This functionality cannot be used together with the kpeter@73: ///Snapshot feature. deba@57: void contract(Node a, Node b, bool r = true) { kpeter@73: for(IncEdgeIt e(*this, b); e!=INVALID;) { alpar@209: IncEdgeIt f = e; ++f; alpar@209: if (r && runningNode(e) == a) { alpar@209: erase(e); deba@235: } else if (u(e) == b) { deba@235: changeU(e, a); alpar@209: } else { deba@235: changeV(e, a); alpar@209: } alpar@209: e = f; deba@57: } deba@57: erase(b); deba@57: } deba@57: deba@57: kpeter@73: /// \brief Class to make a snapshot of the graph and restore kpeter@73: /// it later. deba@57: /// kpeter@73: /// Class to make a snapshot of the graph and restore it later. deba@57: /// deba@57: /// The newly added nodes and edges can be removed deba@57: /// using the restore() function. deba@57: /// kpeter@73: /// \warning Edge and node deletions and other modifications alpar@209: /// (e.g. changing nodes of edges, contracting nodes) cannot be kpeter@73: /// restored. These events invalidate the snapshot. deba@57: class Snapshot { deba@57: protected: deba@57: deba@57: typedef Parent::NodeNotifier NodeNotifier; deba@57: deba@57: class NodeObserverProxy : public NodeNotifier::ObserverBase { deba@57: public: deba@57: deba@57: NodeObserverProxy(Snapshot& _snapshot) deba@57: : snapshot(_snapshot) {} deba@57: deba@57: using NodeNotifier::ObserverBase::attach; deba@57: using NodeNotifier::ObserverBase::detach; deba@57: using NodeNotifier::ObserverBase::attached; alpar@209: deba@57: protected: alpar@209: deba@57: virtual void add(const Node& node) { deba@57: snapshot.addNode(node); deba@57: } deba@57: virtual void add(const std::vector& nodes) { deba@57: for (int i = nodes.size() - 1; i >= 0; ++i) { deba@57: snapshot.addNode(nodes[i]); deba@57: } deba@57: } deba@57: virtual void erase(const Node& node) { deba@57: snapshot.eraseNode(node); deba@57: } deba@57: virtual void erase(const std::vector& nodes) { deba@57: for (int i = 0; i < int(nodes.size()); ++i) { deba@57: snapshot.eraseNode(nodes[i]); deba@57: } deba@57: } deba@57: virtual void build() { deba@57: Node node; deba@57: std::vector nodes; alpar@209: for (notifier()->first(node); node != INVALID; deba@57: notifier()->next(node)) { deba@57: nodes.push_back(node); deba@57: } deba@57: for (int i = nodes.size() - 1; i >= 0; --i) { deba@57: snapshot.addNode(nodes[i]); deba@57: } deba@57: } deba@57: virtual void clear() { deba@57: Node node; alpar@209: for (notifier()->first(node); node != INVALID; deba@57: notifier()->next(node)) { deba@57: snapshot.eraseNode(node); deba@57: } deba@57: } deba@57: deba@57: Snapshot& snapshot; deba@57: }; deba@57: deba@57: class EdgeObserverProxy : public EdgeNotifier::ObserverBase { deba@57: public: deba@57: deba@57: EdgeObserverProxy(Snapshot& _snapshot) deba@57: : snapshot(_snapshot) {} deba@57: deba@57: using EdgeNotifier::ObserverBase::attach; deba@57: using EdgeNotifier::ObserverBase::detach; deba@57: using EdgeNotifier::ObserverBase::attached; alpar@209: deba@57: protected: deba@57: kpeter@73: virtual void add(const Edge& edge) { kpeter@73: snapshot.addEdge(edge); deba@57: } kpeter@73: virtual void add(const std::vector& edges) { kpeter@73: for (int i = edges.size() - 1; i >= 0; ++i) { kpeter@73: snapshot.addEdge(edges[i]); deba@57: } deba@57: } kpeter@73: virtual void erase(const Edge& edge) { kpeter@73: snapshot.eraseEdge(edge); deba@57: } kpeter@73: virtual void erase(const std::vector& edges) { kpeter@73: for (int i = 0; i < int(edges.size()); ++i) { kpeter@73: snapshot.eraseEdge(edges[i]); deba@57: } deba@57: } deba@57: virtual void build() { kpeter@73: Edge edge; kpeter@73: std::vector edges; alpar@209: for (notifier()->first(edge); edge != INVALID; kpeter@73: notifier()->next(edge)) { kpeter@73: edges.push_back(edge); deba@57: } kpeter@73: for (int i = edges.size() - 1; i >= 0; --i) { kpeter@73: snapshot.addEdge(edges[i]); deba@57: } deba@57: } deba@57: virtual void clear() { kpeter@73: Edge edge; alpar@209: for (notifier()->first(edge); edge != INVALID; kpeter@73: notifier()->next(edge)) { kpeter@73: snapshot.eraseEdge(edge); deba@57: } deba@57: } deba@57: deba@57: Snapshot& snapshot; deba@57: }; kpeter@73: kpeter@73: ListGraph *graph; deba@57: deba@57: NodeObserverProxy node_observer_proxy; kpeter@73: EdgeObserverProxy edge_observer_proxy; deba@57: deba@57: std::list added_nodes; kpeter@73: std::list added_edges; deba@57: deba@57: deba@57: void addNode(const Node& node) { alpar@209: added_nodes.push_front(node); deba@57: } deba@57: void eraseNode(const Node& node) { alpar@209: std::list::iterator it = deba@57: std::find(added_nodes.begin(), added_nodes.end(), node); deba@57: if (it == added_nodes.end()) { deba@57: clear(); kpeter@73: edge_observer_proxy.detach(); deba@57: throw NodeNotifier::ImmediateDetach(); deba@57: } else { deba@57: added_nodes.erase(it); deba@57: } deba@57: } deba@57: kpeter@73: void addEdge(const Edge& edge) { alpar@209: added_edges.push_front(edge); deba@57: } kpeter@73: void eraseEdge(const Edge& edge) { alpar@209: std::list::iterator it = kpeter@73: std::find(added_edges.begin(), added_edges.end(), edge); kpeter@73: if (it == added_edges.end()) { deba@57: clear(); deba@57: node_observer_proxy.detach(); deba@57: throw EdgeNotifier::ImmediateDetach(); deba@57: } else { kpeter@73: added_edges.erase(it); kpeter@73: } deba@57: } deba@57: kpeter@73: void attach(ListGraph &_graph) { alpar@209: graph = &_graph; alpar@209: node_observer_proxy.attach(graph->notifier(Node())); kpeter@73: edge_observer_proxy.attach(graph->notifier(Edge())); deba@57: } alpar@209: deba@57: void detach() { alpar@209: node_observer_proxy.detach(); alpar@209: edge_observer_proxy.detach(); deba@57: } deba@57: deba@57: bool attached() const { deba@57: return node_observer_proxy.attached(); deba@57: } deba@57: deba@57: void clear() { deba@57: added_nodes.clear(); alpar@209: added_edges.clear(); deba@57: } deba@57: deba@57: public: deba@57: deba@57: /// \brief Default constructor. deba@57: /// deba@57: /// Default constructor. deba@57: /// To actually make a snapshot you must call save(). alpar@209: Snapshot() alpar@209: : graph(0), node_observer_proxy(*this), kpeter@73: edge_observer_proxy(*this) {} alpar@209: deba@57: /// \brief Constructor that immediately makes a snapshot. alpar@209: /// kpeter@73: /// This constructor immediately makes a snapshot of the graph. kpeter@73: /// \param _graph The graph we make a snapshot of. alpar@209: Snapshot(ListGraph &_graph) alpar@209: : node_observer_proxy(*this), kpeter@73: edge_observer_proxy(*this) { alpar@209: attach(_graph); deba@57: } alpar@209: deba@57: /// \brief Make a snapshot. deba@57: /// kpeter@73: /// Make a snapshot of the graph. deba@57: /// deba@57: /// This function can be called more than once. In case of a repeated deba@57: /// call, the previous snapshot gets lost. kpeter@73: /// \param _graph The graph we make the snapshot of. kpeter@73: void save(ListGraph &_graph) { deba@57: if (attached()) { deba@57: detach(); deba@57: clear(); deba@57: } kpeter@73: attach(_graph); deba@57: } alpar@209: deba@57: /// \brief Undo the changes until the last snapshot. alpar@209: // deba@57: /// Undo the changes until the last snapshot created by save(). deba@57: void restore() { alpar@209: detach(); alpar@209: for(std::list::iterator it = added_edges.begin(); kpeter@73: it != added_edges.end(); ++it) { alpar@209: graph->erase(*it); alpar@209: } alpar@209: for(std::list::iterator it = added_nodes.begin(); deba@57: it != added_nodes.end(); ++it) { alpar@209: graph->erase(*it); alpar@209: } deba@57: clear(); deba@57: } deba@57: deba@57: /// \brief Gives back true when the snapshot is valid. deba@57: /// deba@57: /// Gives back true when the snapshot is valid. deba@57: bool valid() const { deba@57: return attached(); deba@57: } deba@57: }; deba@57: }; alpar@209: alpar@209: /// @} deba@57: } //namespace lemon alpar@209: deba@57: deba@57: #endif