| Index: chrome/browser/profiles/dependency_graph.cc
|
| diff --git a/chrome/browser/profiles/dependency_graph.cc b/chrome/browser/profiles/dependency_graph.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..63d7b77613f0e55dc6949daca0db3bd8f7540e3c
|
| --- /dev/null
|
| +++ b/chrome/browser/profiles/dependency_graph.cc
|
| @@ -0,0 +1,161 @@
|
| +// Copyright 2013 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include "chrome/browser/profiles/dependency_graph.h"
|
| +
|
| +#include <algorithm>
|
| +#include <deque>
|
| +#include <iterator>
|
| +
|
| +DependencyGraph::DependencyGraph(const GetNodeNameCallback& callback)
|
| + : get_node_name_callback_(callback) {
|
| +}
|
| +
|
| +DependencyGraph::~DependencyGraph() {
|
| +}
|
| +
|
| +void DependencyGraph::AddNode(void* node) {
|
| + all_nodes_.push_back(node);
|
| + construction_order_.clear();
|
| +}
|
| +
|
| +void DependencyGraph::RemoveNode(void* node) {
|
| + all_nodes_.erase(std::remove(all_nodes_.begin(),
|
| + all_nodes_.end(),
|
| + node),
|
| + all_nodes_.end());
|
| +
|
| + // Remove all dependency edges that contain this node.
|
| + EdgeMap::iterator it = edges_.begin();
|
| + while (it != edges_.end()) {
|
| + EdgeMap::iterator temp = it;
|
| + ++it;
|
| +
|
| + if (temp->first == node || temp->second == node)
|
| + edges_.erase(temp);
|
| + }
|
| +
|
| + construction_order_.clear();
|
| +}
|
| +
|
| +void DependencyGraph::AddEdge(void* depended, void* dependee) {
|
| + edges_.insert(std::make_pair(depended, dependee));
|
| + construction_order_.clear();
|
| +}
|
| +
|
| +bool DependencyGraph::GetConstructionOrder(std::vector<void*>* order) {
|
| + if (construction_order_.empty() && !BuildConstructionOrder())
|
| + return false;
|
| +
|
| + *order = construction_order_;
|
| + return true;
|
| +}
|
| +
|
| +bool DependencyGraph::GetDestructionOrder(std::vector<void*>* order) {
|
| + if (construction_order_.empty() && !BuildConstructionOrder())
|
| + return false;
|
| +
|
| + *order = construction_order_;
|
| +
|
| + // Destroy nodes in reverse order.
|
| + std::reverse(order->begin(), order->end());
|
| +
|
| + return true;
|
| +}
|
| +
|
| +bool DependencyGraph::BuildConstructionOrder() {
|
| + // Step 1: Build a set of nodes with no incoming edges.
|
| + std::deque<void*> queue;
|
| + std::copy(all_nodes_.begin(),
|
| + all_nodes_.end(),
|
| + std::back_inserter(queue));
|
| +
|
| + std::deque<void*>::iterator queue_end = queue.end();
|
| + for (EdgeMap::const_iterator it = edges_.begin();
|
| + it != edges_.end(); ++it) {
|
| + queue_end = std::remove(queue.begin(), queue_end, it->second);
|
| + }
|
| + queue.erase(queue_end, queue.end());
|
| +
|
| + // Step 2: Do the Kahn topological sort.
|
| + std::vector<void*> output;
|
| + EdgeMap edges(edges_);
|
| + while (!queue.empty()) {
|
| + void* node = queue.front();
|
| + queue.pop_front();
|
| + output.push_back(node);
|
| +
|
| + std::pair<EdgeMap::iterator, EdgeMap::iterator> range =
|
| + edges.equal_range(node);
|
| + EdgeMap::iterator it = range.first;
|
| + while (it != range.second) {
|
| + void* dest = it->second;
|
| + EdgeMap::iterator temp = it;
|
| + it++;
|
| + edges.erase(temp);
|
| +
|
| + bool has_incoming_edges = false;
|
| + for (EdgeMap::iterator jt = edges.begin(); jt != edges.end(); ++jt) {
|
| + if (jt->second == dest) {
|
| + has_incoming_edges = true;
|
| + break;
|
| + }
|
| + }
|
| +
|
| + if (!has_incoming_edges)
|
| + queue.push_back(dest);
|
| + }
|
| + }
|
| +
|
| + if (!edges.empty()) {
|
| + // Dependency graph has a cycle.
|
| + return false;
|
| + }
|
| +
|
| + construction_order_ = output;
|
| + return true;
|
| +}
|
| +
|
| +std::string DependencyGraph::DumpAsGraphviz(const std::string& toplevel_name) {
|
| + std::string result("digraph {\n");
|
| +
|
| + // Make a copy of all nodes.
|
| + std::deque<void*> nodes;
|
| + std::copy(all_nodes_.begin(), all_nodes_.end(), std::back_inserter(nodes));
|
| +
|
| + // State all dependencies and remove |second| so we don't generate an
|
| + // implicit dependency on the top level node.
|
| + std::deque<void*>::iterator nodes_end(nodes.end());
|
| + result.append(" /* Dependencies */\n");
|
| + for (EdgeMap::const_iterator it = edges_.begin(); it != edges_.end(); ++it) {
|
| + result.append(" ");
|
| + result.append(get_node_name_callback_.Run(it->second));
|
| + result.append(" -> ");
|
| + result.append(get_node_name_callback_.Run(it->first));
|
| + result.append(";\n");
|
| +
|
| + nodes_end = std::remove(nodes.begin(), nodes_end, it->second);
|
| + }
|
| + nodes.erase(nodes_end, nodes.end());
|
| +
|
| + // Every node that doesn't depend on anything else will implicitly depend on
|
| + // the top level node.
|
| + result.append("\n /* Toplevel attachments */\n");
|
| + for (std::deque<void*>::const_iterator it =
|
| + nodes.begin(); it != nodes.end(); ++it) {
|
| + result.append(" ");
|
| + result.append(get_node_name_callback_.Run(*it));
|
| + result.append(" -> ");
|
| + result.append(toplevel_name);
|
| + result.append(";\n");
|
| + }
|
| +
|
| + result.append("\n /* Toplevel node */\n");
|
| + result.append(" ");
|
| + result.append(toplevel_name);
|
| + result.append(" [shape=box];\n");
|
| +
|
| + result.append("}\n");
|
| + return result;
|
| +}
|
|
|