Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-10 08:44:46

0001 //===-- Graph.h - XRay Graph Class ------------------------------*- C++ -*-===//
0002 //
0003 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
0004 // See https://llvm.org/LICENSE.txt for license information.
0005 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
0006 //
0007 //===----------------------------------------------------------------------===//
0008 //
0009 // A Graph Datatype for XRay.
0010 //
0011 //===----------------------------------------------------------------------===//
0012 
0013 #ifndef LLVM_XRAY_GRAPH_H
0014 #define LLVM_XRAY_GRAPH_H
0015 
0016 #include <initializer_list>
0017 #include <stdint.h>
0018 #include <type_traits>
0019 #include <utility>
0020 
0021 #include "llvm/ADT/DenseMap.h"
0022 #include "llvm/ADT/DenseSet.h"
0023 #include "llvm/ADT/iterator.h"
0024 #include "llvm/Support/Error.h"
0025 
0026 namespace llvm {
0027 namespace xray {
0028 
0029 /// A Graph object represents a Directed Graph and is used in XRay to compute
0030 /// and store function call graphs and associated statistical information.
0031 ///
0032 /// The graph takes in four template parameters, these are:
0033 ///  - VertexAttribute, this is a structure which is stored for each vertex.
0034 ///    Must be DefaultConstructible, CopyConstructible, CopyAssignable and
0035 ///    Destructible.
0036 ///  - EdgeAttribute, this is a structure which is stored for each edge
0037 ///    Must be DefaultConstructible, CopyConstructible, CopyAssignable and
0038 ///    Destructible.
0039 ///  - EdgeAttribute, this is a structure which is stored for each variable
0040 ///  - VI, this is a type over which DenseMapInfo is defined and is the type
0041 ///    used look up strings, available as VertexIdentifier.
0042 ///  - If the built in DenseMapInfo is not defined, provide a specialization
0043 ///    class type here.
0044 ///
0045 /// Graph is CopyConstructible, CopyAssignable, MoveConstructible and
0046 /// MoveAssignable but is not EqualityComparible or LessThanComparible.
0047 ///
0048 /// Usage Example Graph with weighted edges and vertices:
0049 ///   Graph<int, int, int> G;
0050 ///
0051 ///   G[1] = 0;
0052 ///   G[2] = 2;
0053 ///   G[{1,2}] = 1;
0054 ///   G[{2,1}] = -1;
0055 ///   for(const auto &v : G.vertices()){
0056 ///     // Do something with the vertices in the graph;
0057 ///   }
0058 ///   for(const auto &e : G.edges()){
0059 ///     // Do something with the edges in the graph;
0060 ///   }
0061 ///
0062 /// Usage Example with StrRef keys.
0063 ///   Graph<int, double, StrRef> StrG;
0064 ///    char va[] = "Vertex A";
0065 ///    char vaa[] = "Vertex A";
0066 ///    char vb[] = "Vertex B"; // Vertices are referenced by String Refs.
0067 ///    G[va] = 0;
0068 ///    G[vb] = 1;
0069 ///    G[{va, vb}] = 1.0;
0070 ///    cout() << G[vaa] << " " << G[{vaa, vb}]; //prints "0 1.0".
0071 ///
0072 template <typename VertexAttribute, typename EdgeAttribute,
0073           typename VI = int32_t>
0074 class Graph {
0075 public:
0076   /// These objects are used to name edges and vertices in the graph.
0077   typedef VI VertexIdentifier;
0078   typedef std::pair<VI, VI> EdgeIdentifier;
0079 
0080   /// This type is the value_type of all iterators which range over vertices,
0081   /// Determined by the Vertices DenseMap
0082   using VertexValueType =
0083       detail::DenseMapPair<VertexIdentifier, VertexAttribute>;
0084 
0085   /// This type is the value_type of all iterators which range over edges,
0086   /// Determined by the Edges DenseMap.
0087   using EdgeValueType = detail::DenseMapPair<EdgeIdentifier, EdgeAttribute>;
0088 
0089   using size_type = std::size_t;
0090 
0091 private:
0092   /// The type used for storing the EdgeAttribute for each edge in the graph
0093   using EdgeMapT = DenseMap<EdgeIdentifier, EdgeAttribute>;
0094 
0095   /// The type used for storing the VertexAttribute for each vertex in
0096   /// the graph.
0097   using VertexMapT = DenseMap<VertexIdentifier, VertexAttribute>;
0098 
0099   /// The type used for storing the edges entering a vertex. Indexed by
0100   /// the VertexIdentifier of the start of the edge. Only used to determine
0101   /// where the incoming edges are, the EdgeIdentifiers are stored in an
0102   /// InnerEdgeMapT.
0103   using NeighborSetT = DenseSet<VertexIdentifier>;
0104 
0105   /// The type storing the InnerInvGraphT corresponding to each vertex in
0106   /// the graph (When a vertex has an incoming edge incident to it)
0107   using NeighborLookupT = DenseMap<VertexIdentifier, NeighborSetT>;
0108 
0109 private:
0110   /// Stores the map from the start and end vertex of an edge to it's
0111   /// EdgeAttribute
0112   EdgeMapT Edges;
0113 
0114   /// Stores the map from VertexIdentifier to VertexAttribute
0115   VertexMapT Vertices;
0116 
0117   /// Allows fast lookup for the incoming edge set of any given vertex.
0118   NeighborLookupT InNeighbors;
0119 
0120   /// Allows fast lookup for the outgoing edge set of any given vertex.
0121   NeighborLookupT OutNeighbors;
0122 
0123   /// An Iterator adapter using an InnerInvGraphT::iterator as a base iterator,
0124   /// and storing the VertexIdentifier the iterator range comes from. The
0125   /// dereference operator is then performed using a pointer to the graph's edge
0126   /// set.
0127   template <bool IsConst, bool IsOut,
0128             typename BaseIt = typename NeighborSetT::const_iterator,
0129             typename T =
0130                 std::conditional_t<IsConst, const EdgeValueType, EdgeValueType>>
0131   class NeighborEdgeIteratorT
0132       : public iterator_adaptor_base<
0133             NeighborEdgeIteratorT<IsConst, IsOut>, BaseIt,
0134             typename std::iterator_traits<BaseIt>::iterator_category, T> {
0135     using InternalEdgeMapT =
0136         std::conditional_t<IsConst, const EdgeMapT, EdgeMapT>;
0137 
0138     friend class NeighborEdgeIteratorT<false, IsOut, BaseIt, EdgeValueType>;
0139     friend class NeighborEdgeIteratorT<true, IsOut, BaseIt,
0140                                        const EdgeValueType>;
0141 
0142     InternalEdgeMapT *MP;
0143     VertexIdentifier SI;
0144 
0145   public:
0146     template <bool IsConstDest,
0147               typename = std::enable_if_t<IsConstDest && !IsConst>>
0148     operator NeighborEdgeIteratorT<IsConstDest, IsOut, BaseIt,
0149                                    const EdgeValueType>() const {
0150       return NeighborEdgeIteratorT<IsConstDest, IsOut, BaseIt,
0151                                    const EdgeValueType>(this->I, MP, SI);
0152     }
0153 
0154     NeighborEdgeIteratorT() = default;
0155     NeighborEdgeIteratorT(BaseIt _I, InternalEdgeMapT *_MP,
0156                           VertexIdentifier _SI)
0157         : iterator_adaptor_base<
0158               NeighborEdgeIteratorT<IsConst, IsOut>, BaseIt,
0159               typename std::iterator_traits<BaseIt>::iterator_category, T>(_I),
0160           MP(_MP), SI(_SI) {}
0161 
0162     T &operator*() const {
0163       if (!IsOut)
0164         return *(MP->find({*(this->I), SI}));
0165       else
0166         return *(MP->find({SI, *(this->I)}));
0167     }
0168   };
0169 
0170 public:
0171   /// A const iterator type for iterating through the set of edges entering a
0172   /// vertex.
0173   ///
0174   /// Has a const EdgeValueType as its value_type
0175   using ConstInEdgeIterator = NeighborEdgeIteratorT<true, false>;
0176 
0177   /// An iterator type for iterating through the set of edges leaving a vertex.
0178   ///
0179   /// Has an EdgeValueType as its value_type
0180   using InEdgeIterator = NeighborEdgeIteratorT<false, false>;
0181 
0182   /// A const iterator type for iterating through the set of edges entering a
0183   /// vertex.
0184   ///
0185   /// Has a const EdgeValueType as its value_type
0186   using ConstOutEdgeIterator = NeighborEdgeIteratorT<true, true>;
0187 
0188   /// An iterator type for iterating through the set of edges leaving a vertex.
0189   ///
0190   /// Has an EdgeValueType as its value_type
0191   using OutEdgeIterator = NeighborEdgeIteratorT<false, true>;
0192 
0193   /// A class for ranging over the incoming edges incident to a vertex.
0194   ///
0195   /// Like all views in this class it provides methods to get the beginning and
0196   /// past the range iterators for the range, as well as methods to determine
0197   /// the number of elements in the range and whether the range is empty.
0198   template <bool isConst, bool isOut> class InOutEdgeView {
0199   public:
0200     using iterator = NeighborEdgeIteratorT<isConst, isOut>;
0201     using const_iterator = NeighborEdgeIteratorT<true, isOut>;
0202     using GraphT = std::conditional_t<isConst, const Graph, Graph>;
0203     using InternalEdgeMapT =
0204         std::conditional_t<isConst, const EdgeMapT, EdgeMapT>;
0205 
0206   private:
0207     InternalEdgeMapT &M;
0208     const VertexIdentifier A;
0209     const NeighborLookupT &NL;
0210 
0211   public:
0212     iterator begin() {
0213       auto It = NL.find(A);
0214       if (It == NL.end())
0215         return iterator();
0216       return iterator(It->second.begin(), &M, A);
0217     }
0218 
0219     const_iterator cbegin() const {
0220       auto It = NL.find(A);
0221       if (It == NL.end())
0222         return const_iterator();
0223       return const_iterator(It->second.begin(), &M, A);
0224     }
0225 
0226     const_iterator begin() const { return cbegin(); }
0227 
0228     iterator end() {
0229       auto It = NL.find(A);
0230       if (It == NL.end())
0231         return iterator();
0232       return iterator(It->second.end(), &M, A);
0233     }
0234     const_iterator cend() const {
0235       auto It = NL.find(A);
0236       if (It == NL.end())
0237         return const_iterator();
0238       return const_iterator(It->second.end(), &M, A);
0239     }
0240 
0241     const_iterator end() const { return cend(); }
0242 
0243     size_type size() const {
0244       auto I = NL.find(A);
0245       if (I == NL.end())
0246         return 0;
0247       else
0248         return I->second.size();
0249     }
0250 
0251     bool empty() const { return NL.count(A) == 0; };
0252 
0253     InOutEdgeView(GraphT &G, VertexIdentifier A)
0254         : M(G.Edges), A(A), NL(isOut ? G.OutNeighbors : G.InNeighbors) {}
0255   };
0256 
0257   /// A const iterator type for iterating through the whole vertex set of the
0258   /// graph.
0259   ///
0260   /// Has a const VertexValueType as its value_type
0261   using ConstVertexIterator = typename VertexMapT::const_iterator;
0262 
0263   /// An iterator type for iterating through the whole vertex set of the graph.
0264   ///
0265   /// Has a VertexValueType as its value_type
0266   using VertexIterator = typename VertexMapT::iterator;
0267 
0268   /// A class for ranging over the vertices in the graph.
0269   ///
0270   /// Like all views in this class it provides methods to get the beginning and
0271   /// past the range iterators for the range, as well as methods to determine
0272   /// the number of elements in the range and whether the range is empty.
0273   template <bool isConst> class VertexView {
0274   public:
0275     using iterator =
0276         std::conditional_t<isConst, ConstVertexIterator, VertexIterator>;
0277     using const_iterator = ConstVertexIterator;
0278     using GraphT = std::conditional_t<isConst, const Graph, Graph>;
0279 
0280   private:
0281     GraphT &G;
0282 
0283   public:
0284     iterator begin() { return G.Vertices.begin(); }
0285     iterator end() { return G.Vertices.end(); }
0286     const_iterator cbegin() const { return G.Vertices.cbegin(); }
0287     const_iterator cend() const { return G.Vertices.cend(); }
0288     const_iterator begin() const { return G.Vertices.begin(); }
0289     const_iterator end() const { return G.Vertices.end(); }
0290     size_type size() const { return G.Vertices.size(); }
0291     bool empty() const { return G.Vertices.empty(); }
0292     VertexView(GraphT &_G) : G(_G) {}
0293   };
0294 
0295   /// A const iterator for iterating through the entire edge set of the graph.
0296   ///
0297   /// Has a const EdgeValueType as its value_type
0298   using ConstEdgeIterator = typename EdgeMapT::const_iterator;
0299 
0300   /// An iterator for iterating through the entire edge set of the graph.
0301   ///
0302   /// Has an EdgeValueType as its value_type
0303   using EdgeIterator = typename EdgeMapT::iterator;
0304 
0305   /// A class for ranging over all the edges in the graph.
0306   ///
0307   /// Like all views in this class it provides methods to get the beginning and
0308   /// past the range iterators for the range, as well as methods to determine
0309   /// the number of elements in the range and whether the range is empty.
0310   template <bool isConst> class EdgeView {
0311   public:
0312     using iterator =
0313         std::conditional_t<isConst, ConstEdgeIterator, EdgeIterator>;
0314     using const_iterator = ConstEdgeIterator;
0315     using GraphT = std::conditional_t<isConst, const Graph, Graph>;
0316 
0317   private:
0318     GraphT &G;
0319 
0320   public:
0321     iterator begin() { return G.Edges.begin(); }
0322     iterator end() { return G.Edges.end(); }
0323     const_iterator cbegin() const { return G.Edges.cbegin(); }
0324     const_iterator cend() const { return G.Edges.cend(); }
0325     const_iterator begin() const { return G.Edges.begin(); }
0326     const_iterator end() const { return G.Edges.end(); }
0327     size_type size() const { return G.Edges.size(); }
0328     bool empty() const { return G.Edges.empty(); }
0329     EdgeView(GraphT &_G) : G(_G) {}
0330   };
0331 
0332 public:
0333   // TODO: implement constructor to enable Graph Initialisation.\
0334   // Something like:
0335   //   Graph<int, int, int> G(
0336   //   {1, 2, 3, 4, 5},
0337   //   {{1, 2}, {2, 3}, {3, 4}});
0338 
0339   /// Empty the Graph
0340   void clear() {
0341     Edges.clear();
0342     Vertices.clear();
0343     InNeighbors.clear();
0344     OutNeighbors.clear();
0345   }
0346 
0347   /// Returns a view object allowing iteration over the vertices of the graph.
0348   /// also allows access to the size of the vertex set.
0349   VertexView<false> vertices() { return VertexView<false>(*this); }
0350 
0351   VertexView<true> vertices() const { return VertexView<true>(*this); }
0352 
0353   /// Returns a view object allowing iteration over the edges of the graph.
0354   /// also allows access to the size of the edge set.
0355   EdgeView<false> edges() { return EdgeView<false>(*this); }
0356 
0357   EdgeView<true> edges() const { return EdgeView<true>(*this); }
0358 
0359   /// Returns a view object allowing iteration over the edges which start at
0360   /// a vertex I.
0361   InOutEdgeView<false, true> outEdges(const VertexIdentifier I) {
0362     return InOutEdgeView<false, true>(*this, I);
0363   }
0364 
0365   InOutEdgeView<true, true> outEdges(const VertexIdentifier I) const {
0366     return InOutEdgeView<true, true>(*this, I);
0367   }
0368 
0369   /// Returns a view object allowing iteration over the edges which point to
0370   /// a vertex I.
0371   InOutEdgeView<false, false> inEdges(const VertexIdentifier I) {
0372     return InOutEdgeView<false, false>(*this, I);
0373   }
0374 
0375   InOutEdgeView<true, false> inEdges(const VertexIdentifier I) const {
0376     return InOutEdgeView<true, false>(*this, I);
0377   }
0378 
0379   /// Looks up the vertex with identifier I, if it does not exist it default
0380   /// constructs it.
0381   VertexAttribute &operator[](const VertexIdentifier &I) { return Vertices[I]; }
0382 
0383   /// Looks up the edge with identifier I, if it does not exist it default
0384   /// constructs it, if it's endpoints do not exist it also default constructs
0385   /// them.
0386   EdgeAttribute &operator[](const EdgeIdentifier &I) {
0387     Vertices.try_emplace(I.first);
0388     Vertices.try_emplace(I.second);
0389     InNeighbors[I.second].insert(I.first);
0390     OutNeighbors[I.first].insert(I.second);
0391     return Edges[I];
0392   }
0393 
0394   /// Looks up a vertex with Identifier I, or an error if it does not exist.
0395   Expected<VertexAttribute &> at(const VertexIdentifier &I) {
0396     auto It = Vertices.find(I);
0397     if (It == Vertices.end())
0398       return make_error<StringError>(
0399           "Vertex Identifier Does Not Exist",
0400           std::make_error_code(std::errc::invalid_argument));
0401     return It->second;
0402   }
0403 
0404   Expected<const VertexAttribute &> at(const VertexIdentifier &I) const {
0405     auto It = Vertices.find(I);
0406     if (It == Vertices.end())
0407       return make_error<StringError>(
0408           "Vertex Identifier Does Not Exist",
0409           std::make_error_code(std::errc::invalid_argument));
0410     return It->second;
0411   }
0412 
0413   /// Looks up an edge with Identifier I, or an error if it does not exist.
0414   Expected<EdgeAttribute &> at(const EdgeIdentifier &I) {
0415     auto It = Edges.find(I);
0416     if (It == Edges.end())
0417       return make_error<StringError>(
0418           "Edge Identifier Does Not Exist",
0419           std::make_error_code(std::errc::invalid_argument));
0420     return It->second;
0421   }
0422 
0423   Expected<const EdgeAttribute &> at(const EdgeIdentifier &I) const {
0424     auto It = Edges.find(I);
0425     if (It == Edges.end())
0426       return make_error<StringError>(
0427           "Edge Identifier Does Not Exist",
0428           std::make_error_code(std::errc::invalid_argument));
0429     return It->second;
0430   }
0431 
0432   /// Looks for a vertex with identifier I, returns 1 if one exists, and
0433   /// 0 otherwise
0434   size_type count(const VertexIdentifier &I) const {
0435     return Vertices.count(I);
0436   }
0437 
0438   /// Looks for an edge with Identifier I, returns 1 if one exists and 0
0439   /// otherwise
0440   size_type count(const EdgeIdentifier &I) const { return Edges.count(I); }
0441 
0442   /// Inserts a vertex into the graph with Identifier Val.first, and
0443   /// Attribute Val.second.
0444   std::pair<VertexIterator, bool>
0445   insert(const std::pair<VertexIdentifier, VertexAttribute> &Val) {
0446     return Vertices.insert(Val);
0447   }
0448 
0449   std::pair<VertexIterator, bool>
0450   insert(std::pair<VertexIdentifier, VertexAttribute> &&Val) {
0451     return Vertices.insert(std::move(Val));
0452   }
0453 
0454   /// Inserts an edge into the graph with Identifier Val.first, and
0455   /// Attribute Val.second. If the key is already in the map, it returns false
0456   /// and doesn't update the value.
0457   std::pair<EdgeIterator, bool>
0458   insert(const std::pair<EdgeIdentifier, EdgeAttribute> &Val) {
0459     const auto &p = Edges.insert(Val);
0460     if (p.second) {
0461       const auto &EI = Val.first;
0462       Vertices.FindAndConstruct(EI.first);
0463       Vertices.FindAndConstruct(EI.second);
0464       InNeighbors[EI.second].insert(EI.first);
0465       OutNeighbors[EI.first].insert(EI.second);
0466     };
0467 
0468     return p;
0469   }
0470 
0471   /// Inserts an edge into the graph with Identifier Val.first, and
0472   /// Attribute Val.second. If the key is already in the map, it returns false
0473   /// and doesn't update the value.
0474   std::pair<EdgeIterator, bool>
0475   insert(std::pair<EdgeIdentifier, EdgeAttribute> &&Val) {
0476     auto EI = Val.first;
0477     const auto &p = Edges.insert(std::move(Val));
0478     if (p.second) {
0479       Vertices.try_emplace(EI.first);
0480       Vertices.try_emplace(EI.second);
0481       InNeighbors[EI.second].insert(EI.first);
0482       OutNeighbors[EI.first].insert(EI.second);
0483     };
0484 
0485     return p;
0486   }
0487 };
0488 }
0489 }
0490 #endif