forked from revng/revng
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsubgraph.h
157 lines (127 loc) · 4.75 KB
/
subgraph.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
#ifndef _SUBGRAPH_H
#define _SUBGRAPH_H
//
// This file is distributed under the MIT License. See LICENSE.md for details.
//
// LLVM includes
#include "llvm/ADT/GraphTraits.h"
#include "llvm/ADT/SmallVector.h"
/// \brief Data structure implementing a subgraph of an object providing
/// GraphTraits
///
/// This class represents a "subgraph", i.e., given an object implementing
/// GraphTraits, this class expose a portion of the graph (identified by a
/// whitelist of nodes). The main benefit of such a class is to be able to run
/// graph-oriented algorithms on portion of a graph.
template<typename InnerNodeType>
class SubGraph {
public:
/// \brief A node of the subgraph
///
/// A node is simply a reference to the original node decorated with a vector
/// of successor. In theory we could avoid storing the vector and explore the
/// successors directly of the underlying node (filtering out all the
/// non-whitelisted ones), but this would require a reference to the graph
/// object, which is something we'd like to avoid.
class Node {
public:
Node(InnerNodeType Value) : Value(Value) { }
/// \brief Return the underlying node
InnerNodeType get() const { return Value; }
private:
friend class SubGraph;
friend struct llvm::GraphTraits<SubGraph<InnerNodeType>>;
llvm::SmallVector<Node *, 2> Children;
InnerNodeType Value;
};
using NodeType = Node;
private:
using ParentGraphTraits = llvm::GraphTraits<InnerNodeType>;
using ChildIteratorType = typename llvm::SmallVector<Node *, 2>::iterator;
using nodes_iterator = typename std::set<Node>::iterator;
friend llvm::GraphTraits<SubGraph<InnerNodeType>>;
public:
/// Construct a subgraph starting from the node \p Entry and considering only
/// nodes in \p WhiteList.
///
/// Note: this method has a cost proportional to the size of the subgraph,
/// since it basically creates a copy of it.
SubGraph(InnerNodeType Entry, const std::set<InnerNodeType> WhiteList) {
// Create a node for the entry node, and take note of it
EntryNode = &findOrInsert(Entry);
// We want to rebuild the graph internally considering only the whitelisted
// nodes
OnceQueue<InnerNodeType> Queue;
Queue.insert(Entry);
while (!Queue.empty()) {
InnerNodeType Value = Queue.pop();
// Get (or create) the current node
Node &NewNode = findOrInsert(Value);
// Iterate over successors
auto Successors = make_range(ParentGraphTraits::child_begin(Value),
ParentGraphTraits::child_end(Value));
for (InnerNodeType Successor : Successors) {
// If it's whitelisted, register it as a child and enqueue it
if (WhiteList.count(Successor) != 0) {
NewNode.Children.push_back(&findOrInsert(Successor));
Queue.insert(Successor);
}
}
}
}
private:
struct CompareNodes {
bool operator() (const Node &A, const Node &B) const {
return A.get() < B.get();
}
};
/// \brief Get the node with value \p Value, of, if absent, insert it in the
/// graph
Node &findOrInsert(InnerNodeType Value) {
// We can't use find, because it would use the equality comparison operator
// instead of our CompareNodes. Plus we have to cast away constness, because
// std::set entries are always const (since you might change the key), but
// we don't. Users of this function will never change the key, just
// increment the list of successors.
auto It = Nodes.lower_bound(Node(Value));
if (It != Nodes.end() && It->get() == Value)
return const_cast<Node &>(*It);
else
return const_cast<Node &>(*Nodes.emplace_hint(It, Value));
}
private:
// We define a custom comparator so that Node still preserves the default
// comparison operators
std::set<Node, CompareNodes> Nodes;
Node *EntryNode;
};
namespace llvm {
/// \brief Specialization of GraphTraits for SubGraph
template<typename InnerNodeType>
struct GraphTraits<SubGraph<InnerNodeType>> {
using GraphType = SubGraph<InnerNodeType>;
using NodeType = typename GraphType::Node;
using ChildIteratorType = typename GraphType::ChildIteratorType;
using nodes_iterator = typename GraphType::nodes_iterator;
// TODO: here G should be const
static NodeType *getEntryNode(GraphType &G) {
return G.EntryNode;
}
static ChildIteratorType child_begin(NodeType *Parent) {
return Parent->Children.begin();
}
static ChildIteratorType child_end(NodeType *Parent) {
return Parent->Children.end();
}
static nodes_iterator nodes_begin(GraphType *G) {
return G->Nodes.begin();
}
static nodes_iterator nodes_end(GraphType *G) {
return G->Nodes.end();
}
static unsigned size(GraphType *G) {
return G->Nodes.size();
}
};
}
#endif // _SUBGRAPH_H