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"
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
),
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
;
30 if (temp
->first
== node
|| temp
->second
== node
)
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())
48 *order
= construction_order_
;
52 bool DependencyGraph::GetDestructionOrder(std::vector
<DependencyNode
*>* order
) {
53 if (construction_order_
.empty() && !BuildConstructionOrder())
56 *order
= construction_order_
;
58 // Destroy nodes in reverse order.
59 std::reverse(order
->begin(), order
->end());
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();
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
;
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;
100 if (!has_incoming_edges
)
101 queue
.push_back(dest
);
105 if (!edges
.empty()) {
106 // Dependency graph has a cycle.
110 construction_order_
= output
;
114 std::string
DependencyGraph::DumpAsGraphviz(
115 const std::string
& toplevel_name
,
116 const base::Callback
<std::string(DependencyNode
*)>& node_name_callback
)
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
) {
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();
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");
154 result
.append(toplevel_name
);
155 result
.append(" [shape=box];\n");
157 result
.append("}\n");