Tarjan.h 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  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. // Based on system/update_engine/payload_generator/tarjan.cc
  17. #ifndef LIBMEMUNREACHABLE_TARJAN_H_
  18. #define LIBMEMUNREACHABLE_TARJAN_H_
  19. #include <assert.h>
  20. #include <algorithm>
  21. #include "Allocator.h"
  22. namespace android {
  23. template <class T>
  24. class Node {
  25. public:
  26. allocator::set<Node<T>*> references_in;
  27. allocator::set<Node<T>*> references_out;
  28. size_t index;
  29. size_t lowlink;
  30. T* ptr;
  31. Node(T* ptr, Allocator<Node> allocator)
  32. : references_in(allocator), references_out(allocator), ptr(ptr){};
  33. Node(Node&& rhs) noexcept = default;
  34. void Edge(Node<T>* ref) {
  35. references_out.emplace(ref);
  36. ref->references_in.emplace(this);
  37. }
  38. template <class F>
  39. void Foreach(F&& f) {
  40. for (auto& node : references_out) {
  41. f(node->ptr);
  42. }
  43. }
  44. private:
  45. DISALLOW_COPY_AND_ASSIGN(Node<T>);
  46. };
  47. template <class T>
  48. using Graph = allocator::vector<Node<T>*>;
  49. template <class T>
  50. using SCC = allocator::vector<Node<T>*>;
  51. template <class T>
  52. using SCCList = allocator::vector<SCC<T>>;
  53. template <class T>
  54. class TarjanAlgorithm {
  55. public:
  56. explicit TarjanAlgorithm(Allocator<void> allocator)
  57. : index_(0), stack_(allocator), components_(allocator) {}
  58. void Execute(Graph<T>& graph, SCCList<T>& out);
  59. private:
  60. static constexpr size_t UNDEFINED_INDEX = static_cast<size_t>(-1);
  61. void Tarjan(Node<T>* vertex, Graph<T>& graph);
  62. size_t index_;
  63. allocator::vector<Node<T>*> stack_;
  64. SCCList<T> components_;
  65. };
  66. template <class T>
  67. void TarjanAlgorithm<T>::Execute(Graph<T>& graph, SCCList<T>& out) {
  68. stack_.clear();
  69. components_.clear();
  70. index_ = 0;
  71. for (auto& it : graph) {
  72. it->index = UNDEFINED_INDEX;
  73. it->lowlink = UNDEFINED_INDEX;
  74. }
  75. for (auto& it : graph) {
  76. if (it->index == UNDEFINED_INDEX) {
  77. Tarjan(it, graph);
  78. }
  79. }
  80. out.swap(components_);
  81. }
  82. template <class T>
  83. void TarjanAlgorithm<T>::Tarjan(Node<T>* vertex, Graph<T>& graph) {
  84. assert(vertex->index == UNDEFINED_INDEX);
  85. vertex->index = index_;
  86. vertex->lowlink = index_;
  87. index_++;
  88. stack_.push_back(vertex);
  89. for (auto& it : vertex->references_out) {
  90. Node<T>* vertex_next = it;
  91. if (vertex_next->index == UNDEFINED_INDEX) {
  92. Tarjan(vertex_next, graph);
  93. vertex->lowlink = std::min(vertex->lowlink, vertex_next->lowlink);
  94. } else if (std::find(stack_.begin(), stack_.end(), vertex_next) != stack_.end()) {
  95. vertex->lowlink = std::min(vertex->lowlink, vertex_next->index);
  96. }
  97. }
  98. if (vertex->lowlink == vertex->index) {
  99. SCC<T> component{components_.get_allocator()};
  100. Node<T>* other_vertex;
  101. do {
  102. other_vertex = stack_.back();
  103. stack_.pop_back();
  104. component.push_back(other_vertex);
  105. } while (other_vertex != vertex && !stack_.empty());
  106. components_.emplace_back(component);
  107. }
  108. }
  109. template <class T>
  110. void Tarjan(Graph<T>& graph, SCCList<T>& out) {
  111. TarjanAlgorithm<T> tarjan{graph.get_allocator()};
  112. tarjan.Execute(graph, out);
  113. }
  114. } // namespace android
  115. #endif // LIBMEMUNREACHABLE_TARJAN_H_