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