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
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
495