tan  0.0.1
dependency_graph.h
1 #ifndef __TAN_SRC_ANALYSIS_DEPENDENCY_GRAPH_H__
2 #define __TAN_SRC_ANALYSIS_DEPENDENCY_GRAPH_H__
3 
4 #include "base.h"
5 #include <unordered_set>
6 #include <queue>
7 #include <optional>
8 
9 namespace tanlang {
10 
11 template <typename T> class DependencyGraph {
12 public:
13  /**
14  * \brief \p dependent depends on \p depended
15  */
16  void add_dependency(T depended, T dependent) {
17  _forward[dependent].push_back(depended);
18  _backward[depended].push_back(dependent);
19  _all.insert(depended);
20  _all.insert(dependent);
21  }
22 
23  /**
24  * \brief Sort topologically so for no element is dependent on its succeeding element(s).
25  * \return (res, node)
26  * - If successful, res is a sorted vector of T and node is nullopt
27  * - Otherwise, res is nullopt, and node is the node that has cyclic dependency
28  */
29  std::pair<std::optional<vector<T>>, std::optional<T>> topological_sort() const {
30  umap<T, int> num_depend{};
31  std::queue<T> q{};
32 
33  for (T node : _all) {
34  int n = num_depended(node);
35  if (n == 0) {
36  q.push(node);
37  }
38  num_depend[node] = n;
39  }
40 
41  vector<T> ret{};
42  while (!q.empty()) {
43  T curr = q.front();
44  q.pop();
45  ret.push_back(curr);
46 
47  auto f = _backward.find(curr);
48  vector<T> depended{};
49  if (f != _backward.end()) {
50  depended = f->second;
51  }
52  for (auto d : depended) {
53  --num_depend[d];
54  if (num_depend[d] == 0) {
55  q.push(d);
56  }
57  }
58  }
59 
60  // for (auto [d1, d2] : _forward) {
61  // str d1name = pcast<Decl>(d1)->get_name();
62  // for (auto *d : d2) {
63  // str d2name = pcast<Decl>(d)->get_name();
64  // std::cout << fmt::format("{} depends on {}\n", d1name, d2name);
65  // }
66  // }
67 
68  // check if cyclic
69  for (auto [node, n_depend] : num_depend) {
70  if (n_depend)
71  return std::make_pair(std::nullopt, node);
72  }
73 
74  return std::make_pair(ret, std::nullopt);
75  }
76 
77  /**
78  * \brief Number of nodes that depends on \p depended.
79  */
80  int num_dependent(T depended) const {
81  auto q = _backward.find(depended);
82  if (q == _backward.end()) {
83  return 0;
84  } else {
85  return (int)q->second.size();
86  }
87  }
88 
89  /**
90  * \brief Number of nodes that \p dependent depends on.
91  */
92  int num_depended(T dependent) const {
93  auto q = _forward.find(dependent);
94  if (q == _forward.end()) {
95  return 0;
96  } else {
97  return (int)q->second.size();
98  }
99  }
100 
101  void clear() {
102  _forward.clear();
103  _backward.clear();
104  _all.clear();
105  }
106 
107 private:
108  umap<T, vector<T>> _forward{}; // dependent -> depended
109  umap<T, vector<T>> _backward{}; // depended -> dependent
110  std::unordered_set<T> _all{};
111 };
112 
113 } // namespace tanlang
114 
115 #endif // __TAN_SRC_ANALYSIS_DEPENDENCY_GRAPH_H__
int num_depended(T dependent) const
Number of nodes that dependent depends on.
void add_dependency(T depended, T dependent)
dependent depends on depended
std::pair< std::optional< vector< T > >, std::optional< T > > topological_sort() const
Sort topologically so for no element is dependent on its succeeding element(s).
int num_dependent(T depended) const
Number of nodes that depends on depended.