xref: /llvm-project/llvm/include/llvm/ADT/DirectedGraph.h (revision c95df64ce06443d60881078ef2e80108e24459c4)
18b288c7dSWhitney Tsang //===- llvm/ADT/DirectedGraph.h - Directed Graph ----------------*- C++ -*-===//
28b288c7dSWhitney Tsang //
38b288c7dSWhitney Tsang // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
48b288c7dSWhitney Tsang // See https://llvm.org/LICENSE.txt for license information.
58b288c7dSWhitney Tsang // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
68b288c7dSWhitney Tsang //
78b288c7dSWhitney Tsang //===----------------------------------------------------------------------===//
8*c95df64cSShivam Gupta ///
9*c95df64cSShivam Gupta /// \file
10*c95df64cSShivam Gupta /// This file defines the interface and a base class implementation for a
11*c95df64cSShivam Gupta /// directed graph.
12*c95df64cSShivam Gupta ///
138b288c7dSWhitney Tsang //===----------------------------------------------------------------------===//
148b288c7dSWhitney Tsang 
158b288c7dSWhitney Tsang #ifndef LLVM_ADT_DIRECTEDGRAPH_H
168b288c7dSWhitney Tsang #define LLVM_ADT_DIRECTEDGRAPH_H
178b288c7dSWhitney Tsang 
188b288c7dSWhitney Tsang #include "llvm/ADT/GraphTraits.h"
198b288c7dSWhitney Tsang #include "llvm/ADT/SetVector.h"
208b288c7dSWhitney Tsang #include "llvm/ADT/SmallVector.h"
218b288c7dSWhitney Tsang #include "llvm/Support/Debug.h"
228b288c7dSWhitney Tsang #include "llvm/Support/raw_ostream.h"
238b288c7dSWhitney Tsang 
248b288c7dSWhitney Tsang namespace llvm {
258b288c7dSWhitney Tsang 
268b288c7dSWhitney Tsang /// Represent an edge in the directed graph.
278b288c7dSWhitney Tsang /// The edge contains the target node it connects to.
288b288c7dSWhitney Tsang template <class NodeType, class EdgeType> class DGEdge {
298b288c7dSWhitney Tsang public:
308b288c7dSWhitney Tsang   DGEdge() = delete;
318b288c7dSWhitney Tsang   /// Create an edge pointing to the given node \p N.
DGEdge(NodeType & N)328b288c7dSWhitney Tsang   explicit DGEdge(NodeType &N) : TargetNode(N) {}
DGEdge(const DGEdge<NodeType,EdgeType> & E)338b288c7dSWhitney Tsang   explicit DGEdge(const DGEdge<NodeType, EdgeType> &E)
348b288c7dSWhitney Tsang       : TargetNode(E.TargetNode) {}
358b288c7dSWhitney Tsang   DGEdge<NodeType, EdgeType> &operator=(const DGEdge<NodeType, EdgeType> &E) {
368b288c7dSWhitney Tsang     TargetNode = E.TargetNode;
378b288c7dSWhitney Tsang     return *this;
388b288c7dSWhitney Tsang   }
398b288c7dSWhitney Tsang 
408b288c7dSWhitney Tsang   /// Static polymorphism: delegate implementation (via isEqualTo) to the
418b288c7dSWhitney Tsang   /// derived class.
4292310454SBarry Revzin   bool operator==(const DGEdge &E) const {
4392310454SBarry Revzin     return getDerived().isEqualTo(E.getDerived());
4492310454SBarry Revzin   }
4592310454SBarry Revzin   bool operator!=(const DGEdge &E) const { return !operator==(E); }
468b288c7dSWhitney Tsang 
478b288c7dSWhitney Tsang   /// Retrieve the target node this edge connects to.
getTargetNode()488b288c7dSWhitney Tsang   const NodeType &getTargetNode() const { return TargetNode; }
getTargetNode()498b288c7dSWhitney Tsang   NodeType &getTargetNode() {
508b288c7dSWhitney Tsang     return const_cast<NodeType &>(
518b288c7dSWhitney Tsang         static_cast<const DGEdge<NodeType, EdgeType> &>(*this).getTargetNode());
528b288c7dSWhitney Tsang   }
538b288c7dSWhitney Tsang 
546ef63638STsang Whitney W.H   /// Set the target node this edge connects to.
setTargetNode(const NodeType & N)556ef63638STsang Whitney W.H   void setTargetNode(const NodeType &N) { TargetNode = N; }
566ef63638STsang Whitney W.H 
578b288c7dSWhitney Tsang protected:
588b288c7dSWhitney Tsang   // As the default implementation use address comparison for equality.
isEqualTo(const EdgeType & E)598b288c7dSWhitney Tsang   bool isEqualTo(const EdgeType &E) const { return this == &E; }
608b288c7dSWhitney Tsang 
618b288c7dSWhitney Tsang   // Cast the 'this' pointer to the derived type and return a reference.
getDerived()628b288c7dSWhitney Tsang   EdgeType &getDerived() { return *static_cast<EdgeType *>(this); }
getDerived()638b288c7dSWhitney Tsang   const EdgeType &getDerived() const {
648b288c7dSWhitney Tsang     return *static_cast<const EdgeType *>(this);
658b288c7dSWhitney Tsang   }
668b288c7dSWhitney Tsang 
678b288c7dSWhitney Tsang   // The target node this edge connects to.
688b288c7dSWhitney Tsang   NodeType &TargetNode;
698b288c7dSWhitney Tsang };
708b288c7dSWhitney Tsang 
718b288c7dSWhitney Tsang /// Represent a node in the directed graph.
728b288c7dSWhitney Tsang /// The node has a (possibly empty) list of outgoing edges.
738b288c7dSWhitney Tsang template <class NodeType, class EdgeType> class DGNode {
748b288c7dSWhitney Tsang public:
758b288c7dSWhitney Tsang   using EdgeListTy = SetVector<EdgeType *>;
768b288c7dSWhitney Tsang   using iterator = typename EdgeListTy::iterator;
778b288c7dSWhitney Tsang   using const_iterator = typename EdgeListTy::const_iterator;
788b288c7dSWhitney Tsang 
798b288c7dSWhitney Tsang   /// Create a node with a single outgoing edge \p E.
DGNode(EdgeType & E)808b288c7dSWhitney Tsang   explicit DGNode(EdgeType &E) : Edges() { Edges.insert(&E); }
818b288c7dSWhitney Tsang   DGNode() = default;
828b288c7dSWhitney Tsang 
DGNode(const DGNode<NodeType,EdgeType> & N)838b288c7dSWhitney Tsang   explicit DGNode(const DGNode<NodeType, EdgeType> &N) : Edges(N.Edges) {}
DGNode(DGNode<NodeType,EdgeType> && N)848b288c7dSWhitney Tsang   DGNode(DGNode<NodeType, EdgeType> &&N) : Edges(std::move(N.Edges)) {}
858b288c7dSWhitney Tsang 
868b288c7dSWhitney Tsang   DGNode<NodeType, EdgeType> &operator=(const DGNode<NodeType, EdgeType> &N) {
878b288c7dSWhitney Tsang     Edges = N.Edges;
888b288c7dSWhitney Tsang     return *this;
898b288c7dSWhitney Tsang   }
908b288c7dSWhitney Tsang   DGNode<NodeType, EdgeType> &operator=(const DGNode<NodeType, EdgeType> &&N) {
918b288c7dSWhitney Tsang     Edges = std::move(N.Edges);
928b288c7dSWhitney Tsang     return *this;
938b288c7dSWhitney Tsang   }
948b288c7dSWhitney Tsang 
958b288c7dSWhitney Tsang   /// Static polymorphism: delegate implementation (via isEqualTo) to the
968b288c7dSWhitney Tsang   /// derived class.
9792310454SBarry Revzin   friend bool operator==(const NodeType &M, const NodeType &N) {
9892310454SBarry Revzin     return M.isEqualTo(N);
9992310454SBarry Revzin   }
10092310454SBarry Revzin   friend bool operator!=(const NodeType &M, const NodeType &N) {
10192310454SBarry Revzin     return !(M == N);
10292310454SBarry Revzin   }
1038b288c7dSWhitney Tsang 
begin()1048b288c7dSWhitney Tsang   const_iterator begin() const { return Edges.begin(); }
end()1058b288c7dSWhitney Tsang   const_iterator end() const { return Edges.end(); }
begin()1068b288c7dSWhitney Tsang   iterator begin() { return Edges.begin(); }
end()1078b288c7dSWhitney Tsang   iterator end() { return Edges.end(); }
front()1088b288c7dSWhitney Tsang   const EdgeType &front() const { return *Edges.front(); }
front()1098b288c7dSWhitney Tsang   EdgeType &front() { return *Edges.front(); }
back()1108b288c7dSWhitney Tsang   const EdgeType &back() const { return *Edges.back(); }
back()1118b288c7dSWhitney Tsang   EdgeType &back() { return *Edges.back(); }
1128b288c7dSWhitney Tsang 
1138b288c7dSWhitney Tsang   /// Collect in \p EL, all the edges from this node to \p N.
1148b288c7dSWhitney Tsang   /// Return true if at least one edge was found, and false otherwise.
1158b288c7dSWhitney Tsang   /// Note that this implementation allows more than one edge to connect
1168b288c7dSWhitney Tsang   /// a given pair of nodes.
findEdgesTo(const NodeType & N,SmallVectorImpl<EdgeType * > & EL)1178b288c7dSWhitney Tsang   bool findEdgesTo(const NodeType &N, SmallVectorImpl<EdgeType *> &EL) const {
1188b288c7dSWhitney Tsang     assert(EL.empty() && "Expected the list of edges to be empty.");
1198b288c7dSWhitney Tsang     for (auto *E : Edges)
1208b288c7dSWhitney Tsang       if (E->getTargetNode() == N)
1218b288c7dSWhitney Tsang         EL.push_back(E);
1228b288c7dSWhitney Tsang     return !EL.empty();
1238b288c7dSWhitney Tsang   }
1248b288c7dSWhitney Tsang 
1258b288c7dSWhitney Tsang   /// Add the given edge \p E to this node, if it doesn't exist already. Returns
1268b288c7dSWhitney Tsang   /// true if the edge is added and false otherwise.
addEdge(EdgeType & E)1278b288c7dSWhitney Tsang   bool addEdge(EdgeType &E) { return Edges.insert(&E); }
1288b288c7dSWhitney Tsang 
1298b288c7dSWhitney Tsang   /// Remove the given edge \p E from this node, if it exists.
removeEdge(EdgeType & E)1308b288c7dSWhitney Tsang   void removeEdge(EdgeType &E) { Edges.remove(&E); }
1318b288c7dSWhitney Tsang 
1328b288c7dSWhitney Tsang   /// Test whether there is an edge that goes from this node to \p N.
hasEdgeTo(const NodeType & N)1338b288c7dSWhitney Tsang   bool hasEdgeTo(const NodeType &N) const {
1348b288c7dSWhitney Tsang     return (findEdgeTo(N) != Edges.end());
1358b288c7dSWhitney Tsang   }
1368b288c7dSWhitney Tsang 
1378b288c7dSWhitney Tsang   /// Retrieve the outgoing edges for the node.
getEdges()1388b288c7dSWhitney Tsang   const EdgeListTy &getEdges() const { return Edges; }
getEdges()1398b288c7dSWhitney Tsang   EdgeListTy &getEdges() {
1408b288c7dSWhitney Tsang     return const_cast<EdgeListTy &>(
1418b288c7dSWhitney Tsang         static_cast<const DGNode<NodeType, EdgeType> &>(*this).Edges);
1428b288c7dSWhitney Tsang   }
1438b288c7dSWhitney Tsang 
1448b288c7dSWhitney Tsang   /// Clear the outgoing edges.
clear()1458b288c7dSWhitney Tsang   void clear() { Edges.clear(); }
1468b288c7dSWhitney Tsang 
1478b288c7dSWhitney Tsang protected:
1488b288c7dSWhitney Tsang   // As the default implementation use address comparison for equality.
isEqualTo(const NodeType & N)1498b288c7dSWhitney Tsang   bool isEqualTo(const NodeType &N) const { return this == &N; }
1508b288c7dSWhitney Tsang 
1518b288c7dSWhitney Tsang   // Cast the 'this' pointer to the derived type and return a reference.
getDerived()1528b288c7dSWhitney Tsang   NodeType &getDerived() { return *static_cast<NodeType *>(this); }
getDerived()1538b288c7dSWhitney Tsang   const NodeType &getDerived() const {
1548b288c7dSWhitney Tsang     return *static_cast<const NodeType *>(this);
1558b288c7dSWhitney Tsang   }
1568b288c7dSWhitney Tsang 
1578b288c7dSWhitney Tsang   /// Find an edge to \p N. If more than one edge exists, this will return
1588b288c7dSWhitney Tsang   /// the first one in the list of edges.
findEdgeTo(const NodeType & N)1598b288c7dSWhitney Tsang   const_iterator findEdgeTo(const NodeType &N) const {
1608b288c7dSWhitney Tsang     return llvm::find_if(
1618b288c7dSWhitney Tsang         Edges, [&N](const EdgeType *E) { return E->getTargetNode() == N; });
1628b288c7dSWhitney Tsang   }
1638b288c7dSWhitney Tsang 
1648b288c7dSWhitney Tsang   // The list of outgoing edges.
1658b288c7dSWhitney Tsang   EdgeListTy Edges;
1668b288c7dSWhitney Tsang };
1678b288c7dSWhitney Tsang 
1688b288c7dSWhitney Tsang /// Directed graph
1698b288c7dSWhitney Tsang ///
1708b288c7dSWhitney Tsang /// The graph is represented by a table of nodes.
1718b288c7dSWhitney Tsang /// Each node contains a (possibly empty) list of outgoing edges.
1728b288c7dSWhitney Tsang /// Each edge contains the target node it connects to.
1738b288c7dSWhitney Tsang template <class NodeType, class EdgeType> class DirectedGraph {
1748b288c7dSWhitney Tsang protected:
1758b288c7dSWhitney Tsang   using NodeListTy = SmallVector<NodeType *, 10>;
1768b288c7dSWhitney Tsang   using EdgeListTy = SmallVector<EdgeType *, 10>;
1778b288c7dSWhitney Tsang public:
1788b288c7dSWhitney Tsang   using iterator = typename NodeListTy::iterator;
1798b288c7dSWhitney Tsang   using const_iterator = typename NodeListTy::const_iterator;
1808b288c7dSWhitney Tsang   using DGraphType = DirectedGraph<NodeType, EdgeType>;
1818b288c7dSWhitney Tsang 
1828b288c7dSWhitney Tsang   DirectedGraph() = default;
DirectedGraph(NodeType & N)1838b288c7dSWhitney Tsang   explicit DirectedGraph(NodeType &N) : Nodes() { addNode(N); }
DirectedGraph(const DGraphType & G)1848b288c7dSWhitney Tsang   DirectedGraph(const DGraphType &G) : Nodes(G.Nodes) {}
DirectedGraph(DGraphType && RHS)1858b288c7dSWhitney Tsang   DirectedGraph(DGraphType &&RHS) : Nodes(std::move(RHS.Nodes)) {}
1868b288c7dSWhitney Tsang   DGraphType &operator=(const DGraphType &G) {
1878b288c7dSWhitney Tsang     Nodes = G.Nodes;
1888b288c7dSWhitney Tsang     return *this;
1898b288c7dSWhitney Tsang   }
1908b288c7dSWhitney Tsang   DGraphType &operator=(const DGraphType &&G) {
1918b288c7dSWhitney Tsang     Nodes = std::move(G.Nodes);
1928b288c7dSWhitney Tsang     return *this;
1938b288c7dSWhitney Tsang   }
1948b288c7dSWhitney Tsang 
begin()1958b288c7dSWhitney Tsang   const_iterator begin() const { return Nodes.begin(); }
end()1968b288c7dSWhitney Tsang   const_iterator end() const { return Nodes.end(); }
begin()1978b288c7dSWhitney Tsang   iterator begin() { return Nodes.begin(); }
end()1988b288c7dSWhitney Tsang   iterator end() { return Nodes.end(); }
front()1998b288c7dSWhitney Tsang   const NodeType &front() const { return *Nodes.front(); }
front()2008b288c7dSWhitney Tsang   NodeType &front() { return *Nodes.front(); }
back()2018b288c7dSWhitney Tsang   const NodeType &back() const { return *Nodes.back(); }
back()2028b288c7dSWhitney Tsang   NodeType &back() { return *Nodes.back(); }
2038b288c7dSWhitney Tsang 
size()2048b288c7dSWhitney Tsang   size_t size() const { return Nodes.size(); }
2058b288c7dSWhitney Tsang 
2068b288c7dSWhitney Tsang   /// Find the given node \p N in the table.
findNode(const NodeType & N)2078b288c7dSWhitney Tsang   const_iterator findNode(const NodeType &N) const {
2088b288c7dSWhitney Tsang     return llvm::find_if(Nodes,
2098b288c7dSWhitney Tsang                          [&N](const NodeType *Node) { return *Node == N; });
2108b288c7dSWhitney Tsang   }
findNode(const NodeType & N)2118b288c7dSWhitney Tsang   iterator findNode(const NodeType &N) {
2128b288c7dSWhitney Tsang     return const_cast<iterator>(
2138b288c7dSWhitney Tsang         static_cast<const DGraphType &>(*this).findNode(N));
2148b288c7dSWhitney Tsang   }
2158b288c7dSWhitney Tsang 
2168b288c7dSWhitney Tsang   /// Add the given node \p N to the graph if it is not already present.
addNode(NodeType & N)2178b288c7dSWhitney Tsang   bool addNode(NodeType &N) {
2188b288c7dSWhitney Tsang     if (findNode(N) != Nodes.end())
2198b288c7dSWhitney Tsang       return false;
2208b288c7dSWhitney Tsang     Nodes.push_back(&N);
2218b288c7dSWhitney Tsang     return true;
2228b288c7dSWhitney Tsang   }
2238b288c7dSWhitney Tsang 
2248b288c7dSWhitney Tsang   /// Collect in \p EL all edges that are coming into node \p N. Return true
2258b288c7dSWhitney Tsang   /// if at least one edge was found, and false otherwise.
findIncomingEdgesToNode(const NodeType & N,SmallVectorImpl<EdgeType * > & EL)2268b288c7dSWhitney Tsang   bool findIncomingEdgesToNode(const NodeType &N, SmallVectorImpl<EdgeType*> &EL) const {
2278b288c7dSWhitney Tsang     assert(EL.empty() && "Expected the list of edges to be empty.");
2288b288c7dSWhitney Tsang     EdgeListTy TempList;
2298b288c7dSWhitney Tsang     for (auto *Node : Nodes) {
2308b288c7dSWhitney Tsang       if (*Node == N)
2318b288c7dSWhitney Tsang         continue;
2328b288c7dSWhitney Tsang       Node->findEdgesTo(N, TempList);
2331d0bc055SKazu Hirata       llvm::append_range(EL, TempList);
2348b288c7dSWhitney Tsang       TempList.clear();
2358b288c7dSWhitney Tsang     }
2368b288c7dSWhitney Tsang     return !EL.empty();
2378b288c7dSWhitney Tsang   }
2388b288c7dSWhitney Tsang 
2398b288c7dSWhitney Tsang   /// Remove the given node \p N from the graph. If the node has incoming or
2408b288c7dSWhitney Tsang   /// outgoing edges, they are also removed. Return true if the node was found
2418b288c7dSWhitney Tsang   /// and then removed, and false if the node was not found in the graph to
2428b288c7dSWhitney Tsang   /// begin with.
removeNode(NodeType & N)2438b288c7dSWhitney Tsang   bool removeNode(NodeType &N) {
2448b288c7dSWhitney Tsang     iterator IT = findNode(N);
2458b288c7dSWhitney Tsang     if (IT == Nodes.end())
2468b288c7dSWhitney Tsang       return false;
2478b288c7dSWhitney Tsang     // Remove incoming edges.
2488b288c7dSWhitney Tsang     EdgeListTy EL;
2498b288c7dSWhitney Tsang     for (auto *Node : Nodes) {
2508b288c7dSWhitney Tsang       if (*Node == N)
2518b288c7dSWhitney Tsang         continue;
2528b288c7dSWhitney Tsang       Node->findEdgesTo(N, EL);
2538b288c7dSWhitney Tsang       for (auto *E : EL)
2548b288c7dSWhitney Tsang         Node->removeEdge(*E);
2558b288c7dSWhitney Tsang       EL.clear();
2568b288c7dSWhitney Tsang     }
2578b288c7dSWhitney Tsang     N.clear();
2588b288c7dSWhitney Tsang     Nodes.erase(IT);
2598b288c7dSWhitney Tsang     return true;
2608b288c7dSWhitney Tsang   }
2618b288c7dSWhitney Tsang 
2628b288c7dSWhitney Tsang   /// Assuming nodes \p Src and \p Dst are already in the graph, connect node \p
2638b288c7dSWhitney Tsang   /// Src to node \p Dst using the provided edge \p E. Return true if \p Src is
2648b288c7dSWhitney Tsang   /// not already connected to \p Dst via \p E, and false otherwise.
connect(NodeType & Src,NodeType & Dst,EdgeType & E)2658b288c7dSWhitney Tsang   bool connect(NodeType &Src, NodeType &Dst, EdgeType &E) {
2668b288c7dSWhitney Tsang     assert(findNode(Src) != Nodes.end() && "Src node should be present.");
2678b288c7dSWhitney Tsang     assert(findNode(Dst) != Nodes.end() && "Dst node should be present.");
2688b288c7dSWhitney Tsang     assert((E.getTargetNode() == Dst) &&
2698b288c7dSWhitney Tsang            "Target of the given edge does not match Dst.");
2708b288c7dSWhitney Tsang     return Src.addEdge(E);
2718b288c7dSWhitney Tsang   }
2728b288c7dSWhitney Tsang 
2738b288c7dSWhitney Tsang protected:
2748b288c7dSWhitney Tsang   // The list of nodes in the graph.
2758b288c7dSWhitney Tsang   NodeListTy Nodes;
2768b288c7dSWhitney Tsang };
2778b288c7dSWhitney Tsang 
2788b288c7dSWhitney Tsang } // namespace llvm
2798b288c7dSWhitney Tsang 
2808b288c7dSWhitney Tsang #endif // LLVM_ADT_DIRECTEDGRAPH_H
281