| // Copyright 2017 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/devtools/serialize_host_descriptions.h" |
| |
| #include <map> |
| #include <unordered_set> |
| #include <utility> |
| |
| #include "base/strings/string_piece.h" |
| |
| namespace { |
| |
| // Returns the serialization of |root|. It expects |children[x]| to be the |
| // vector of child nodes for all descendants |x| of |root|. The serialization |
| // consists of taking the |representation| value of each node, starting in |
| // leaves, and injecting children's representations into a ListValue under the |
| // key |child_key| in the parent's |representation|. This is desctructive to the |
| // representation stored with the nodes (which gets moved out of them). |
| base::DictionaryValue Serialize( |
| base::StringPiece child_key, |
| base::DictionaryValue* root, |
| const std::map<base::DictionaryValue*, std::vector<base::DictionaryValue*>>& |
| children) { |
| auto children_list = std::make_unique<base::ListValue>(); |
| auto child_it = children.find(root); |
| if (child_it != children.end()) { |
| for (base::DictionaryValue* child : child_it->second) { |
| children_list->base::Value::Append(Serialize(child_key, child, children)); |
| } |
| } |
| |
| if (!children_list->empty()) |
| root->Set(child_key, std::move(children_list)); |
| return std::move(*root); |
| } |
| |
| // Takes a vector of host description and converts it into: |
| // |children|: a map from a host's representation to representations of its |
| // children, |
| // |roots|: a set of representations of hosts with no parents, and |
| // |representations|: a vector actually storing all those representations to |
| // which the rest just points. |
| void CreateDictionaryForest( |
| std::vector<HostDescriptionNode> hosts, |
| std::map<base::DictionaryValue*, std::vector<base::DictionaryValue*>>* |
| children, |
| std::unordered_set<base::DictionaryValue*>* roots, |
| std::vector<base::DictionaryValue>* representations) { |
| representations->reserve(hosts.size()); |
| children->clear(); |
| roots->clear(); |
| representations->clear(); |
| |
| std::map<base::StringPiece, base::DictionaryValue*> name_to_representation; |
| |
| // First move the representations and map the names to them. |
| for (HostDescriptionNode& node : hosts) { |
| representations->push_back(std::move(node.representation)); |
| // If there are multiple nodes with the same name, subsequent insertions |
| // will be ignored, so only the first node with a given name will be |
| // referenced by |roots| and |children|. |
| name_to_representation.emplace(node.name, &representations->back()); |
| } |
| |
| // Now compute children. |
| for (HostDescriptionNode& node : hosts) { |
| base::DictionaryValue* node_rep = name_to_representation[node.name]; |
| base::StringPiece parent_name = node.parent_name; |
| if (parent_name.empty()) { |
| roots->insert(node_rep); |
| continue; |
| } |
| auto node_it = name_to_representation.find(parent_name); |
| if (node_it == name_to_representation.end()) { |
| roots->insert(node_rep); |
| continue; |
| } |
| (*children)[name_to_representation[parent_name]].push_back(node_rep); |
| } |
| } |
| |
| } // namespace |
| |
| base::ListValue SerializeHostDescriptions( |
| std::vector<HostDescriptionNode> hosts, |
| base::StringPiece child_key) { |
| // |representations| must outlive |children| and |roots|, which contain |
| // pointers to objects in |representations|. |
| std::vector<base::DictionaryValue> representations; |
| std::map<base::DictionaryValue*, std::vector<base::DictionaryValue*>> |
| children; |
| std::unordered_set<base::DictionaryValue*> roots; |
| |
| CreateDictionaryForest(std::move(hosts), &children, &roots, &representations); |
| |
| base::ListValue list_value; |
| for (auto* root : roots) { |
| list_value.base::Value::Append(Serialize(child_key, root, children)); |
| } |
| return list_value; |
| } |