blob: a4d34a8a4be34d228f4fe37ab3ea68b5cf10bed7 [file] [log] [blame]
Andrew Scull5e1ddfa2018-08-14 10:06:54 +01001//===-- Graph.h - XRay Graph Class ------------------------------*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// A Graph Datatype for XRay.
11//
12//===----------------------------------------------------------------------===//
13
14#ifndef LLVM_XRAY_GRAPH_T_H
15#define LLVM_XRAY_GRAPH_T_H
16
17#include <initializer_list>
18#include <stdint.h>
19#include <type_traits>
20#include <utility>
21
22#include "llvm/ADT/DenseMap.h"
23#include "llvm/ADT/DenseSet.h"
24#include "llvm/ADT/iterator.h"
25#include "llvm/Support/Error.h"
26
27namespace llvm {
28namespace xray {
29
30/// A Graph object represents a Directed Graph and is used in XRay to compute
31/// and store function call graphs and associated statistical information.
32///
33/// The graph takes in four template parameters, these are:
34/// - VertexAttribute, this is a structure which is stored for each vertex.
35/// Must be DefaultConstructible, CopyConstructible, CopyAssignable and
36/// Destructible.
37/// - EdgeAttribute, this is a structure which is stored for each edge
38/// Must be DefaultConstructible, CopyConstructible, CopyAssignable and
39/// Destructible.
40/// - EdgeAttribute, this is a structure which is stored for each variable
41/// - VI, this is a type over which DenseMapInfo is defined and is the type
42/// used look up strings, available as VertexIdentifier.
43/// - If the built in DenseMapInfo is not defined, provide a specialization
44/// class type here.
45///
46/// Graph is CopyConstructible, CopyAssignable, MoveConstructible and
47/// MoveAssignable but is not EqualityComparible or LessThanComparible.
48///
49/// Usage Example Graph with weighted edges and vertices:
50/// Graph<int, int, int> G;
51///
52/// G[1] = 0;
53/// G[2] = 2;
54/// G[{1,2}] = 1;
55/// G[{2,1}] = -1;
56/// for(const auto &v : G.vertices()){
57/// // Do something with the vertices in the graph;
58/// }
59/// for(const auto &e : G.edges()){
60/// // Do something with the edges in the graph;
61/// }
62///
63/// Usage Example with StrRef keys.
64/// Graph<int, double, StrRef> StrG;
65/// char va[] = "Vertex A";
66/// char vaa[] = "Vertex A";
67/// char vb[] = "Vertex B"; // Vertices are referenced by String Refs.
68/// G[va] = 0;
69/// G[vb] = 1;
70/// G[{va, vb}] = 1.0;
71/// cout() << G[vaa] << " " << G[{vaa, vb}]; //prints "0 1.0".
72///
73template <typename VertexAttribute, typename EdgeAttribute,
74 typename VI = int32_t>
75class Graph {
76public:
77 /// These objects are used to name edges and vertices in the graph.
78 typedef VI VertexIdentifier;
79 typedef std::pair<VI, VI> EdgeIdentifier;
80
81 /// This type is the value_type of all iterators which range over vertices,
82 /// Determined by the Vertices DenseMap
83 using VertexValueType =
84 detail::DenseMapPair<VertexIdentifier, VertexAttribute>;
85
86 /// This type is the value_type of all iterators which range over edges,
87 /// Determined by the Edges DenseMap.
88 using EdgeValueType = detail::DenseMapPair<EdgeIdentifier, EdgeAttribute>;
89
90 using size_type = std::size_t;
91
92private:
93 /// The type used for storing the EdgeAttribute for each edge in the graph
94 using EdgeMapT = DenseMap<EdgeIdentifier, EdgeAttribute>;
95
96 /// The type used for storing the VertexAttribute for each vertex in
97 /// the graph.
98 using VertexMapT = DenseMap<VertexIdentifier, VertexAttribute>;
99
100 /// The type used for storing the edges entering a vertex. Indexed by
101 /// the VertexIdentifier of the start of the edge. Only used to determine
102 /// where the incoming edges are, the EdgeIdentifiers are stored in an
103 /// InnerEdgeMapT.
104 using NeighborSetT = DenseSet<VertexIdentifier>;
105
106 /// The type storing the InnerInvGraphT corresponding to each vertex in
107 /// the graph (When a vertex has an incoming edge incident to it)
108 using NeighborLookupT = DenseMap<VertexIdentifier, NeighborSetT>;
109
110private:
111 /// Stores the map from the start and end vertex of an edge to it's
112 /// EdgeAttribute
113 EdgeMapT Edges;
114
115 /// Stores the map from VertexIdentifier to VertexAttribute
116 VertexMapT Vertices;
117
118 /// Allows fast lookup for the incoming edge set of any given vertex.
119 NeighborLookupT InNeighbors;
120
121 /// Allows fast lookup for the outgoing edge set of any given vertex.
122 NeighborLookupT OutNeighbors;
123
124 /// An Iterator adapter using an InnerInvGraphT::iterator as a base iterator,
125 /// and storing the VertexIdentifier the iterator range comes from. The
126 /// dereference operator is then performed using a pointer to the graph's edge
127 /// set.
128 template <bool IsConst, bool IsOut,
129 typename BaseIt = typename NeighborSetT::const_iterator,
130 typename T = typename std::conditional<IsConst, const EdgeValueType,
131 EdgeValueType>::type>
132 class NeighborEdgeIteratorT
133 : public iterator_adaptor_base<
134 NeighborEdgeIteratorT<IsConst, IsOut>, BaseIt,
135 typename std::iterator_traits<BaseIt>::iterator_category, T> {
136 using InternalEdgeMapT =
137 typename std::conditional<IsConst, const EdgeMapT, EdgeMapT>::type;
138
139 friend class NeighborEdgeIteratorT<false, IsOut, BaseIt, EdgeValueType>;
140 friend class NeighborEdgeIteratorT<true, IsOut, BaseIt,
141 const EdgeValueType>;
142
143 InternalEdgeMapT *MP;
144 VertexIdentifier SI;
145
146 public:
147 template <bool IsConstDest,
148 typename = typename std::enable_if<IsConstDest && !IsConst>::type>
149 operator NeighborEdgeIteratorT<IsConstDest, IsOut, BaseIt,
150 const EdgeValueType>() const {
151 return NeighborEdgeIteratorT<IsConstDest, IsOut, BaseIt,
152 const EdgeValueType>(this->I, MP, SI);
153 }
154
155 NeighborEdgeIteratorT() = default;
156 NeighborEdgeIteratorT(BaseIt _I, InternalEdgeMapT *_MP,
157 VertexIdentifier _SI)
158 : iterator_adaptor_base<
159 NeighborEdgeIteratorT<IsConst, IsOut>, BaseIt,
160 typename std::iterator_traits<BaseIt>::iterator_category, T>(_I),
161 MP(_MP), SI(_SI) {}
162
163 T &operator*() const {
164 if (!IsOut)
165 return *(MP->find({*(this->I), SI}));
166 else
167 return *(MP->find({SI, *(this->I)}));
168 }
169 };
170
171public:
172 /// A const iterator type for iterating through the set of edges entering a
173 /// vertex.
174 ///
175 /// Has a const EdgeValueType as its value_type
176 using ConstInEdgeIterator = NeighborEdgeIteratorT<true, false>;
177
178 /// An iterator type for iterating through the set of edges leaving a vertex.
179 ///
180 /// Has an EdgeValueType as its value_type
181 using InEdgeIterator = NeighborEdgeIteratorT<false, false>;
182
183 /// A const iterator type for iterating through the set of edges entering a
184 /// vertex.
185 ///
186 /// Has a const EdgeValueType as its value_type
187 using ConstOutEdgeIterator = NeighborEdgeIteratorT<true, true>;
188
189 /// An iterator type for iterating through the set of edges leaving a vertex.
190 ///
191 /// Has an EdgeValueType as its value_type
192 using OutEdgeIterator = NeighborEdgeIteratorT<false, true>;
193
194 /// A class for ranging over the incoming edges incident to a vertex.
195 ///
196 /// Like all views in this class it provides methods to get the beginning and
197 /// past the range iterators for the range, as well as methods to determine
198 /// the number of elements in the range and whether the range is empty.
199 template <bool isConst, bool isOut> class InOutEdgeView {
200 public:
201 using iterator = NeighborEdgeIteratorT<isConst, isOut>;
202 using const_iterator = NeighborEdgeIteratorT<true, isOut>;
203 using GraphT = typename std::conditional<isConst, const Graph, Graph>::type;
204 using InternalEdgeMapT =
205 typename std::conditional<isConst, const EdgeMapT, EdgeMapT>::type;
206
207 private:
208 InternalEdgeMapT &M;
209 const VertexIdentifier A;
210 const NeighborLookupT &NL;
211
212 public:
213 iterator begin() {
214 auto It = NL.find(A);
215 if (It == NL.end())
216 return iterator();
217 return iterator(It->second.begin(), &M, A);
218 }
219
220 const_iterator cbegin() const {
221 auto It = NL.find(A);
222 if (It == NL.end())
223 return const_iterator();
224 return const_iterator(It->second.begin(), &M, A);
225 }
226
227 const_iterator begin() const { return cbegin(); }
228
229 iterator end() {
230 auto It = NL.find(A);
231 if (It == NL.end())
232 return iterator();
233 return iterator(It->second.end(), &M, A);
234 }
235 const_iterator cend() const {
236 auto It = NL.find(A);
237 if (It == NL.end())
238 return const_iterator();
239 return const_iterator(It->second.end(), &M, A);
240 }
241
242 const_iterator end() const { return cend(); }
243
244 size_type size() const {
245 auto I = NL.find(A);
246 if (I == NL.end())
247 return 0;
248 else
249 return I->second.size();
250 }
251
252 bool empty() const { return NL.count(A) == 0; };
253
254 InOutEdgeView(GraphT &G, VertexIdentifier A)
255 : M(G.Edges), A(A), NL(isOut ? G.OutNeighbors : G.InNeighbors) {}
256 };
257
258 /// A const iterator type for iterating through the whole vertex set of the
259 /// graph.
260 ///
261 /// Has a const VertexValueType as its value_type
262 using ConstVertexIterator = typename VertexMapT::const_iterator;
263
264 /// An iterator type for iterating through the whole vertex set of the graph.
265 ///
266 /// Has a VertexValueType as its value_type
267 using VertexIterator = typename VertexMapT::iterator;
268
269 /// A class for ranging over the vertices in the graph.
270 ///
271 /// Like all views in this class it provides methods to get the beginning and
272 /// past the range iterators for the range, as well as methods to determine
273 /// the number of elements in the range and whether the range is empty.
274 template <bool isConst> class VertexView {
275 public:
276 using iterator = typename std::conditional<isConst, ConstVertexIterator,
277 VertexIterator>::type;
278 using const_iterator = ConstVertexIterator;
279 using GraphT = typename std::conditional<isConst, const Graph, Graph>::type;
280
281 private:
282 GraphT &G;
283
284 public:
285 iterator begin() { return G.Vertices.begin(); }
286 iterator end() { return G.Vertices.end(); }
287 const_iterator cbegin() const { return G.Vertices.cbegin(); }
288 const_iterator cend() const { return G.Vertices.cend(); }
289 const_iterator begin() const { return G.Vertices.begin(); }
290 const_iterator end() const { return G.Vertices.end(); }
291 size_type size() const { return G.Vertices.size(); }
292 bool empty() const { return G.Vertices.empty(); }
293 VertexView(GraphT &_G) : G(_G) {}
294 };
295
296 /// A const iterator for iterating through the entire edge set of the graph.
297 ///
298 /// Has a const EdgeValueType as its value_type
299 using ConstEdgeIterator = typename EdgeMapT::const_iterator;
300
301 /// An iterator for iterating through the entire edge set of the graph.
302 ///
303 /// Has an EdgeValueType as its value_type
304 using EdgeIterator = typename EdgeMapT::iterator;
305
306 /// A class for ranging over all the edges in the graph.
307 ///
308 /// Like all views in this class it provides methods to get the beginning and
309 /// past the range iterators for the range, as well as methods to determine
310 /// the number of elements in the range and whether the range is empty.
311 template <bool isConst> class EdgeView {
312 public:
313 using iterator = typename std::conditional<isConst, ConstEdgeIterator,
314 EdgeIterator>::type;
315 using const_iterator = ConstEdgeIterator;
316 using GraphT = typename std::conditional<isConst, const Graph, Graph>::type;
317
318 private:
319 GraphT &G;
320
321 public:
322 iterator begin() { return G.Edges.begin(); }
323 iterator end() { return G.Edges.end(); }
324 const_iterator cbegin() const { return G.Edges.cbegin(); }
325 const_iterator cend() const { return G.Edges.cend(); }
326 const_iterator begin() const { return G.Edges.begin(); }
327 const_iterator end() const { return G.Edges.end(); }
328 size_type size() const { return G.Edges.size(); }
329 bool empty() const { return G.Edges.empty(); }
330 EdgeView(GraphT &_G) : G(_G) {}
331 };
332
333public:
334 // TODO: implement constructor to enable Graph Initialisation.\
335 // Something like:
336 // Graph<int, int, int> G(
337 // {1, 2, 3, 4, 5},
338 // {{1, 2}, {2, 3}, {3, 4}});
339
340 /// Empty the Graph
341 void clear() {
342 Edges.clear();
343 Vertices.clear();
344 InNeighbors.clear();
345 OutNeighbors.clear();
346 }
347
348 /// Returns a view object allowing iteration over the vertices of the graph.
349 /// also allows access to the size of the vertex set.
350 VertexView<false> vertices() { return VertexView<false>(*this); }
351
352 VertexView<true> vertices() const { return VertexView<true>(*this); }
353
354 /// Returns a view object allowing iteration over the edges of the graph.
355 /// also allows access to the size of the edge set.
356 EdgeView<false> edges() { return EdgeView<false>(*this); }
357
358 EdgeView<true> edges() const { return EdgeView<true>(*this); }
359
360 /// Returns a view object allowing iteration over the edges which start at
361 /// a vertex I.
362 InOutEdgeView<false, true> outEdges(const VertexIdentifier I) {
363 return InOutEdgeView<false, true>(*this, I);
364 }
365
366 InOutEdgeView<true, true> outEdges(const VertexIdentifier I) const {
367 return InOutEdgeView<true, true>(*this, I);
368 }
369
370 /// Returns a view object allowing iteration over the edges which point to
371 /// a vertex I.
372 InOutEdgeView<false, false> inEdges(const VertexIdentifier I) {
373 return InOutEdgeView<false, false>(*this, I);
374 }
375
376 InOutEdgeView<true, false> inEdges(const VertexIdentifier I) const {
377 return InOutEdgeView<true, false>(*this, I);
378 }
379
380 /// Looks up the vertex with identifier I, if it does not exist it default
381 /// constructs it.
382 VertexAttribute &operator[](const VertexIdentifier &I) {
383 return Vertices.FindAndConstruct(I).second;
384 }
385
386 /// Looks up the edge with identifier I, if it does not exist it default
387 /// constructs it, if it's endpoints do not exist it also default constructs
388 /// them.
389 EdgeAttribute &operator[](const EdgeIdentifier &I) {
390 auto &P = Edges.FindAndConstruct(I);
391 Vertices.FindAndConstruct(I.first);
392 Vertices.FindAndConstruct(I.second);
393 InNeighbors[I.second].insert(I.first);
394 OutNeighbors[I.first].insert(I.second);
395 return P.second;
396 }
397
398 /// Looks up a vertex with Identifier I, or an error if it does not exist.
399 Expected<VertexAttribute &> at(const VertexIdentifier &I) {
400 auto It = Vertices.find(I);
401 if (It == Vertices.end())
402 return make_error<StringError>(
403 "Vertex Identifier Does Not Exist",
404 std::make_error_code(std::errc::invalid_argument));
405 return It->second;
406 }
407
408 Expected<const VertexAttribute &> at(const VertexIdentifier &I) const {
409 auto It = Vertices.find(I);
410 if (It == Vertices.end())
411 return make_error<StringError>(
412 "Vertex Identifier Does Not Exist",
413 std::make_error_code(std::errc::invalid_argument));
414 return It->second;
415 }
416
417 /// Looks up an edge with Identifier I, or an error if it does not exist.
418 Expected<EdgeAttribute &> at(const EdgeIdentifier &I) {
419 auto It = Edges.find(I);
420 if (It == Edges.end())
421 return make_error<StringError>(
422 "Edge Identifier Does Not Exist",
423 std::make_error_code(std::errc::invalid_argument));
424 return It->second;
425 }
426
427 Expected<const EdgeAttribute &> at(const EdgeIdentifier &I) const {
428 auto It = Edges.find(I);
429 if (It == Edges.end())
430 return make_error<StringError>(
431 "Edge Identifier Does Not Exist",
432 std::make_error_code(std::errc::invalid_argument));
433 return It->second;
434 }
435
436 /// Looks for a vertex with identifier I, returns 1 if one exists, and
437 /// 0 otherwise
438 size_type count(const VertexIdentifier &I) const {
439 return Vertices.count(I);
440 }
441
442 /// Looks for an edge with Identifier I, returns 1 if one exists and 0
443 /// otherwise
444 size_type count(const EdgeIdentifier &I) const { return Edges.count(I); }
445
446 /// Inserts a vertex into the graph with Identifier Val.first, and
447 /// Attribute Val.second.
448 std::pair<VertexIterator, bool>
449 insert(const std::pair<VertexIdentifier, VertexAttribute> &Val) {
450 return Vertices.insert(Val);
451 }
452
453 std::pair<VertexIterator, bool>
454 insert(std::pair<VertexIdentifier, VertexAttribute> &&Val) {
455 return Vertices.insert(std::move(Val));
456 }
457
458 /// Inserts an edge into the graph with Identifier Val.first, and
459 /// Attribute Val.second. If the key is already in the map, it returns false
460 /// and doesn't update the value.
461 std::pair<EdgeIterator, bool>
462 insert(const std::pair<EdgeIdentifier, EdgeAttribute> &Val) {
463 const auto &p = Edges.insert(Val);
464 if (p.second) {
465 const auto &EI = Val.first;
466 Vertices.FindAndConstruct(EI.first);
467 Vertices.FindAndConstruct(EI.second);
468 InNeighbors[EI.second].insert(EI.first);
469 OutNeighbors[EI.first].insert(EI.second);
470 };
471
472 return p;
473 }
474
475 /// Inserts an edge into the graph with Identifier Val.first, and
476 /// Attribute Val.second. If the key is already in the map, it returns false
477 /// and doesn't update the value.
478 std::pair<EdgeIterator, bool>
479 insert(std::pair<EdgeIdentifier, EdgeAttribute> &&Val) {
480 auto EI = Val.first;
481 const auto &p = Edges.insert(std::move(Val));
482 if (p.second) {
483 Vertices.FindAndConstruct(EI.first);
484 Vertices.FindAndConstruct(EI.second);
485 InNeighbors[EI.second].insert(EI.first);
486 OutNeighbors[EI.first].insert(EI.second);
487 };
488
489 return p;
490 }
491};
492}
493}
494#endif