diff --git a/include/revng/UnitTestHelpers/DotGraphObject.h b/include/revng/UnitTestHelpers/DotGraphObject.h index 3d81575c5..5cf1a1b8c 100644 --- a/include/revng/UnitTestHelpers/DotGraphObject.h +++ b/include/revng/UnitTestHelpers/DotGraphObject.h @@ -8,6 +8,7 @@ // Standard includes #include #include +#include #include // LLVM includes @@ -21,17 +22,24 @@ class DotNode { // Define the container for the successors and some useful helpers. public: - using child_container = llvm::SmallVector; + 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; // Actual container for the pointers to the successors nodes. child_container Successors; + edge_container SuccEdges; public: DotNode(llvm::StringRef Name) : Name(Name) {} @@ -45,6 +53,14 @@ public: 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()); + } + llvm::StringRef getName() const { return Name; } void addSuccessor(DotNode *Successor); @@ -53,25 +69,28 @@ public: 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 PtrFromRefT = DotNode *(*) (std::unique_ptr &P); using CPtrFromRefT = const DotNode *(*) (const std::unique_ptr &P); public: - using child_container = std::vector>; - using internal_iterator = typename child_container::iterator; - using internal_const_iterator = typename child_container::const_iterator; - using child_iterator = llvm::mapped_iterator; - using child_const_iterator = llvm::mapped_iterator; - using child_range = llvm::iterator_range; - using child_const_range = llvm::iterator_range; + 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: - child_container Nodes; + node_container Nodes; DotNode *EntryNode; public: @@ -82,21 +101,21 @@ public: void parseDotFromFile(llvm::StringRef FileName, llvm::StringRef EntryName = ""); - child_range nodes() { return llvm::make_range(begin(), end()); } + node_range nodes() { return llvm::make_range(begin(), end()); } - child_const_range nodes() const { return llvm::make_range(begin(), end()); } + node_const_range nodes() const { return llvm::make_range(begin(), end()); } - child_iterator begin() { + node_iterator begin() { return llvm::map_iterator(Nodes.begin(), ptrFromRef); } - child_const_iterator begin() const { + node_const_iterator begin() const { return llvm::map_iterator(Nodes.begin(), constPtrFromRef); } - child_iterator end() { return llvm::map_iterator(Nodes.end(), ptrFromRef); } + node_iterator end() { return llvm::map_iterator(Nodes.end(), ptrFromRef); } - child_const_iterator end() const { + node_const_iterator end() const { return llvm::map_iterator(Nodes.end(), constPtrFromRef); } @@ -117,9 +136,24 @@ 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 inline ChildIteratorType child_begin(NodeRef N) { return N->successors().begin(); } @@ -127,25 +161,78 @@ struct GraphTraits { static inline 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; }; }; template<> struct GraphTraits { using NodeRef = const DotNode *; - using ChildIteratorType = DotNode::child_const_iterator; + 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 inline ChildIteratorType child_begin(NodeRef N) { - return N->successors().begin(); + return llvm::map_iterator(N->successors().begin(), toConstNode); } static inline ChildIteratorType child_end(NodeRef N) { - return N->successors().end(); + return llvm::map_iterator(N->successors().end(), toConstNode); } + +public: + 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; }; }; template<> struct GraphTraits : public GraphTraits { - using nodes_iterator = DotGraph::child_iterator; + using nodes_iterator = DotGraph::node_iterator; static NodeRef getEntryNode(DotGraph *G) { return G->getEntryNode(); } @@ -158,7 +245,7 @@ struct GraphTraits : public GraphTraits { template<> struct GraphTraits : public GraphTraits { - using nodes_iterator = DotGraph::child_const_iterator; + using nodes_iterator = DotGraph::node_const_iterator; static NodeRef getEntryNode(const DotGraph *G) { return G->getEntryNode(); } diff --git a/lib/UnitTestHelpers/DotGraphObject.cpp b/lib/UnitTestHelpers/DotGraphObject.cpp index a992774e4..2240bfd3c 100644 --- a/lib/UnitTestHelpers/DotGraphObject.cpp +++ b/lib/UnitTestHelpers/DotGraphObject.cpp @@ -33,6 +33,7 @@ void DotNode::addSuccessor(DotNode *NewSuccessor) { revng_assert(not Found); Successors.push_back(NewSuccessor); + SuccEdges.push_back(std::make_pair(this, NewSuccessor)); } void DotGraph::parseDotImpl(std::ifstream &F, llvm::StringRef EntryName) {