/*
 * Copyright (C) 2016 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

// Based on system/update_engine/payload_generator/tarjan.cc

#ifndef LIBMEMUNREACHABLE_TARJAN_H_
#define LIBMEMUNREACHABLE_TARJAN_H_

#include <assert.h>
#include <algorithm>

#include "Allocator.h"

template<class T>
class Node {
 public:
  allocator::set<Node<T>*> references_in;
  allocator::set<Node<T>*> references_out;
  size_t index;
  size_t lowlink;

  T* ptr;

  Node(T* ptr, Allocator<Node> allocator) : references_in(allocator), references_out(allocator),
      ptr(ptr) {};
  Node(Node&& rhs) = default;
  void Edge(Node<T>* ref) {
    references_out.emplace(ref);
    ref->references_in.emplace(this);
  }
  template<class F>
  void Foreach(F&& f) {
    for (auto& node: references_out) {
      f(node->ptr);
    }
  }
 private:
  DISALLOW_COPY_AND_ASSIGN(Node<T>);
};

template<class T>
using Graph = allocator::vector<Node<T>*>;

template<class T>
using SCC = allocator::vector<Node<T>*>;

template<class T>
using SCCList = allocator::vector<SCC<T>>;

template<class T>
class TarjanAlgorithm {
 public:
  explicit TarjanAlgorithm(Allocator<void> allocator) : index_(0),
    stack_(allocator), components_(allocator) {}

  void Execute(Graph<T>& graph, SCCList<T>& out);
 private:
  static constexpr size_t UNDEFINED_INDEX = static_cast<size_t>(-1);
  void Tarjan(Node<T>* vertex, Graph<T>& graph);

  size_t index_;
  allocator::vector<Node<T>*> stack_;
  SCCList<T> components_;
};

template<class T>
void TarjanAlgorithm<T>::Execute(Graph<T>& graph, SCCList<T>& out) {
  stack_.clear();
  components_.clear();
  index_ = 0;
  for (auto& it: graph) {
    it->index = UNDEFINED_INDEX;
    it->lowlink = UNDEFINED_INDEX;
  }

  for (auto& it: graph) {
    if (it->index == UNDEFINED_INDEX) {
      Tarjan(it, graph);
    }
  }
  out.swap(components_);
}

template<class T>
void TarjanAlgorithm<T>::Tarjan(Node<T>* vertex, Graph<T>& graph) {
  assert(vertex->index == UNDEFINED_INDEX);
  vertex->index = index_;
  vertex->lowlink = index_;
  index_++;
  stack_.push_back(vertex);
  for (auto& it: vertex->references_out) {
    Node<T>* vertex_next = it;
    if (vertex_next->index == UNDEFINED_INDEX) {
      Tarjan(vertex_next, graph);
      vertex->lowlink = std::min(vertex->lowlink, vertex_next->lowlink);
    } else if (std::find(stack_.begin(), stack_.end(), vertex_next) != stack_.end()) {
      vertex->lowlink = std::min(vertex->lowlink, vertex_next->index);
    }
  }
  if (vertex->lowlink == vertex->index) {
    SCC<T> component{components_.get_allocator()};
    Node<T>* other_vertex;
    do {
      other_vertex = stack_.back();
      stack_.pop_back();
      component.push_back(other_vertex);
    } while (other_vertex != vertex && !stack_.empty());

    components_.emplace_back(component);
  }
}

template<class T>
void Tarjan(Graph<T>& graph, SCCList<T>& out) {
  TarjanAlgorithm<T> tarjan{graph.get_allocator()};
  tarjan.Execute(graph, out);
}

#endif // LIBMEMUNREACHABLE_TARJAN_H_
