Graph.h 17 KB

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