|  | // 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; | 
|  | } |