xref: /freebsd/contrib/llvm-project/llvm/include/llvm/ADT/DirectedGraph.h (revision 1fd87a682ad7442327078e1eeb63edc4258f9815)
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