DotGraph: add EdgeRef and ChildEdgeIteratorType

Add EdgeRef and ChildEdgeIteratorType to GraphTraits<DotNode *> and to
GraphTraits<const DotNode *>.

This allows iterating on edges of DotGraphs, which will be useful for
some testing on edge properties.
This commit is contained in:
Pietro Fezzardi
2020-03-02 09:19:58 +01:00
committed by Alessandro Di Federico
parent a955cb9a50
commit 2bf702b74b
2 changed files with 110 additions and 22 deletions
+109 -22
View File
@@ -8,6 +8,7 @@
// Standard includes
#include <cstdlib>
#include <iosfwd>
#include <type_traits>
#include <vector>
// LLVM includes
@@ -21,17 +22,24 @@ class DotNode {
// Define the container for the successors and some useful helpers.
public:
using child_container = llvm::SmallVector<DotNode *, 2>;
using child_container = std::vector<DotNode *>;
using child_iterator = typename child_container::iterator;
using child_const_iterator = typename child_container::const_iterator;
using child_range = llvm::iterator_range<child_iterator>;
using child_const_range = llvm::iterator_range<child_const_iterator>;
using edge_container = std::vector<std::pair<DotNode *, DotNode *>>;
using edge_iterator = typename edge_container::iterator;
using edge_const_iterator = typename edge_container::const_iterator;
using edge_range = llvm::iterator_range<edge_iterator>;
using edge_const_range = llvm::iterator_range<edge_const_iterator>;
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<DotNode> &P) { return P.get(); }
using PtrFromRefT = DotNode *(*) (std::unique_ptr<DotNode> &P);
static const DotNode *constPtrFromRef(const std::unique_ptr<DotNode> &P) {
return P.get();
}
using PtrFromRefT = DotNode *(*) (std::unique_ptr<DotNode> &P);
using CPtrFromRefT = const DotNode *(*) (const std::unique_ptr<DotNode> &P);
public:
using child_container = std::vector<std::unique_ptr<DotNode>>;
using internal_iterator = typename child_container::iterator;
using internal_const_iterator = typename child_container::const_iterator;
using child_iterator = llvm::mapped_iterator<internal_iterator, PtrFromRefT>;
using child_const_iterator = llvm::mapped_iterator<internal_const_iterator,
CPtrFromRefT>;
using child_range = llvm::iterator_range<child_iterator>;
using child_const_range = llvm::iterator_range<child_const_iterator>;
using node_container = std::vector<std::unique_ptr<DotNode>>;
using internal_iterator = typename node_container::iterator;
using node_iterator = llvm::mapped_iterator<internal_iterator, PtrFromRefT>;
using node_range = llvm::iterator_range<node_iterator>;
using internal_const_iterator = typename node_container::const_iterator;
using node_const_iterator = llvm::mapped_iterator<internal_const_iterator,
CPtrFromRefT>;
using node_const_range = llvm::iterator_range<node_const_iterator>;
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<DotNode *> {
public:
using NodeRef = DotNode *;
using ChildIteratorType = DotNode::child_iterator;
using EdgeRef = std::pair<NodeRef, NodeRef>;
using ChildEdgeIteratorType = DotNode::edge_iterator;
protected:
template<typename T>
using unref_t = std::remove_reference_t<T>;
using ChildT = unref_t<decltype(*std::declval<ChildIteratorType>())>;
static_assert(std::is_same_v<NodeRef, ChildT>);
using ChildEdgeT = unref_t<decltype(*std::declval<ChildEdgeIteratorType>())>;
static_assert(std::is_same_v<EdgeRef, ChildEdgeT>);
public:
static inline ChildIteratorType child_begin(NodeRef N) {
return N->successors().begin();
}
@@ -127,25 +161,78 @@ struct GraphTraits<DotNode *> {
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<const DotNode *> {
using NodeRef = const DotNode *;
using ChildIteratorType = DotNode::child_const_iterator;
using EdgeRef = std::pair<const NodeRef, const NodeRef>;
protected:
static const DotNode *toConstNode(const NodeRef P) { return P; }
using ConstNode = const DotNode *(*) (const NodeRef);
using const_node_it = llvm::mapped_iterator<DotNode::child_const_iterator,
ConstNode>;
static std::pair<const NodeRef, const NodeRef> toConstEdge(const EdgeRef E) {
return E;
}
using ConstEdge = std::pair<const NodeRef, const NodeRef> (*)(const EdgeRef);
using const_edge_it = llvm::mapped_iterator<DotNode::edge_const_iterator,
ConstEdge>;
public:
using ChildIteratorType = const_node_it;
using ChildEdgeIteratorType = const_edge_it;
protected:
template<typename T>
using unref_t = std::remove_reference_t<T>;
using ChildT = unref_t<decltype(*std::declval<ChildIteratorType>())>;
static_assert(std::is_same_v<NodeRef, ChildT>);
using ChildEdgeT = unref_t<decltype(*std::declval<ChildEdgeIteratorType>())>;
static_assert(std::is_same_v<EdgeRef, ChildEdgeT>);
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<DotGraph *> : public GraphTraits<DotNode *> {
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<DotGraph *> : public GraphTraits<DotNode *> {
template<>
struct GraphTraits<const DotGraph *> : public GraphTraits<const DotNode *> {
using nodes_iterator = DotGraph::child_const_iterator;
using nodes_iterator = DotGraph::node_const_iterator;
static NodeRef getEntryNode(const DotGraph *G) { return G->getEntryNode(); }
+1
View File
@@ -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) {