blob: c54955a5ab7c4d720ff9f717c37feb39900b7ecf [file] [log] [blame]
Kostya Serebryanybe1d22b2014-02-12 11:28:09 +00001//===-- sanitizer_bvgraph.h -------------------------------------*- 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// This file is a part of Sanitizer runtime.
11// BVGraph -- a directed graph.
12//
13//===----------------------------------------------------------------------===//
14
15#ifndef SANITIZER_BVGRAPH_H
16#define SANITIZER_BVGRAPH_H
17
18#include "sanitizer_common.h"
19#include "sanitizer_bitvector.h"
20
21namespace __sanitizer {
22
23// Directed graph of fixed size implemented as an array of bit vectors.
Kostya Serebryanye233d862014-02-14 12:08:23 +000024// Not thread-safe, all accesses should be protected by an external lock.
Kostya Serebryanybe1d22b2014-02-12 11:28:09 +000025template<class BV>
26class BVGraph {
27 public:
28 enum SizeEnum { kSize = BV::kSize };
29 uptr size() const { return kSize; }
30 // No CTOR.
31 void clear() {
32 for (uptr i = 0; i < size(); i++)
33 v[i].clear();
34 }
35
Kostya Serebryany73325582014-02-17 11:21:52 +000036 bool empty() const {
37 for (uptr i = 0; i < size(); i++)
38 if (!v[i].empty())
39 return false;
40 return true;
41 }
42
Kostya Serebryanybe1d22b2014-02-12 11:28:09 +000043 // Returns true if a new edge was added.
44 bool addEdge(uptr from, uptr to) {
Kostya Serebryany07526fb2014-02-13 12:39:21 +000045 check(from, to);
Kostya Serebryanybe1d22b2014-02-12 11:28:09 +000046 return v[from].setBit(to);
47 }
48
Kostya Serebryanyec684292014-02-17 08:47:48 +000049 // Returns true if at least one new edge was added.
50 bool addEdges(const BV &from, uptr to) {
51 bool res = false;
52 t1.copyFrom(from);
53 while (!t1.empty())
54 if (v[t1.getAndClearFirstOne()].setBit(to))
55 res = true;
56 return res;
57 }
58
Kostya Serebryany73325582014-02-17 11:21:52 +000059 // Returns true if the edge from=>to was removed.
60 bool removeEdge(uptr from, uptr to) {
61 return v[from].clearBit(to);
62 }
63
64 // Returns true if at least one edge *=>to was removed.
65 bool removeEdgesTo(const BV &to) {
66 bool res = 0;
67 for (uptr from = 0; from < size(); from++) {
68 if (v[from].setDifference(to))
69 res = true;
70 }
71 return res;
72 }
73
74 // Returns true if at least one edge from=>* was removed.
75 bool removeEdgesFrom(const BV &from) {
76 bool res = false;
77 t1.copyFrom(from);
78 while (!t1.empty()) {
79 uptr idx = t1.getAndClearFirstOne();
80 if (!v[idx].empty()) {
81 v[idx].clear();
82 res = true;
83 }
84 }
85 return res;
86 }
87
88 void removeEdgesFrom(uptr from) {
89 return v[from].clear();
90 }
91
Kostya Serebryanybe1d22b2014-02-12 11:28:09 +000092 bool hasEdge(uptr from, uptr to) const {
Kostya Serebryany07526fb2014-02-13 12:39:21 +000093 check(from, to);
Kostya Serebryanybe1d22b2014-02-12 11:28:09 +000094 return v[from].getBit(to);
95 }
96
97 // Returns true if there is a path from the node 'from'
Kostya Serebryany5e52d482014-02-13 07:44:51 +000098 // to any of the nodes in 'targets'.
99 bool isReachable(uptr from, const BV &targets) {
Kostya Serebryanye233d862014-02-14 12:08:23 +0000100 BV &to_visit = t1,
101 &visited = t2;
Kostya Serebryanyf6cb35a2014-02-13 09:52:15 +0000102 to_visit.copyFrom(v[from]);
Kostya Serebryanybe1d22b2014-02-12 11:28:09 +0000103 visited.clear();
104 visited.setBit(from);
105 while (!to_visit.empty()) {
106 uptr idx = to_visit.getAndClearFirstOne();
107 if (visited.setBit(idx))
108 to_visit.setUnion(v[idx]);
109 }
Kostya Serebryany5e52d482014-02-13 07:44:51 +0000110 return targets.intersectsWith(visited);
Kostya Serebryanybe1d22b2014-02-12 11:28:09 +0000111 }
112
Kostya Serebryanyf6cb35a2014-02-13 09:52:15 +0000113 // Finds a path from 'from' to one of the nodes in 'target',
114 // stores up to 'path_size' items of the path into 'path',
115 // returns the path length, or 0 if there is no path of size 'path_size'.
116 uptr findPath(uptr from, const BV &targets, uptr *path, uptr path_size) {
117 if (path_size == 0)
118 return 0;
119 path[0] = from;
120 if (targets.getBit(from))
121 return 1;
Kostya Serebryanye233d862014-02-14 12:08:23 +0000122 // The function is recursive, so we don't want to create BV on stack.
123 // Instead of a getAndClearFirstOne loop we use the slower iterator.
124 for (typename BV::Iterator it(v[from]); it.hasNext(); ) {
125 uptr idx = it.next();
Kostya Serebryanyf6cb35a2014-02-13 09:52:15 +0000126 if (uptr res = findPath(idx, targets, path + 1, path_size - 1))
127 return res + 1;
128 }
129 return 0;
130 }
131
Kostya Serebryanybe1d22b2014-02-12 11:28:09 +0000132 private:
Kostya Serebryany67d41972014-02-13 15:45:20 +0000133 void check(uptr idx1, uptr idx2) const {
134 CHECK_LT(idx1, size());
135 CHECK_LT(idx2, size());
136 }
Kostya Serebryanybe1d22b2014-02-12 11:28:09 +0000137 BV v[kSize];
Kostya Serebryanye233d862014-02-14 12:08:23 +0000138 // Keep temporary vectors here since we can not create large objects on stack.
139 BV t1, t2;
Kostya Serebryanybe1d22b2014-02-12 11:28:09 +0000140};
141
142} // namespace __sanitizer
143
144#endif // SANITIZER_BVGRAPH_H