• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 // Based on system/update_engine/payload_generator/tarjan.cc
18 
19 #ifndef LIBMEMUNREACHABLE_TARJAN_H_
20 #define LIBMEMUNREACHABLE_TARJAN_H_
21 
22 #include <assert.h>
23 #include <algorithm>
24 
25 #include "Allocator.h"
26 
27 namespace android {
28 
29 template <class T>
30 class Node {
31  public:
32   allocator::set<Node<T>*> references_in;
33   allocator::set<Node<T>*> references_out;
34   size_t index;
35   size_t lowlink;
36 
37   T* ptr;
38 
Node(T * ptr,Allocator<Node> allocator)39   Node(T* ptr, Allocator<Node> allocator)
40       : references_in(allocator), references_out(allocator), ptr(ptr){};
41   Node(Node&& rhs) noexcept = default;
Edge(Node<T> * ref)42   void Edge(Node<T>* ref) {
43     references_out.emplace(ref);
44     ref->references_in.emplace(this);
45   }
46   template <class F>
Foreach(F && f)47   void Foreach(F&& f) {
48     for (auto& node : references_out) {
49       f(node->ptr);
50     }
51   }
52 
53  private:
54   DISALLOW_COPY_AND_ASSIGN(Node<T>);
55 };
56 
57 template <class T>
58 using Graph = allocator::vector<Node<T>*>;
59 
60 template <class T>
61 using SCC = allocator::vector<Node<T>*>;
62 
63 template <class T>
64 using SCCList = allocator::vector<SCC<T>>;
65 
66 template <class T>
67 class TarjanAlgorithm {
68  public:
TarjanAlgorithm(Allocator<void> allocator)69   explicit TarjanAlgorithm(Allocator<void> allocator)
70       : index_(0), stack_(allocator), components_(allocator) {}
71 
72   void Execute(Graph<T>& graph, SCCList<T>& out);
73 
74  private:
75   static constexpr size_t UNDEFINED_INDEX = static_cast<size_t>(-1);
76   void Tarjan(Node<T>* vertex, Graph<T>& graph);
77 
78   size_t index_;
79   allocator::vector<Node<T>*> stack_;
80   SCCList<T> components_;
81 };
82 
83 template <class T>
Execute(Graph<T> & graph,SCCList<T> & out)84 void TarjanAlgorithm<T>::Execute(Graph<T>& graph, SCCList<T>& out) {
85   stack_.clear();
86   components_.clear();
87   index_ = 0;
88   for (auto& it : graph) {
89     it->index = UNDEFINED_INDEX;
90     it->lowlink = UNDEFINED_INDEX;
91   }
92 
93   for (auto& it : graph) {
94     if (it->index == UNDEFINED_INDEX) {
95       Tarjan(it, graph);
96     }
97   }
98   out.swap(components_);
99 }
100 
101 template <class T>
Tarjan(Node<T> * vertex,Graph<T> & graph)102 void TarjanAlgorithm<T>::Tarjan(Node<T>* vertex, Graph<T>& graph) {
103   assert(vertex->index == UNDEFINED_INDEX);
104   vertex->index = index_;
105   vertex->lowlink = index_;
106   index_++;
107   stack_.push_back(vertex);
108   for (auto& it : vertex->references_out) {
109     Node<T>* vertex_next = it;
110     if (vertex_next->index == UNDEFINED_INDEX) {
111       Tarjan(vertex_next, graph);
112       vertex->lowlink = std::min(vertex->lowlink, vertex_next->lowlink);
113     } else if (std::find(stack_.begin(), stack_.end(), vertex_next) != stack_.end()) {
114       vertex->lowlink = std::min(vertex->lowlink, vertex_next->index);
115     }
116   }
117   if (vertex->lowlink == vertex->index) {
118     SCC<T> component{components_.get_allocator()};
119     Node<T>* other_vertex;
120     do {
121       other_vertex = stack_.back();
122       stack_.pop_back();
123       component.push_back(other_vertex);
124     } while (other_vertex != vertex && !stack_.empty());
125 
126     components_.emplace_back(component);
127   }
128 }
129 
130 template <class T>
Tarjan(Graph<T> & graph,SCCList<T> & out)131 void Tarjan(Graph<T>& graph, SCCList<T>& out) {
132   TarjanAlgorithm<T> tarjan{graph.get_allocator()};
133   tarjan.Execute(graph, out);
134 }
135 
136 }  // namespace android
137 
138 #endif  // LIBMEMUNREACHABLE_TARJAN_H_
139