1 //===- llvm/ADT/DirectedGraph.h - Directed Graph ----------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 /// 9 /// \file 10 /// This file defines the interface and a base class implementation for a 11 /// directed graph. 12 /// 13 //===----------------------------------------------------------------------===// 14 15 #ifndef LLVM_ADT_DIRECTEDGRAPH_H 16 #define LLVM_ADT_DIRECTEDGRAPH_H 17 18 #include "llvm/ADT/GraphTraits.h" 19 #include "llvm/ADT/SetVector.h" 20 #include "llvm/ADT/SmallVector.h" 21 #include "llvm/Support/Debug.h" 22 #include "llvm/Support/raw_ostream.h" 23 24 namespace llvm { 25 26 /// Represent an edge in the directed graph. 27 /// The edge contains the target node it connects to. 28 template <class NodeType, class EdgeType> class DGEdge { 29 public: 30 DGEdge() = delete; 31 /// Create an edge pointing to the given node \p N. DGEdge(NodeType & N)32 explicit DGEdge(NodeType &N) : TargetNode(N) {} DGEdge(const DGEdge<NodeType,EdgeType> & E)33 explicit DGEdge(const DGEdge<NodeType, EdgeType> &E) 34 : TargetNode(E.TargetNode) {} 35 DGEdge<NodeType, EdgeType> &operator=(const DGEdge<NodeType, EdgeType> &E) { 36 TargetNode = E.TargetNode; 37 return *this; 38 } 39 40 /// Static polymorphism: delegate implementation (via isEqualTo) to the 41 /// derived class. 42 bool operator==(const DGEdge &E) const { 43 return getDerived().isEqualTo(E.getDerived()); 44 } 45 bool operator!=(const DGEdge &E) const { return !operator==(E); } 46 47 /// Retrieve the target node this edge connects to. getTargetNode()48 const NodeType &getTargetNode() const { return TargetNode; } getTargetNode()49 NodeType &getTargetNode() { 50 return const_cast<NodeType &>( 51 static_cast<const DGEdge<NodeType, EdgeType> &>(*this).getTargetNode()); 52 } 53 54 /// Set the target node this edge connects to. setTargetNode(const NodeType & N)55 void setTargetNode(const NodeType &N) { TargetNode = N; } 56 57 protected: 58 // As the default implementation use address comparison for equality. isEqualTo(const EdgeType & E)59 bool isEqualTo(const EdgeType &E) const { return this == &E; } 60 61 // Cast the 'this' pointer to the derived type and return a reference. getDerived()62 EdgeType &getDerived() { return *static_cast<EdgeType *>(this); } getDerived()63 const EdgeType &getDerived() const { 64 return *static_cast<const EdgeType *>(this); 65 } 66 67 // The target node this edge connects to. 68 NodeType &TargetNode; 69 }; 70 71 /// Represent a node in the directed graph. 72 /// The node has a (possibly empty) list of outgoing edges. 73 template <class NodeType, class EdgeType> class DGNode { 74 public: 75 using EdgeListTy = SetVector<EdgeType *>; 76 using iterator = typename EdgeListTy::iterator; 77 using const_iterator = typename EdgeListTy::const_iterator; 78 79 /// Create a node with a single outgoing edge \p E. DGNode(EdgeType & E)80 explicit DGNode(EdgeType &E) : Edges() { Edges.insert(&E); } 81 DGNode() = default; 82 DGNode(const DGNode<NodeType,EdgeType> & N)83 explicit DGNode(const DGNode<NodeType, EdgeType> &N) : Edges(N.Edges) {} DGNode(DGNode<NodeType,EdgeType> && N)84 DGNode(DGNode<NodeType, EdgeType> &&N) : Edges(std::move(N.Edges)) {} 85 86 DGNode<NodeType, EdgeType> &operator=(const DGNode<NodeType, EdgeType> &N) { 87 Edges = N.Edges; 88 return *this; 89 } 90 DGNode<NodeType, EdgeType> &operator=(const DGNode<NodeType, EdgeType> &&N) { 91 Edges = std::move(N.Edges); 92 return *this; 93 } 94 95 /// Static polymorphism: delegate implementation (via isEqualTo) to the 96 /// derived class. 97 friend bool operator==(const NodeType &M, const NodeType &N) { 98 return M.isEqualTo(N); 99 } 100 friend bool operator!=(const NodeType &M, const NodeType &N) { 101 return !(M == N); 102 } 103 begin()104 const_iterator begin() const { return Edges.begin(); } end()105 const_iterator end() const { return Edges.end(); } begin()106 iterator begin() { return Edges.begin(); } end()107 iterator end() { return Edges.end(); } front()108 const EdgeType &front() const { return *Edges.front(); } front()109 EdgeType &front() { return *Edges.front(); } back()110 const EdgeType &back() const { return *Edges.back(); } back()111 EdgeType &back() { return *Edges.back(); } 112 113 /// Collect in \p EL, all the edges from this node to \p N. 114 /// Return true if at least one edge was found, and false otherwise. 115 /// Note that this implementation allows more than one edge to connect 116 /// a given pair of nodes. findEdgesTo(const NodeType & N,SmallVectorImpl<EdgeType * > & EL)117 bool findEdgesTo(const NodeType &N, SmallVectorImpl<EdgeType *> &EL) const { 118 assert(EL.empty() && "Expected the list of edges to be empty."); 119 for (auto *E : Edges) 120 if (E->getTargetNode() == N) 121 EL.push_back(E); 122 return !EL.empty(); 123 } 124 125 /// Add the given edge \p E to this node, if it doesn't exist already. Returns 126 /// true if the edge is added and false otherwise. addEdge(EdgeType & E)127 bool addEdge(EdgeType &E) { return Edges.insert(&E); } 128 129 /// Remove the given edge \p E from this node, if it exists. removeEdge(EdgeType & E)130 void removeEdge(EdgeType &E) { Edges.remove(&E); } 131 132 /// Test whether there is an edge that goes from this node to \p N. hasEdgeTo(const NodeType & N)133 bool hasEdgeTo(const NodeType &N) const { 134 return (findEdgeTo(N) != Edges.end()); 135 } 136 137 /// Retrieve the outgoing edges for the node. getEdges()138 const EdgeListTy &getEdges() const { return Edges; } getEdges()139 EdgeListTy &getEdges() { 140 return const_cast<EdgeListTy &>( 141 static_cast<const DGNode<NodeType, EdgeType> &>(*this).Edges); 142 } 143 144 /// Clear the outgoing edges. clear()145 void clear() { Edges.clear(); } 146 147 protected: 148 // As the default implementation use address comparison for equality. isEqualTo(const NodeType & N)149 bool isEqualTo(const NodeType &N) const { return this == &N; } 150 151 // Cast the 'this' pointer to the derived type and return a reference. getDerived()152 NodeType &getDerived() { return *static_cast<NodeType *>(this); } getDerived()153 const NodeType &getDerived() const { 154 return *static_cast<const NodeType *>(this); 155 } 156 157 /// Find an edge to \p N. If more than one edge exists, this will return 158 /// the first one in the list of edges. findEdgeTo(const NodeType & N)159 const_iterator findEdgeTo(const NodeType &N) const { 160 return llvm::find_if( 161 Edges, [&N](const EdgeType *E) { return E->getTargetNode() == N; }); 162 } 163 164 // The list of outgoing edges. 165 EdgeListTy Edges; 166 }; 167 168 /// Directed graph 169 /// 170 /// The graph is represented by a table of nodes. 171 /// Each node contains a (possibly empty) list of outgoing edges. 172 /// Each edge contains the target node it connects to. 173 template <class NodeType, class EdgeType> class DirectedGraph { 174 protected: 175 using NodeListTy = SmallVector<NodeType *, 10>; 176 using EdgeListTy = SmallVector<EdgeType *, 10>; 177 public: 178 using iterator = typename NodeListTy::iterator; 179 using const_iterator = typename NodeListTy::const_iterator; 180 using DGraphType = DirectedGraph<NodeType, EdgeType>; 181 182 DirectedGraph() = default; DirectedGraph(NodeType & N)183 explicit DirectedGraph(NodeType &N) : Nodes() { addNode(N); } DirectedGraph(const DGraphType & G)184 DirectedGraph(const DGraphType &G) : Nodes(G.Nodes) {} DirectedGraph(DGraphType && RHS)185 DirectedGraph(DGraphType &&RHS) : Nodes(std::move(RHS.Nodes)) {} 186 DGraphType &operator=(const DGraphType &G) { 187 Nodes = G.Nodes; 188 return *this; 189 } 190 DGraphType &operator=(const DGraphType &&G) { 191 Nodes = std::move(G.Nodes); 192 return *this; 193 } 194 begin()195 const_iterator begin() const { return Nodes.begin(); } end()196 const_iterator end() const { return Nodes.end(); } begin()197 iterator begin() { return Nodes.begin(); } end()198 iterator end() { return Nodes.end(); } front()199 const NodeType &front() const { return *Nodes.front(); } front()200 NodeType &front() { return *Nodes.front(); } back()201 const NodeType &back() const { return *Nodes.back(); } back()202 NodeType &back() { return *Nodes.back(); } 203 size()204 size_t size() const { return Nodes.size(); } 205 206 /// Find the given node \p N in the table. findNode(const NodeType & N)207 const_iterator findNode(const NodeType &N) const { 208 return llvm::find_if(Nodes, 209 [&N](const NodeType *Node) { return *Node == N; }); 210 } findNode(const NodeType & N)211 iterator findNode(const NodeType &N) { 212 return const_cast<iterator>( 213 static_cast<const DGraphType &>(*this).findNode(N)); 214 } 215 216 /// Add the given node \p N to the graph if it is not already present. addNode(NodeType & N)217 bool addNode(NodeType &N) { 218 if (findNode(N) != Nodes.end()) 219 return false; 220 Nodes.push_back(&N); 221 return true; 222 } 223 224 /// Collect in \p EL all edges that are coming into node \p N. Return true 225 /// if at least one edge was found, and false otherwise. findIncomingEdgesToNode(const NodeType & N,SmallVectorImpl<EdgeType * > & EL)226 bool findIncomingEdgesToNode(const NodeType &N, SmallVectorImpl<EdgeType*> &EL) const { 227 assert(EL.empty() && "Expected the list of edges to be empty."); 228 EdgeListTy TempList; 229 for (auto *Node : Nodes) { 230 if (*Node == N) 231 continue; 232 Node->findEdgesTo(N, TempList); 233 llvm::append_range(EL, TempList); 234 TempList.clear(); 235 } 236 return !EL.empty(); 237 } 238 239 /// Remove the given node \p N from the graph. If the node has incoming or 240 /// outgoing edges, they are also removed. Return true if the node was found 241 /// and then removed, and false if the node was not found in the graph to 242 /// begin with. removeNode(NodeType & N)243 bool removeNode(NodeType &N) { 244 iterator IT = findNode(N); 245 if (IT == Nodes.end()) 246 return false; 247 // Remove incoming edges. 248 EdgeListTy EL; 249 for (auto *Node : Nodes) { 250 if (*Node == N) 251 continue; 252 Node->findEdgesTo(N, EL); 253 for (auto *E : EL) 254 Node->removeEdge(*E); 255 EL.clear(); 256 } 257 N.clear(); 258 Nodes.erase(IT); 259 return true; 260 } 261 262 /// Assuming nodes \p Src and \p Dst are already in the graph, connect node \p 263 /// Src to node \p Dst using the provided edge \p E. Return true if \p Src is 264 /// not already connected to \p Dst via \p E, and false otherwise. connect(NodeType & Src,NodeType & Dst,EdgeType & E)265 bool connect(NodeType &Src, NodeType &Dst, EdgeType &E) { 266 assert(findNode(Src) != Nodes.end() && "Src node should be present."); 267 assert(findNode(Dst) != Nodes.end() && "Dst node should be present."); 268 assert((E.getTargetNode() == Dst) && 269 "Target of the given edge does not match Dst."); 270 return Src.addEdge(E); 271 } 272 273 protected: 274 // The list of nodes in the graph. 275 NodeListTy Nodes; 276 }; 277 278 } // namespace llvm 279 280 #endif // LLVM_ADT_DIRECTEDGRAPH_H 281