#pragma once // // This file is distributed under the MIT License. See LICENSE.md for details. // #include #include #include #include #include "llvm/ADT/GraphTraits.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" namespace llvm { class raw_ostream; } // end namespace llvm class DotGraph; class DotNode { // Define the container for the successors and some useful helpers. public: using child_container = std::vector; using child_iterator = typename child_container::iterator; using child_const_iterator = typename child_container::const_iterator; using child_range = llvm::iterator_range; using child_const_range = llvm::iterator_range; using edge_container = std::vector>; using edge_iterator = typename edge_container::iterator; using edge_const_iterator = typename edge_container::const_iterator; using edge_range = llvm::iterator_range; using edge_const_range = llvm::iterator_range; private: llvm::SmallString<8> Name; DotGraph *Parent = nullptr; // Actual container for the pointers to the successors nodes. child_container Successors; edge_container SuccEdges; child_container Predecessors; edge_container PredEdges; public: DotNode(llvm::StringRef N, DotGraph *P) : Name(N), Parent(P) {} void printAsOperand(llvm::raw_ostream &O, bool /* PrintType */) const; DotGraph *getParent() { return Parent; } child_range successors() { return llvm::make_range(Successors.begin(), Successors.end()); } child_const_range successors() const { return llvm::make_range(Successors.begin(), Successors.end()); } edge_range edge_successors() { return llvm::make_range(SuccEdges.begin(), SuccEdges.end()); } edge_const_range edge_successors() const { return llvm::make_range(SuccEdges.begin(), SuccEdges.end()); } child_range predecessors() { return llvm::make_range(Predecessors.begin(), Predecessors.end()); } child_const_range predecessors() const { return llvm::make_range(Predecessors.begin(), Predecessors.end()); } edge_range edge_predecessors() { return llvm::make_range(PredEdges.begin(), PredEdges.end()); } edge_const_range edge_predecessors() const { return llvm::make_range(PredEdges.begin(), PredEdges.end()); } llvm::StringRef getName() const { return Name; } void addSuccessor(DotNode *Successor); void addPredecessor(DotNode *Predecessor); }; class DotGraph { static DotNode *ptrFromRef(std::unique_ptr &P) { return P.get(); } using PtrFromRefT = DotNode *(*) (std::unique_ptr &P); static const DotNode *constPtrFromRef(const std::unique_ptr &P) { return P.get(); } using CPtrFromRefT = const DotNode *(*) (const std::unique_ptr &P); public: using node_container = std::vector>; using internal_iterator = typename node_container::iterator; using node_iterator = llvm::mapped_iterator; using node_range = llvm::iterator_range; using internal_const_iterator = typename node_container::const_iterator; using node_const_iterator = llvm::mapped_iterator; using node_const_range = llvm::iterator_range; private: node_container Nodes; DotNode *EntryNode = nullptr; public: DotGraph() {} public: /// Parse a particularly well-formed GraphViz from a file. void parseDotFromFile(llvm::StringRef FileName, llvm::StringRef EntryName = {}); node_range nodes() { return llvm::make_range(begin(), end()); } node_const_range nodes() const { return llvm::make_range(begin(), end()); } node_iterator begin() { return llvm::map_iterator(Nodes.begin(), ptrFromRef); } node_const_iterator begin() const { return llvm::map_iterator(Nodes.begin(), constPtrFromRef); } node_iterator end() { return llvm::map_iterator(Nodes.end(), ptrFromRef); } node_const_iterator end() const { return llvm::map_iterator(Nodes.end(), constPtrFromRef); } size_t size() const { return Nodes.size(); } DotNode *getEntryNode() const { return EntryNode; } DotNode *addNode(llvm::StringRef Name); DotNode *getNodeByName(llvm::StringRef Name); private: /// Actual implementation of the parser. void parseDotImpl(std::ifstream &F, llvm::StringRef EntryName); }; namespace llvm { template<> struct GraphTraits { public: using NodeRef = DotNode *; using ChildIteratorType = DotNode::child_iterator; using EdgeRef = std::pair; using ChildEdgeIteratorType = DotNode::edge_iterator; protected: template using unref_t = std::remove_reference_t; using ChildT = unref_t())>; static_assert(std::is_same_v); using ChildEdgeT = unref_t())>; static_assert(std::is_same_v); public: static ChildIteratorType child_begin(NodeRef N) { return N->successors().begin(); } static ChildIteratorType child_end(NodeRef N) { return N->successors().end(); } public: static ChildEdgeIteratorType child_edge_begin(NodeRef N) { return N->edge_successors().begin(); } static ChildEdgeIteratorType child_edge_end(NodeRef N) { return N->edge_successors().end(); } static NodeRef edge_dest(EdgeRef E) { return E.second; }; static NodeRef getEntryNode(NodeRef N) { return N; }; }; template<> struct GraphTraits> { using NodeRef = GraphTraits::NodeRef; using EdgeRef = GraphTraits::EdgeRef; using ChildIteratorType = GraphTraits::ChildIteratorType; using ChildEdgeIteratorType = GraphTraits::ChildEdgeIteratorType; static ChildIteratorType child_begin(NodeRef N) { return N->predecessors().begin(); } static ChildIteratorType child_end(NodeRef N) { return N->predecessors().end(); } static ChildEdgeIteratorType child_edge_begin(NodeRef N) { return N->edge_predecessors().begin(); } static ChildEdgeIteratorType child_edge_end(NodeRef N) { return N->edge_predecessors().end(); } static NodeRef edge_dest(EdgeRef E) { return E.first; }; static NodeRef getEntryNode(NodeRef N) { return N; }; }; template<> struct GraphTraits { using NodeRef = const DotNode *; using EdgeRef = std::pair; protected: static const DotNode *toConstNode(const NodeRef P) { return P; } using ConstNode = const DotNode *(*) (const NodeRef); using const_node_it = llvm::mapped_iterator; static std::pair toConstEdge(const EdgeRef E) { return E; } using ConstEdge = std::pair (*)(const EdgeRef); using const_edge_it = llvm::mapped_iterator; public: using ChildIteratorType = const_node_it; using ChildEdgeIteratorType = const_edge_it; protected: template using unref_t = std::remove_reference_t; using ChildT = unref_t())>; static_assert(std::is_same_v); using ChildEdgeT = unref_t())>; static_assert(std::is_same_v); public: static ChildIteratorType child_begin(NodeRef N) { return llvm::map_iterator(N->successors().begin(), toConstNode); } static ChildIteratorType child_end(NodeRef N) { return llvm::map_iterator(N->successors().end(), toConstNode); } static ChildEdgeIteratorType child_edge_begin(NodeRef N) { return llvm::map_iterator(N->edge_successors().begin(), toConstEdge); } static ChildEdgeIteratorType child_edge_end(NodeRef N) { return llvm::map_iterator(N->edge_successors().end(), toConstEdge); } static NodeRef edge_dest(EdgeRef E) { return E.second; }; static NodeRef getEntryNode(NodeRef N) { return N; }; }; template<> struct GraphTraits> { using Node = const DotNode *; using NodeRef = GraphTraits::NodeRef; using EdgeRef = GraphTraits::EdgeRef; using ChildIteratorType = GraphTraits::ChildIteratorType; using ChildEdgeIteratorType = GraphTraits::ChildEdgeIteratorType; protected: static const DotNode *toConstNode(const NodeRef P) { return P; } static std::pair toConstEdge(const EdgeRef E) { return E; } public: static ChildIteratorType child_begin(NodeRef N) { return llvm::map_iterator(N->predecessors().begin(), toConstNode); } static ChildIteratorType child_end(NodeRef N) { return llvm::map_iterator(N->predecessors().end(), toConstNode); } static ChildEdgeIteratorType child_edge_begin(NodeRef N) { return llvm::map_iterator(N->edge_predecessors().begin(), toConstEdge); } static ChildEdgeIteratorType child_edge_end(NodeRef N) { return llvm::map_iterator(N->edge_predecessors().end(), toConstEdge); } static NodeRef edge_dest(EdgeRef E) { return E.first; }; static NodeRef getEntryNode(NodeRef N) { return N; }; }; template<> struct GraphTraits : public GraphTraits { using nodes_iterator = DotGraph::node_iterator; static NodeRef getEntryNode(DotGraph *G) { return G->getEntryNode(); } static nodes_iterator nodes_begin(DotGraph *G) { return G->begin(); } static nodes_iterator nodes_end(DotGraph *G) { return G->end(); } static size_t size(DotGraph *G) { return G->size(); } }; template<> struct GraphTraits> : public GraphTraits> { using nodes_iterator = DotGraph::node_iterator; static NodeRef getEntryNode(DotGraph *G) { return G->getEntryNode(); } static nodes_iterator nodes_begin(DotGraph *G) { return G->begin(); } static nodes_iterator nodes_end(DotGraph *G) { return G->end(); } static size_t size(DotGraph *G) { return G->size(); } }; template<> struct GraphTraits : public GraphTraits { using nodes_iterator = DotGraph::node_const_iterator; static NodeRef getEntryNode(const DotGraph *G) { return G->getEntryNode(); } static nodes_iterator nodes_begin(const DotGraph *G) { return G->begin(); } static nodes_iterator nodes_end(const DotGraph *G) { return G->end(); } static size_t size(const DotGraph *G) { return G->size(); } }; template<> struct GraphTraits> : public GraphTraits> { using nodes_iterator = DotGraph::node_const_iterator; static NodeRef getEntryNode(const DotGraph *G) { return G->getEntryNode(); } static nodes_iterator nodes_begin(const DotGraph *G) { return G->begin(); } static nodes_iterator nodes_end(const DotGraph *G) { return G->end(); } static size_t size(const DotGraph *G) { return G->size(); } }; } // namespace llvm