diff options
Diffstat (limited to 'src/google/protobuf/util/message_differencer.cc')
-rw-r--r-- | src/google/protobuf/util/message_differencer.cc | 104 |
1 files changed, 81 insertions, 23 deletions
diff --git a/src/google/protobuf/util/message_differencer.cc b/src/google/protobuf/util/message_differencer.cc index 830850be..d62038ad 100644 --- a/src/google/protobuf/util/message_differencer.cc +++ b/src/google/protobuf/util/message_differencer.cc @@ -53,6 +53,7 @@ #include <google/protobuf/io/printer.h> #include <google/protobuf/io/zero_copy_stream.h> #include <google/protobuf/io/zero_copy_stream_impl.h> +#include <google/protobuf/descriptor.pb.h> #include <google/protobuf/dynamic_message.h> #include <google/protobuf/text_format.h> #include <google/protobuf/util/field_comparator.h> @@ -150,6 +151,32 @@ class MessageDifferencer::MultipleFieldsMapKeyComparator GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MultipleFieldsMapKeyComparator); }; +MessageDifferencer::MapEntryKeyComparator::MapEntryKeyComparator( + MessageDifferencer* message_differencer) + : message_differencer_(message_differencer) {} + +bool MessageDifferencer::MapEntryKeyComparator::IsMatch( + const Message& message1, const Message& message2, + const std::vector<SpecificField>& parent_fields) const { + // Map entry has its key in the field with tag 1. See the comment for + // map_entry in MessageOptions. + const FieldDescriptor* key = message1.GetDescriptor()->FindFieldByNumber(1); + // If key is not present in message1 and we're doing partial comparison or if + // map key is explicitly ignored treat the field as set instead, + const bool treat_as_set = + (message_differencer_->scope() == PARTIAL && + !message1.GetReflection()->HasField(message1, key)) || + message_differencer_->IsIgnored(message1, message2, key, parent_fields); + + std::vector<SpecificField> current_parent_fields(parent_fields); + if (treat_as_set) { + return message_differencer_->Compare(message1, message2, + ¤t_parent_fields); + } + return message_differencer_->CompareFieldValueUsingParentFields( + message1, message2, key, -1, -1, ¤t_parent_fields); +} + bool MessageDifferencer::Equals(const Message& message1, const Message& message2) { MessageDifferencer differencer; @@ -191,8 +218,10 @@ MessageDifferencer::MessageDifferencer() message_field_comparison_(EQUAL), scope_(FULL), repeated_field_comparison_(AS_LIST), + map_entry_key_comparator_(this), report_matches_(false), - output_string_(NULL) { } + report_moves_(true), + output_string_(NULL) {} MessageDifferencer::~MessageDifferencer() { for (int i = 0; i < owned_key_comparators_.size(); ++i) { @@ -484,8 +513,22 @@ bool MessageDifferencer::Compare( std::vector<const FieldDescriptor*> message2_fields; message2_fields.reserve(1 + message2.GetDescriptor()->field_count()); - reflection1->ListFields(message1, &message1_fields); - reflection2->ListFields(message2, &message2_fields); + if (descriptor1->options().map_entry()) { + if (scope_ == PARTIAL) { + reflection1->ListFields(message1, &message1_fields); + } else { + // Map entry fields are always considered present. + for (int i = 0; i < descriptor1->field_count(); i++) { + message1_fields.push_back(descriptor1->field(i)); + } + } + for (int i = 0; i < descriptor1->field_count(); i++) { + message2_fields.push_back(descriptor1->field(i)); + } + } else { + reflection1->ListFields(message1, &message1_fields); + reflection2->ListFields(message2, &message2_fields); + } // Add sentinel values to deal with the // case where the number of the fields in @@ -783,6 +826,8 @@ bool MessageDifferencer::IsMatch( reflection2->GetRepeatedMessage(*message2, repeated_field, index2); SpecificField specific_field; specific_field.field = repeated_field; + specific_field.index = index1; + specific_field.new_index = index2; current_parent_fields.push_back(specific_field); match = key_comparator->IsMatch(m1, m2, current_parent_fields); } @@ -854,7 +899,7 @@ bool MessageDifferencer::CompareRepeatedField( fieldDifferent = true; } else if (reporter_ != NULL && specific_field.index != specific_field.new_index && - !specific_field.field->is_map()) { + !specific_field.field->is_map() && report_moves_) { parent_fields->push_back(specific_field); reporter_->ReportMoved(message1, message2, *parent_fields); parent_fields->pop_back(); @@ -945,6 +990,8 @@ bool MessageDifferencer::CompareFieldValueUsingParentFields( bool MessageDifferencer::CheckPathChanged( const std::vector<SpecificField>& field_path) { for (int i = 0; i < field_path.size(); ++i) { + // Don't check indexes for map entries -- maps are unordered. + if (field_path[i].field != NULL && field_path[i].field->is_map()) continue; if (field_path[i].index != field_path[i].new_index) return true; } return false; @@ -952,7 +999,6 @@ bool MessageDifferencer::CheckPathChanged( bool MessageDifferencer::IsTreatedAsSet(const FieldDescriptor* field) { if (!field->is_repeated()) return false; - if (field->is_map()) return true; if (repeated_field_comparison_ == AS_SET) return list_fields_.find(field) == list_fields_.end(); return (set_fields_.find(field) != set_fields_.end()); @@ -993,12 +1039,18 @@ bool MessageDifferencer::IsUnknownFieldIgnored( return false; } -const MessageDifferencer::MapKeyComparator* MessageDifferencer - ::GetMapKeyComparator(const FieldDescriptor* field) { +const MessageDifferencer::MapKeyComparator* +MessageDifferencer ::GetMapKeyComparator(const FieldDescriptor* field) const { if (!field->is_repeated()) return NULL; - if (map_field_key_comparator_.find(field) != - map_field_key_comparator_.end()) { - return map_field_key_comparator_[field]; + FieldKeyComparatorMap::const_iterator it = + map_field_key_comparator_.find(field); + if (it != map_field_key_comparator_.end()) { + return it->second; + } + if (field->is_map()) { + // field cannot already be treated as list or set since TreatAsList() and + // TreatAsSet() call GetMapKeyComparator() and fail if it returns non-NULL. + return &map_entry_key_comparator_; } return NULL; } @@ -1400,7 +1452,7 @@ bool MessageDifferencer::MatchRepeatedFieldIndices( // algorithm will fail to find a maximum matching. // Here we use the argumenting path algorithm. MaximumMatcher::NodeMatchCallback* callback = - NewPermanentCallback( + ::google::protobuf::NewPermanentCallback( this, &MessageDifferencer::IsMatch, repeated_field, key_comparator, &message1, &message2, parent_fields); @@ -1524,6 +1576,12 @@ void MessageDifferencer::StreamReporter::PrintPath( } } +void MessageDifferencer::StreamReporter::PrintPath( + const std::vector<SpecificField>& field_path, bool left_side, + const Message& message) { + PrintPath(field_path, left_side); +} + void MessageDifferencer:: StreamReporter::PrintValue(const Message& message, const std::vector<SpecificField>& field_path, @@ -1601,7 +1659,7 @@ void MessageDifferencer::StreamReporter::ReportAdded( const Message& message2, const std::vector<SpecificField>& field_path) { printer_->Print("added: "); - PrintPath(field_path, false); + PrintPath(field_path, false, message2); printer_->Print(": "); PrintValue(message2, field_path, false); printer_->Print("\n"); // Print for newlines. @@ -1612,7 +1670,7 @@ void MessageDifferencer::StreamReporter::ReportDeleted( const Message& message2, const std::vector<SpecificField>& field_path) { printer_->Print("deleted: "); - PrintPath(field_path, true); + PrintPath(field_path, true, message1); printer_->Print(": "); PrintValue(message1, field_path, true); printer_->Print("\n"); // Print for newlines @@ -1636,10 +1694,10 @@ void MessageDifferencer::StreamReporter::ReportModified( } printer_->Print("modified: "); - PrintPath(field_path, true); + PrintPath(field_path, true, message1); if (CheckPathChanged(field_path)) { printer_->Print(" -> "); - PrintPath(field_path, false); + PrintPath(field_path, false, message2); } printer_->Print(": "); PrintValue(message1, field_path, true); @@ -1653,9 +1711,9 @@ void MessageDifferencer::StreamReporter::ReportMoved( const Message& message2, const std::vector<SpecificField>& field_path) { printer_->Print("moved: "); - PrintPath(field_path, true); + PrintPath(field_path, true, message1); printer_->Print(" -> "); - PrintPath(field_path, false); + PrintPath(field_path, false, message2); printer_->Print(" : "); PrintValue(message1, field_path, true); printer_->Print("\n"); // Print for newlines. @@ -1666,10 +1724,10 @@ void MessageDifferencer::StreamReporter::ReportMatched( const Message& message2, const std::vector<SpecificField>& field_path) { printer_->Print("matched: "); - PrintPath(field_path, true); + PrintPath(field_path, true, message1); if (CheckPathChanged(field_path)) { printer_->Print(" -> "); - PrintPath(field_path, false); + PrintPath(field_path, false, message2); } printer_->Print(" : "); PrintValue(message1, field_path, true); @@ -1681,10 +1739,10 @@ void MessageDifferencer::StreamReporter::ReportIgnored( const Message& message2, const std::vector<SpecificField>& field_path) { printer_->Print("ignored: "); - PrintPath(field_path, true); + PrintPath(field_path, true, message1); if (CheckPathChanged(field_path)) { printer_->Print(" -> "); - PrintPath(field_path, false); + PrintPath(field_path, false, message2); } printer_->Print("\n"); // Print for newlines. } @@ -1693,10 +1751,10 @@ void MessageDifferencer::StreamReporter::ReportUnknownFieldIgnored( const Message& message1, const Message& message2, const std::vector<SpecificField>& field_path) { printer_->Print("ignored: "); - PrintPath(field_path, true); + PrintPath(field_path, true, message1); if (CheckPathChanged(field_path)) { printer_->Print(" -> "); - PrintPath(field_path, false); + PrintPath(field_path, false, message2); } printer_->Print("\n"); // Print for newlines. } |