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. |
32 | explicit DGEdge(NodeType &N) : TargetNode(N) {} |
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. |
48 | const NodeType &getTargetNode() const { return TargetNode; } |
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. |
55 | void setTargetNode(const NodeType &N) { TargetNode = N; } |
56 | |
57 | protected: |
58 | // As the default implementation use address comparison for equality. |
59 | bool isEqualTo(const EdgeType &E) const { return this == &E; } |
60 | |
61 | // Cast the 'this' pointer to the derived type and return a reference. |
62 | EdgeType &getDerived() { return *static_cast<EdgeType *>(this); } |
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. |
80 | explicit DGNode(EdgeType &E) : Edges() { Edges.insert(&E); } |
81 | DGNode() = default; |
82 | |
83 | explicit DGNode(const DGNode<NodeType, EdgeType> &N) : Edges(N.Edges) {} |
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 | |
104 | const_iterator begin() const { return Edges.begin(); } |
105 | const_iterator end() const { return Edges.end(); } |
106 | iterator begin() { return Edges.begin(); } |
107 | iterator end() { return Edges.end(); } |
108 | const EdgeType &front() const { return *Edges.front(); } |
109 | EdgeType &front() { return *Edges.front(); } |
110 | const EdgeType &back() const { return *Edges.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. |
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. |
127 | bool addEdge(EdgeType &E) { return Edges.insert(&E); } |
128 | |
129 | /// Remove the given edge \p E from this node, if it exists. |
130 | void removeEdge(EdgeType &E) { Edges.remove(&E); } |
131 | |
132 | /// Test whether there is an edge that goes from this node to \p N. |
133 | bool hasEdgeTo(const NodeType &N) const { |
134 | return (findEdgeTo(N) != Edges.end()); |
135 | } |
136 | |
137 | /// Retrieve the outgoing edges for the node. |
138 | const EdgeListTy &getEdges() const { return Edges; } |
139 | EdgeListTy &getEdges() { |
140 | return const_cast<EdgeListTy &>( |
141 | static_cast<const DGNode<NodeType, EdgeType> &>(*this).Edges); |
142 | } |
143 | |
144 | /// Clear the outgoing edges. |
145 | void clear() { Edges.clear(); } |
146 | |
147 | protected: |
148 | // As the default implementation use address comparison for equality. |
149 | bool isEqualTo(const NodeType &N) const { return this == &N; } |
150 | |
151 | // Cast the 'this' pointer to the derived type and return a reference. |
152 | NodeType &getDerived() { return *static_cast<NodeType *>(this); } |
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. |
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; |
183 | explicit DirectedGraph(NodeType &N) : Nodes() { addNode(N); } |
184 | DirectedGraph(const DGraphType &G) : Nodes(G.Nodes) {} |
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 | |
195 | const_iterator begin() const { return Nodes.begin(); } |
196 | const_iterator end() const { return Nodes.end(); } |
197 | iterator begin() { return Nodes.begin(); } |
198 | iterator end() { return Nodes.end(); } |
199 | const NodeType &front() const { return *Nodes.front(); } |
200 | NodeType &front() { return *Nodes.front(); } |
201 | const NodeType &back() const { return *Nodes.back(); } |
202 | NodeType &back() { return *Nodes.back(); } |
203 | |
204 | size_t size() const { return Nodes.size(); } |
205 | |
206 | /// Find the given node \p N in the table. |
207 | const_iterator findNode(const NodeType &N) const { |
208 | return llvm::find_if(Nodes, |
209 | [&N](const NodeType *Node) { return *Node == N; }); |
210 | } |
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. |
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. |
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. |
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. |
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 | |