Add an exponential backoff to rechecking the app list doodle.
[chromium-blink-merge.git] / components / keyed_service / core / dependency_graph.cc
blob2b7f4126f9b4c2dafcf3cd9d1acde138ee049ade
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "components/keyed_service/core/dependency_graph.h"
7 #include <algorithm>
8 #include <deque>
9 #include <iterator>
11 DependencyGraph::DependencyGraph() {}
13 DependencyGraph::~DependencyGraph() {}
15 void DependencyGraph::AddNode(DependencyNode* node) {
16 all_nodes_.push_back(node);
17 construction_order_.clear();
20 void DependencyGraph::RemoveNode(DependencyNode* node) {
21 all_nodes_.erase(std::remove(all_nodes_.begin(), all_nodes_.end(), node),
22 all_nodes_.end());
24 // Remove all dependency edges that contain this node.
25 EdgeMap::iterator it = edges_.begin();
26 while (it != edges_.end()) {
27 EdgeMap::iterator temp = it;
28 ++it;
30 if (temp->first == node || temp->second == node)
31 edges_.erase(temp);
34 construction_order_.clear();
37 void DependencyGraph::AddEdge(DependencyNode* depended,
38 DependencyNode* dependee) {
39 edges_.insert(std::make_pair(depended, dependee));
40 construction_order_.clear();
43 bool DependencyGraph::GetConstructionOrder(
44 std::vector<DependencyNode*>* order) {
45 if (construction_order_.empty() && !BuildConstructionOrder())
46 return false;
48 *order = construction_order_;
49 return true;
52 bool DependencyGraph::GetDestructionOrder(std::vector<DependencyNode*>* order) {
53 if (construction_order_.empty() && !BuildConstructionOrder())
54 return false;
56 *order = construction_order_;
58 // Destroy nodes in reverse order.
59 std::reverse(order->begin(), order->end());
61 return true;
64 bool DependencyGraph::BuildConstructionOrder() {
65 // Step 1: Build a set of nodes with no incoming edges.
66 std::deque<DependencyNode*> queue;
67 std::copy(all_nodes_.begin(), all_nodes_.end(), std::back_inserter(queue));
69 std::deque<DependencyNode*>::iterator queue_end = queue.end();
70 for (EdgeMap::const_iterator it = edges_.begin(); it != edges_.end(); ++it) {
71 queue_end = std::remove(queue.begin(), queue_end, it->second);
73 queue.erase(queue_end, queue.end());
75 // Step 2: Do the Kahn topological sort.
76 std::vector<DependencyNode*> output;
77 EdgeMap edges(edges_);
78 while (!queue.empty()) {
79 DependencyNode* node = queue.front();
80 queue.pop_front();
81 output.push_back(node);
83 std::pair<EdgeMap::iterator, EdgeMap::iterator> range =
84 edges.equal_range(node);
85 EdgeMap::iterator it = range.first;
86 while (it != range.second) {
87 DependencyNode* dest = it->second;
88 EdgeMap::iterator temp = it;
89 it++;
90 edges.erase(temp);
92 bool has_incoming_edges = false;
93 for (EdgeMap::iterator jt = edges.begin(); jt != edges.end(); ++jt) {
94 if (jt->second == dest) {
95 has_incoming_edges = true;
96 break;
100 if (!has_incoming_edges)
101 queue.push_back(dest);
105 if (!edges.empty()) {
106 // Dependency graph has a cycle.
107 return false;
110 construction_order_ = output;
111 return true;
114 std::string DependencyGraph::DumpAsGraphviz(
115 const std::string& toplevel_name,
116 const base::Callback<std::string(DependencyNode*)>& node_name_callback)
117 const {
118 std::string result("digraph {\n");
120 // Make a copy of all nodes.
121 std::deque<DependencyNode*> nodes;
122 std::copy(all_nodes_.begin(), all_nodes_.end(), std::back_inserter(nodes));
124 // State all dependencies and remove |second| so we don't generate an
125 // implicit dependency on the top level node.
126 std::deque<DependencyNode*>::iterator nodes_end(nodes.end());
127 result.append(" /* Dependencies */\n");
128 for (EdgeMap::const_iterator it = edges_.begin(); it != edges_.end(); ++it) {
129 result.append(" ");
130 result.append(node_name_callback.Run(it->second));
131 result.append(" -> ");
132 result.append(node_name_callback.Run(it->first));
133 result.append(";\n");
135 nodes_end = std::remove(nodes.begin(), nodes_end, it->second);
137 nodes.erase(nodes_end, nodes.end());
139 // Every node that doesn't depend on anything else will implicitly depend on
140 // the top level node.
141 result.append("\n /* Toplevel attachments */\n");
142 for (std::deque<DependencyNode*>::const_iterator it = nodes.begin();
143 it != nodes.end();
144 ++it) {
145 result.append(" ");
146 result.append(node_name_callback.Run(*it));
147 result.append(" -> ");
148 result.append(toplevel_name);
149 result.append(";\n");
152 result.append("\n /* Toplevel node */\n");
153 result.append(" ");
154 result.append(toplevel_name);
155 result.append(" [shape=box];\n");
157 result.append("}\n");
158 return result;