1 //===-- 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 27 namespace llvm { 28 namespace 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 /// 73 template <typename VertexAttribute, typename EdgeAttribute, 74 typename VI = int32_t> 75 class Graph { 76 public: 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 92 private: 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 110 private: 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; NeighborEdgeIteratorT(BaseIt _I,InternalEdgeMapT * _MP,VertexIdentifier _SI)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 171 public: 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: begin()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 cbegin()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 begin()227 const_iterator begin() const { return cbegin(); } 228 end()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 } cend()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 end()242 const_iterator end() const { return cend(); } 243 size()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 empty()252 bool empty() const { return NL.count(A) == 0; }; 253 InOutEdgeView(GraphT & G,VertexIdentifier A)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: begin()285 iterator begin() { return G.Vertices.begin(); } end()286 iterator end() { return G.Vertices.end(); } cbegin()287 const_iterator cbegin() const { return G.Vertices.cbegin(); } cend()288 const_iterator cend() const { return G.Vertices.cend(); } begin()289 const_iterator begin() const { return G.Vertices.begin(); } end()290 const_iterator end() const { return G.Vertices.end(); } size()291 size_type size() const { return G.Vertices.size(); } empty()292 bool empty() const { return G.Vertices.empty(); } VertexView(GraphT & _G)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: begin()322 iterator begin() { return G.Edges.begin(); } end()323 iterator end() { return G.Edges.end(); } cbegin()324 const_iterator cbegin() const { return G.Edges.cbegin(); } cend()325 const_iterator cend() const { return G.Edges.cend(); } begin()326 const_iterator begin() const { return G.Edges.begin(); } end()327 const_iterator end() const { return G.Edges.end(); } size()328 size_type size() const { return G.Edges.size(); } empty()329 bool empty() const { return G.Edges.empty(); } EdgeView(GraphT & _G)330 EdgeView(GraphT &_G) : G(_G) {} 331 }; 332 333 public: 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 clear()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. vertices()350 VertexView<false> vertices() { return VertexView<false>(*this); } 351 vertices()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. edges()356 EdgeView<false> edges() { return EdgeView<false>(*this); } 357 edges()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. outEdges(const VertexIdentifier I)362 InOutEdgeView<false, true> outEdges(const VertexIdentifier I) { 363 return InOutEdgeView<false, true>(*this, I); 364 } 365 outEdges(const VertexIdentifier I)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. inEdges(const VertexIdentifier I)372 InOutEdgeView<false, false> inEdges(const VertexIdentifier I) { 373 return InOutEdgeView<false, false>(*this, I); 374 } 375 inEdges(const VertexIdentifier I)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. at(const VertexIdentifier & I)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 at(const VertexIdentifier & I)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. at(const EdgeIdentifier & I)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 at(const EdgeIdentifier & I)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 count(const VertexIdentifier & I)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 count(const EdgeIdentifier & I)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> insert(const std::pair<VertexIdentifier,VertexAttribute> & Val)449 insert(const std::pair<VertexIdentifier, VertexAttribute> &Val) { 450 return Vertices.insert(Val); 451 } 452 453 std::pair<VertexIterator, bool> insert(std::pair<VertexIdentifier,VertexAttribute> && Val)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> insert(const std::pair<EdgeIdentifier,EdgeAttribute> & Val)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> insert(std::pair<EdgeIdentifier,EdgeAttribute> && Val)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 495