| Index: base/values.cc
|
| diff --git a/base/values.cc b/base/values.cc
|
| index 031e1caf1144232e2b9e7db17fef28eb03ccdb08..8fdd4ea39d47fed85a7afdb9ed6c1b766ea113a9 100644
|
| --- a/base/values.cc
|
| +++ b/base/values.cc
|
| @@ -874,6 +874,114 @@ void DictionaryValue::MergeDictionary(const DictionaryValue* dictionary) {
|
| }
|
| }
|
|
|
| +bool DictionaryValue::GetDifferingPathsHelper(
|
| + const std::string& path_prefix,
|
| + const DictionaryValue* other,
|
| + std::vector<std::string>* different_paths) const {
|
| + bool added_path = false;
|
| + std::map<std::string, Value*>::const_iterator current_this;
|
| + std::map<std::string, Value*>::const_iterator end_this;
|
| + current_this = dictionary_.begin();
|
| + end_this = dictionary_.end();
|
| + if (!other) {
|
| + // Recursively add all paths from the |this| dictionary, since they are
|
| + // not in |other|.
|
| + for (; current_this != end_this; ++current_this) {
|
| + std::string full_path_for_key(path_prefix.empty() ? current_this->first :
|
| + path_prefix + "." + current_this->first);
|
| + different_paths->push_back(full_path_for_key);
|
| + added_path = true;
|
| + if (current_this->second->IsType(Value::TYPE_DICTIONARY)) {
|
| + const DictionaryValue* dictionary_this =
|
| + static_cast<const DictionaryValue*>(current_this->second);
|
| + dictionary_this->GetDifferingPathsHelper(full_path_for_key,
|
| + NULL,
|
| + different_paths);
|
| + }
|
| + }
|
| + } else {
|
| + // Both the |this| and |other| dictionaries have entries. Iterate over
|
| + // both simultaneously. Paths that are in one but not the other are
|
| + // added to |different_paths| and DictionaryValues are processed
|
| + // recursively.
|
| + std::map<std::string, Value*>::const_iterator current_other =
|
| + other->dictionary_.begin();
|
| + std::map<std::string, Value*>::const_iterator end_other =
|
| + other->dictionary_.end();
|
| + while (current_this != end_this || current_other != end_other) {
|
| + const Value* recursion_this = NULL;
|
| + const Value* recursion_other = NULL;
|
| + const std::string* key_name = NULL;
|
| + bool current_value_known_equal = false;
|
| + if (current_this == end_this ||
|
| + (current_other != end_other &&
|
| + (current_other->first < current_this->first))) {
|
| + key_name = ¤t_other->first;
|
| + if (current_other->second->IsType(Value::TYPE_DICTIONARY))
|
| + recursion_this = current_other->second;
|
| + ++current_other;
|
| + } else {
|
| + key_name = ¤t_this->first;
|
| + if (current_other == end_other ||
|
| + current_this->first < current_other->first) {
|
| + if (current_this->second->IsType(Value::TYPE_DICTIONARY))
|
| + recursion_this = current_this->second;
|
| + ++current_this;
|
| + } else {
|
| + DCHECK(current_this->first == current_other->first);
|
| + if (current_this->second->IsType(Value::TYPE_DICTIONARY)) {
|
| + recursion_this = current_this->second;
|
| + if (current_other->second->IsType(Value::TYPE_DICTIONARY)) {
|
| + recursion_other = current_other->second;
|
| + }
|
| + } else {
|
| + if (current_other->second->IsType(Value::TYPE_DICTIONARY)) {
|
| + recursion_this = current_other->second;
|
| + } else {
|
| + current_value_known_equal =
|
| + current_this->second->Equals(current_other->second);
|
| + }
|
| + }
|
| + ++current_this;
|
| + ++current_other;
|
| + }
|
| + }
|
| + const std::string& full_path_for_key(path_prefix.empty() ?
|
| + *key_name : path_prefix + "." + *key_name);
|
| + if (!current_value_known_equal)
|
| + different_paths->push_back(full_path_for_key);
|
| + if (recursion_this) {
|
| + const DictionaryValue* dictionary_this =
|
| + static_cast<const DictionaryValue*>(recursion_this);
|
| + bool subtree_changed = dictionary_this->GetDifferingPathsHelper(
|
| + full_path_for_key,
|
| + static_cast<const DictionaryValue*>(recursion_other),
|
| + different_paths);
|
| + if (subtree_changed) {
|
| + added_path = true;
|
| + } else {
|
| + // In order to maintain lexicographical sorting order, directory
|
| + // paths are pushed "optimistically" assuming that their subtree will
|
| + // contain differences. If in retrospect there were no differences
|
| + // in the subtree, the assumption was false and the dictionary path
|
| + // must be removed.
|
| + different_paths->pop_back();
|
| + }
|
| + } else {
|
| + added_path |= !current_value_known_equal;
|
| + }
|
| + }
|
| + }
|
| + return added_path;
|
| +}
|
| +
|
| +void DictionaryValue::GetDifferingPaths(
|
| + const DictionaryValue* other,
|
| + std::vector<std::string>* different_paths) const {
|
| + different_paths->clear();
|
| + GetDifferingPathsHelper("", other, different_paths);
|
| +}
|
| +
|
| ///////////////////// ListValue ////////////////////
|
|
|
| ListValue::ListValue() : Value(TYPE_LIST) {
|
|
|