| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773 |
- // Protocol Buffers - Google's data interchange format
- // Copyright 2008 Google Inc. All rights reserved.
- // https://developers.google.com/protocol-buffers/
- //
- // Redistribution and use in source and binary forms, with or without
- // modification, are permitted provided that the following conditions are
- // met:
- //
- // * Redistributions of source code must retain the above copyright
- // notice, this list of conditions and the following disclaimer.
- // * Redistributions in binary form must reproduce the above
- // copyright notice, this list of conditions and the following disclaimer
- // in the documentation and/or other materials provided with the
- // distribution.
- // * Neither the name of Google Inc. nor the names of its
- // contributors may be used to endorse or promote products derived from
- // this software without specific prior written permission.
- //
- // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- // Author: jschorr@google.com (Joseph Schorr)
- // Based on original Protocol Buffers design by
- // Sanjay Ghemawat, Jeff Dean, and others.
- //
- // This file defines static methods and classes for comparing Protocol
- // Messages (see //google/protobuf/util/message_differencer.h for more
- // information).
- #include <google/protobuf/util/message_differencer.h>
- #include <algorithm>
- #include <memory>
- #include <utility>
- #include <google/protobuf/stubs/callback.h>
- #include <google/protobuf/stubs/common.h>
- #include <google/protobuf/stubs/logging.h>
- #include <google/protobuf/stubs/stringprintf.h>
- #include <google/protobuf/any.h>
- #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>
- #include <google/protobuf/stubs/strutil.h>
- namespace google {
- namespace protobuf {
- namespace util {
- // When comparing a repeated field as map, MultipleFieldMapKeyComparator can
- // be used to specify multiple fields as key for key comparison.
- // Two elements of a repeated field will be regarded as having the same key
- // iff they have the same value for every specified key field.
- // Note that you can also specify only one field as key.
- class MessageDifferencer::MultipleFieldsMapKeyComparator
- : public MessageDifferencer::MapKeyComparator {
- public:
- MultipleFieldsMapKeyComparator(
- MessageDifferencer* message_differencer,
- const std::vector<std::vector<const FieldDescriptor*> >& key_field_paths)
- : message_differencer_(message_differencer),
- key_field_paths_(key_field_paths) {
- GOOGLE_CHECK(!key_field_paths_.empty());
- for (int i = 0; i < key_field_paths_.size(); ++i) {
- GOOGLE_CHECK(!key_field_paths_[i].empty());
- }
- }
- MultipleFieldsMapKeyComparator(
- MessageDifferencer* message_differencer,
- const FieldDescriptor* key)
- : message_differencer_(message_differencer) {
- std::vector<const FieldDescriptor*> key_field_path;
- key_field_path.push_back(key);
- key_field_paths_.push_back(key_field_path);
- }
- virtual bool IsMatch(
- const Message& message1,
- const Message& message2,
- const std::vector<SpecificField>& parent_fields) const {
- for (int i = 0; i < key_field_paths_.size(); ++i) {
- if (!IsMatchInternal(message1, message2, parent_fields,
- key_field_paths_[i], 0)) {
- return false;
- }
- }
- return true;
- }
- private:
- bool IsMatchInternal(
- const Message& message1,
- const Message& message2,
- const std::vector<SpecificField>& parent_fields,
- const std::vector<const FieldDescriptor*>& key_field_path,
- int path_index) const {
- const FieldDescriptor* field = key_field_path[path_index];
- std::vector<SpecificField> current_parent_fields(parent_fields);
- if (path_index == key_field_path.size() - 1) {
- if (field->is_repeated()) {
- if (!message_differencer_->CompareRepeatedField(
- message1, message2, field, ¤t_parent_fields)) {
- return false;
- }
- } else {
- if (!message_differencer_->CompareFieldValueUsingParentFields(
- message1, message2, field, -1, -1, ¤t_parent_fields)) {
- return false;
- }
- }
- return true;
- } else {
- const Reflection* reflection1 = message1.GetReflection();
- const Reflection* reflection2 = message2.GetReflection();
- bool has_field1 = reflection1->HasField(message1, field);
- bool has_field2 = reflection2->HasField(message2, field);
- if (!has_field1 && !has_field2) {
- return true;
- }
- if (has_field1 != has_field2) {
- return false;
- }
- SpecificField specific_field;
- specific_field.field = field;
- current_parent_fields.push_back(specific_field);
- return IsMatchInternal(
- reflection1->GetMessage(message1, field),
- reflection2->GetMessage(message2, field),
- current_parent_fields,
- key_field_path,
- path_index + 1);
- }
- }
- MessageDifferencer* message_differencer_;
- std::vector<std::vector<const FieldDescriptor*> > key_field_paths_;
- 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;
- return differencer.Compare(message1, message2);
- }
- bool MessageDifferencer::Equivalent(const Message& message1,
- const Message& message2) {
- MessageDifferencer differencer;
- differencer.set_message_field_comparison(MessageDifferencer::EQUIVALENT);
- return differencer.Compare(message1, message2);
- }
- bool MessageDifferencer::ApproximatelyEquals(const Message& message1,
- const Message& message2) {
- MessageDifferencer differencer;
- differencer.set_float_comparison(
- MessageDifferencer::APPROXIMATE);
- return differencer.Compare(message1, message2);
- }
- bool MessageDifferencer::ApproximatelyEquivalent(const Message& message1,
- const Message& message2) {
- MessageDifferencer differencer;
- differencer.set_message_field_comparison(MessageDifferencer::EQUIVALENT);
- differencer.set_float_comparison(MessageDifferencer::APPROXIMATE);
- return differencer.Compare(message1, message2);
- }
- // ===========================================================================
- MessageDifferencer::MessageDifferencer()
- : reporter_(NULL),
- field_comparator_(NULL),
- message_field_comparison_(EQUAL),
- scope_(FULL),
- repeated_field_comparison_(AS_LIST),
- map_entry_key_comparator_(this),
- report_matches_(false),
- report_moves_(true),
- output_string_(NULL) {}
- MessageDifferencer::~MessageDifferencer() {
- for (int i = 0; i < owned_key_comparators_.size(); ++i) {
- delete owned_key_comparators_[i];
- }
- for (int i = 0; i < ignore_criteria_.size(); ++i) {
- delete ignore_criteria_[i];
- }
- }
- void MessageDifferencer::set_field_comparator(FieldComparator* comparator) {
- GOOGLE_CHECK(comparator) << "Field comparator can't be NULL.";
- field_comparator_ = comparator;
- }
- void MessageDifferencer::set_message_field_comparison(
- MessageFieldComparison comparison) {
- message_field_comparison_ = comparison;
- }
- void MessageDifferencer::set_scope(Scope scope) {
- scope_ = scope;
- }
- MessageDifferencer::Scope MessageDifferencer::scope() {
- return scope_;
- }
- void MessageDifferencer::set_float_comparison(FloatComparison comparison) {
- default_field_comparator_.set_float_comparison(
- comparison == EXACT ?
- DefaultFieldComparator::EXACT : DefaultFieldComparator::APPROXIMATE);
- }
- void MessageDifferencer::set_repeated_field_comparison(
- RepeatedFieldComparison comparison) {
- repeated_field_comparison_ = comparison;
- }
- void MessageDifferencer::TreatAsSet(const FieldDescriptor* field) {
- GOOGLE_CHECK(field->is_repeated()) << "Field must be repeated: "
- << field->full_name();
- const MapKeyComparator* key_comparator = GetMapKeyComparator(field);
- GOOGLE_CHECK(key_comparator == NULL)
- << "Cannot treat this repeated field as both Map and Set for"
- << " comparison. Field name is: " << field->full_name();
- GOOGLE_CHECK(list_fields_.find(field) == list_fields_.end())
- << "Cannot treat the same field as both SET and LIST. Field name is: "
- << field->full_name();
- set_fields_.insert(field);
- }
- void MessageDifferencer::TreatAsList(const FieldDescriptor* field) {
- GOOGLE_CHECK(field->is_repeated()) << "Field must be repeated: "
- << field->full_name();
- const MapKeyComparator* key_comparator = GetMapKeyComparator(field);
- GOOGLE_CHECK(key_comparator == NULL)
- << "Cannot treat this repeated field as both Map and Set for"
- << " comparison. Field name is: " << field->full_name();
- GOOGLE_CHECK(set_fields_.find(field) == set_fields_.end())
- << "Cannot treat the same field as both SET and LIST. Field name is: "
- << field->full_name();
- list_fields_.insert(field);
- }
- void MessageDifferencer::TreatAsMap(const FieldDescriptor* field,
- const FieldDescriptor* key) {
- GOOGLE_CHECK(field->is_repeated()) << "Field must be repeated: "
- << field->full_name();
- GOOGLE_CHECK_EQ(FieldDescriptor::CPPTYPE_MESSAGE, field->cpp_type())
- << "Field has to be message type. Field name is: "
- << field->full_name();
- GOOGLE_CHECK(key->containing_type() == field->message_type())
- << key->full_name()
- << " must be a direct subfield within the repeated field "
- << field->full_name() << ", not " << key->containing_type()->full_name();
- GOOGLE_CHECK(set_fields_.find(field) == set_fields_.end())
- << "Cannot treat this repeated field as both Map and Set for "
- << "comparison.";
- GOOGLE_CHECK(list_fields_.find(field) == list_fields_.end())
- << "Cannot treat this repeated field as both Map and List for "
- << "comparison.";
- MapKeyComparator* key_comparator =
- new MultipleFieldsMapKeyComparator(this, key);
- owned_key_comparators_.push_back(key_comparator);
- map_field_key_comparator_[field] = key_comparator;
- }
- void MessageDifferencer::TreatAsMapWithMultipleFieldsAsKey(
- const FieldDescriptor* field,
- const std::vector<const FieldDescriptor*>& key_fields) {
- std::vector<std::vector<const FieldDescriptor*> > key_field_paths;
- for (int i = 0; i < key_fields.size(); ++i) {
- std::vector<const FieldDescriptor*> key_field_path;
- key_field_path.push_back(key_fields[i]);
- key_field_paths.push_back(key_field_path);
- }
- TreatAsMapWithMultipleFieldPathsAsKey(field, key_field_paths);
- }
- void MessageDifferencer::TreatAsMapWithMultipleFieldPathsAsKey(
- const FieldDescriptor* field,
- const std::vector<std::vector<const FieldDescriptor*> >& key_field_paths) {
- GOOGLE_CHECK(field->is_repeated()) << "Field must be repeated: "
- << field->full_name();
- GOOGLE_CHECK_EQ(FieldDescriptor::CPPTYPE_MESSAGE, field->cpp_type())
- << "Field has to be message type. Field name is: "
- << field->full_name();
- for (int i = 0; i < key_field_paths.size(); ++i) {
- const std::vector<const FieldDescriptor*>& key_field_path =
- key_field_paths[i];
- for (int j = 0; j < key_field_path.size(); ++j) {
- const FieldDescriptor* parent_field =
- j == 0 ? field : key_field_path[j - 1];
- const FieldDescriptor* child_field = key_field_path[j];
- GOOGLE_CHECK(child_field->containing_type() == parent_field->message_type())
- << child_field->full_name()
- << " must be a direct subfield within the field: "
- << parent_field->full_name();
- if (j != 0) {
- GOOGLE_CHECK_EQ(FieldDescriptor::CPPTYPE_MESSAGE, parent_field->cpp_type())
- << parent_field->full_name() << " has to be of type message.";
- GOOGLE_CHECK(!parent_field->is_repeated())
- << parent_field->full_name() << " cannot be a repeated field.";
- }
- }
- }
- GOOGLE_CHECK(set_fields_.find(field) == set_fields_.end())
- << "Cannot treat this repeated field as both Map and Set for "
- << "comparison.";
- MapKeyComparator* key_comparator =
- new MultipleFieldsMapKeyComparator(this, key_field_paths);
- owned_key_comparators_.push_back(key_comparator);
- map_field_key_comparator_[field] = key_comparator;
- }
- void MessageDifferencer::TreatAsMapUsingKeyComparator(
- const FieldDescriptor* field,
- const MapKeyComparator* key_comparator) {
- GOOGLE_CHECK(field->is_repeated()) << "Field must be repeated: "
- << field->full_name();
- GOOGLE_CHECK(set_fields_.find(field) == set_fields_.end())
- << "Cannot treat this repeated field as both Map and Set for "
- << "comparison.";
- map_field_key_comparator_[field] = key_comparator;
- }
- void MessageDifferencer::AddIgnoreCriteria(IgnoreCriteria* ignore_criteria) {
- ignore_criteria_.push_back(ignore_criteria);
- }
- void MessageDifferencer::IgnoreField(const FieldDescriptor* field) {
- ignored_fields_.insert(field);
- }
- void MessageDifferencer::SetFractionAndMargin(const FieldDescriptor* field,
- double fraction, double margin) {
- default_field_comparator_.SetFractionAndMargin(field, fraction, margin);
- }
- void MessageDifferencer::ReportDifferencesToString(string* output) {
- GOOGLE_DCHECK(output) << "Specified output string was NULL";
- output_string_ = output;
- output_string_->clear();
- }
- void MessageDifferencer::ReportDifferencesTo(Reporter* reporter) {
- // If an output string is set, clear it to prevent
- // it superceding the specified reporter.
- if (output_string_) {
- output_string_ = NULL;
- }
- reporter_ = reporter;
- }
- bool MessageDifferencer::FieldBefore(const FieldDescriptor* field1,
- const FieldDescriptor* field2) {
- // Handle sentinel values (i.e. make sure NULLs are always ordered
- // at the end of the list).
- if (field1 == NULL) {
- return false;
- }
- if (field2 == NULL) {
- return true;
- }
- // Always order fields by their tag number
- return (field1->number() < field2->number());
- }
- bool MessageDifferencer::Compare(const Message& message1,
- const Message& message2) {
- std::vector<SpecificField> parent_fields;
- bool result = false;
- // Setup the internal reporter if need be.
- if (output_string_) {
- io::StringOutputStream output_stream(output_string_);
- StreamReporter reporter(&output_stream);
- reporter_ = &reporter;
- result = Compare(message1, message2, &parent_fields);
- reporter_ = NULL;
- } else {
- result = Compare(message1, message2, &parent_fields);
- }
- return result;
- }
- bool MessageDifferencer::CompareWithFields(
- const Message& message1,
- const Message& message2,
- const std::vector<const FieldDescriptor*>& message1_fields_arg,
- const std::vector<const FieldDescriptor*>& message2_fields_arg) {
- if (message1.GetDescriptor() != message2.GetDescriptor()) {
- GOOGLE_LOG(DFATAL) << "Comparison between two messages with different "
- << "descriptors.";
- return false;
- }
- std::vector<SpecificField> parent_fields;
- bool result = false;
- std::vector<const FieldDescriptor*> message1_fields(message1_fields_arg);
- std::vector<const FieldDescriptor*> message2_fields(message2_fields_arg);
- std::sort(message1_fields.begin(), message1_fields.end(), FieldBefore);
- std::sort(message2_fields.begin(), message2_fields.end(), FieldBefore);
- // Append NULL sentinel values.
- message1_fields.push_back(NULL);
- message2_fields.push_back(NULL);
- // Setup the internal reporter if need be.
- if (output_string_) {
- io::StringOutputStream output_stream(output_string_);
- StreamReporter reporter(&output_stream);
- reporter_ = &reporter;
- result = CompareRequestedFieldsUsingSettings(
- message1, message2, message1_fields, message2_fields, &parent_fields);
- reporter_ = NULL;
- } else {
- result = CompareRequestedFieldsUsingSettings(
- message1, message2, message1_fields, message2_fields, &parent_fields);
- }
- return result;
- }
- bool MessageDifferencer::Compare(
- const Message& message1,
- const Message& message2,
- std::vector<SpecificField>* parent_fields) {
- const Descriptor* descriptor1 = message1.GetDescriptor();
- const Descriptor* descriptor2 = message2.GetDescriptor();
- if (descriptor1 != descriptor2) {
- GOOGLE_LOG(DFATAL) << "Comparison between two messages with different "
- << "descriptors. "
- << descriptor1->full_name() << " vs "
- << descriptor2->full_name();
- return false;
- }
- // Expand google.protobuf.Any payload if possible.
- if (descriptor1->full_name() == internal::kAnyFullTypeName) {
- std::unique_ptr<Message> data1;
- std::unique_ptr<Message> data2;
- if (UnpackAny(message1, &data1) && UnpackAny(message2, &data2)) {
- // Avoid DFATAL for different descriptors in google.protobuf.Any payloads.
- if (data1->GetDescriptor() != data2->GetDescriptor()) {
- return false;
- }
- return Compare(*data1, *data2, parent_fields);
- }
- }
- const Reflection* reflection1 = message1.GetReflection();
- const Reflection* reflection2 = message2.GetReflection();
- // Retrieve all the set fields, including extensions.
- std::vector<const FieldDescriptor*> message1_fields;
- message1_fields.reserve(1 + message1.GetDescriptor()->field_count());
- std::vector<const FieldDescriptor*> message2_fields;
- message2_fields.reserve(1 + message2.GetDescriptor()->field_count());
- 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
- // each list are different.
- message1_fields.push_back(NULL);
- message2_fields.push_back(NULL);
- bool unknown_compare_result = true;
- // Ignore unknown fields in EQUIVALENT mode
- if (message_field_comparison_ != EQUIVALENT) {
- const google::protobuf::UnknownFieldSet* unknown_field_set1 =
- &reflection1->GetUnknownFields(message1);
- const google::protobuf::UnknownFieldSet* unknown_field_set2 =
- &reflection2->GetUnknownFields(message2);
- if (!CompareUnknownFields(message1, message2,
- *unknown_field_set1, *unknown_field_set2,
- parent_fields)) {
- if (reporter_ == NULL) {
- return false;
- };
- unknown_compare_result = false;
- }
- }
- return CompareRequestedFieldsUsingSettings(
- message1, message2,
- message1_fields, message2_fields,
- parent_fields) && unknown_compare_result;
- }
- bool MessageDifferencer::CompareRequestedFieldsUsingSettings(
- const Message& message1,
- const Message& message2,
- const std::vector<const FieldDescriptor*>& message1_fields,
- const std::vector<const FieldDescriptor*>& message2_fields,
- std::vector<SpecificField>* parent_fields) {
- if (scope_ == FULL) {
- if (message_field_comparison_ == EQUIVALENT) {
- // We need to merge the field lists of both messages (i.e.
- // we are merely checking for a difference in field values,
- // rather than the addition or deletion of fields).
- std::vector<const FieldDescriptor*> fields_union;
- CombineFields(message1_fields, FULL, message2_fields, FULL,
- &fields_union);
- return CompareWithFieldsInternal(message1, message2, fields_union,
- fields_union, parent_fields);
- } else {
- // Simple equality comparison, use the unaltered field lists.
- return CompareWithFieldsInternal(message1, message2, message1_fields,
- message2_fields, parent_fields);
- }
- } else {
- if (message_field_comparison_ == EQUIVALENT) {
- // We use the list of fields for message1 for both messages when
- // comparing. This way, extra fields in message2 are ignored,
- // and missing fields in message2 use their default value.
- return CompareWithFieldsInternal(message1, message2, message1_fields,
- message1_fields, parent_fields);
- } else {
- // We need to consider the full list of fields for message1
- // but only the intersection for message2. This way, any fields
- // only present in message2 will be ignored, but any fields only
- // present in message1 will be marked as a difference.
- std::vector<const FieldDescriptor*> fields_intersection;
- CombineFields(message1_fields, PARTIAL, message2_fields, PARTIAL,
- &fields_intersection);
- return CompareWithFieldsInternal(message1, message2, message1_fields,
- fields_intersection, parent_fields);
- }
- }
- }
- void MessageDifferencer::CombineFields(
- const std::vector<const FieldDescriptor*>& fields1,
- Scope fields1_scope,
- const std::vector<const FieldDescriptor*>& fields2,
- Scope fields2_scope,
- std::vector<const FieldDescriptor*>* combined_fields) {
- int index1 = 0;
- int index2 = 0;
- while (index1 < fields1.size() && index2 < fields2.size()) {
- const FieldDescriptor* field1 = fields1[index1];
- const FieldDescriptor* field2 = fields2[index2];
- if (FieldBefore(field1, field2)) {
- if (fields1_scope == FULL) {
- combined_fields->push_back(fields1[index1]);
- }
- ++index1;
- } else if (FieldBefore(field2, field1)) {
- if (fields2_scope == FULL) {
- combined_fields->push_back(fields2[index2]);
- }
- ++index2;
- } else {
- combined_fields->push_back(fields1[index1]);
- ++index1;
- ++index2;
- }
- }
- }
- bool MessageDifferencer::CompareWithFieldsInternal(
- const Message& message1,
- const Message& message2,
- const std::vector<const FieldDescriptor*>& message1_fields,
- const std::vector<const FieldDescriptor*>& message2_fields,
- std::vector<SpecificField>* parent_fields) {
- bool isDifferent = false;
- int field_index1 = 0;
- int field_index2 = 0;
- const Reflection* reflection1 = message1.GetReflection();
- const Reflection* reflection2 = message2.GetReflection();
- while (true) {
- const FieldDescriptor* field1 = message1_fields[field_index1];
- const FieldDescriptor* field2 = message2_fields[field_index2];
- // Once we have reached sentinel values, we are done the comparison.
- if (field1 == NULL && field2 == NULL) {
- break;
- }
- // Check for differences in the field itself.
- if (FieldBefore(field1, field2)) {
- // Field 1 is not in the field list for message 2.
- if (IsIgnored(message1, message2, field1, *parent_fields)) {
- // We are ignoring field1. Report the ignore and move on to
- // the next field in message1_fields.
- if (reporter_ != NULL) {
- SpecificField specific_field;
- specific_field.field = field1;
- parent_fields->push_back(specific_field);
- reporter_->ReportIgnored(message1, message2, *parent_fields);
- parent_fields->pop_back();
- }
- ++field_index1;
- continue;
- }
- if (reporter_ != NULL) {
- assert(field1 != NULL);
- int count = field1->is_repeated() ?
- reflection1->FieldSize(message1, field1) : 1;
- for (int i = 0; i < count; ++i) {
- SpecificField specific_field;
- specific_field.field = field1;
- specific_field.index = field1->is_repeated() ? i : -1;
- parent_fields->push_back(specific_field);
- reporter_->ReportDeleted(message1, message2, *parent_fields);
- parent_fields->pop_back();
- }
- isDifferent = true;
- } else {
- return false;
- }
- ++field_index1;
- continue;
- } else if (FieldBefore(field2, field1)) {
- // Field 2 is not in the field list for message 1.
- if (IsIgnored(message1, message2, field2, *parent_fields)) {
- // We are ignoring field2. Report the ignore and move on to
- // the next field in message2_fields.
- if (reporter_ != NULL) {
- SpecificField specific_field;
- specific_field.field = field2;
- parent_fields->push_back(specific_field);
- reporter_->ReportIgnored(message1, message2, *parent_fields);
- parent_fields->pop_back();
- }
- ++field_index2;
- continue;
- }
- if (reporter_ != NULL) {
- int count = field2->is_repeated() ?
- reflection2->FieldSize(message2, field2) : 1;
- for (int i = 0; i < count; ++i) {
- SpecificField specific_field;
- specific_field.field = field2;
- specific_field.index = field2->is_repeated() ? i : -1;
- specific_field.new_index = specific_field.index;
- parent_fields->push_back(specific_field);
- reporter_->ReportAdded(message1, message2, *parent_fields);
- parent_fields->pop_back();
- }
- isDifferent = true;
- } else {
- return false;
- }
- ++field_index2;
- continue;
- }
- // By this point, field1 and field2 are guarenteed to point to the same
- // field, so we can now compare the values.
- if (IsIgnored(message1, message2, field1, *parent_fields)) {
- // Ignore this field. Report and move on.
- if (reporter_ != NULL) {
- SpecificField specific_field;
- specific_field.field = field1;
- parent_fields->push_back(specific_field);
- reporter_->ReportIgnored(message1, message2, *parent_fields);
- parent_fields->pop_back();
- }
- ++field_index1;
- ++field_index2;
- continue;
- }
- bool fieldDifferent = false;
- assert(field1 != NULL);
- if (field1->is_repeated()) {
- fieldDifferent = !CompareRepeatedField(message1, message2, field1,
- parent_fields);
- if (fieldDifferent) {
- if (reporter_ == NULL) return false;
- isDifferent = true;
- }
- } else {
- fieldDifferent = !CompareFieldValueUsingParentFields(
- message1, message2, field1, -1, -1, parent_fields);
- // If we have found differences, either report them or terminate if
- // no reporter is present.
- if (fieldDifferent && reporter_ == NULL) {
- return false;
- }
- if (reporter_ != NULL) {
- SpecificField specific_field;
- specific_field.field = field1;
- parent_fields->push_back(specific_field);
- if (fieldDifferent) {
- reporter_->ReportModified(message1, message2, *parent_fields);
- isDifferent = true;
- } else if (report_matches_) {
- reporter_->ReportMatched(message1, message2, *parent_fields);
- }
- parent_fields->pop_back();
- }
- }
- // Increment the field indicies.
- ++field_index1;
- ++field_index2;
- }
- return !isDifferent;
- }
- bool MessageDifferencer::IsMatch(
- const FieldDescriptor* repeated_field,
- const MapKeyComparator* key_comparator, const Message* message1,
- const Message* message2, const std::vector<SpecificField>& parent_fields,
- int index1, int index2) {
- std::vector<SpecificField> current_parent_fields(parent_fields);
- if (repeated_field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) {
- return CompareFieldValueUsingParentFields(
- *message1, *message2, repeated_field, index1, index2,
- ¤t_parent_fields);
- }
- // Back up the Reporter and output_string_. They will be reset in the
- // following code.
- Reporter* backup_reporter = reporter_;
- string* output_string = output_string_;
- reporter_ = NULL;
- output_string_ = NULL;
- bool match;
- if (key_comparator == NULL) {
- match = CompareFieldValueUsingParentFields(
- *message1, *message2, repeated_field, index1, index2,
- ¤t_parent_fields);
- } else {
- const Reflection* reflection1 = message1->GetReflection();
- const Reflection* reflection2 = message2->GetReflection();
- const Message& m1 =
- reflection1->GetRepeatedMessage(*message1, repeated_field, index1);
- const Message& m2 =
- 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);
- }
- reporter_ = backup_reporter;
- output_string_ = output_string;
- return match;
- }
- bool MessageDifferencer::CompareRepeatedField(
- const Message& message1,
- const Message& message2,
- const FieldDescriptor* repeated_field,
- std::vector<SpecificField>* parent_fields) {
- // the input FieldDescriptor is guaranteed to be repeated field.
- const Reflection* reflection1 = message1.GetReflection();
- const Reflection* reflection2 = message2.GetReflection();
- const int count1 = reflection1->FieldSize(message1, repeated_field);
- const int count2 = reflection2->FieldSize(message2, repeated_field);
- const bool treated_as_subset = IsTreatedAsSubset(repeated_field);
- // If the field is not treated as subset and no detailed reports is needed,
- // we do a quick check on the number of the elements to avoid unnecessary
- // comparison.
- if (count1 != count2 && reporter_ == NULL && !treated_as_subset) {
- return false;
- }
- // A match can never be found if message1 has more items than message2.
- if (count1 > count2 && reporter_ == NULL) {
- return false;
- }
- // These two list are used for store the index of the correspondent
- // element in peer repeated field.
- std::vector<int> match_list1;
- std::vector<int> match_list2;
- // Try to match indices of the repeated fields. Return false if match fails
- // and there's no detailed report needed.
- if (!MatchRepeatedFieldIndices(message1, message2, repeated_field,
- *parent_fields, &match_list1, &match_list2) &&
- reporter_ == NULL) {
- return false;
- }
- bool fieldDifferent = false;
- SpecificField specific_field;
- specific_field.field = repeated_field;
- // At this point, we have already matched pairs of fields (with the reporting
- // to be done later). Now to check if the paired elements are different.
- for (int i = 0; i < count1; i++) {
- if (match_list1[i] == -1) continue;
- specific_field.index = i;
- specific_field.new_index = match_list1[i];
- const bool result = CompareFieldValueUsingParentFields(
- message1, message2, repeated_field, i, specific_field.new_index,
- parent_fields);
- // If we have found differences, either report them or terminate if
- // no reporter is present. Note that ReportModified, ReportMoved, and
- // ReportMatched are all mutually exclusive.
- if (!result) {
- if (reporter_ == NULL) return false;
- parent_fields->push_back(specific_field);
- reporter_->ReportModified(message1, message2, *parent_fields);
- parent_fields->pop_back();
- fieldDifferent = true;
- } else if (reporter_ != NULL &&
- specific_field.index != specific_field.new_index &&
- !specific_field.field->is_map() && report_moves_) {
- parent_fields->push_back(specific_field);
- reporter_->ReportMoved(message1, message2, *parent_fields);
- parent_fields->pop_back();
- } else if (report_matches_ && reporter_ != NULL) {
- parent_fields->push_back(specific_field);
- reporter_->ReportMatched(message1, message2, *parent_fields);
- parent_fields->pop_back();
- }
- }
- // Report any remaining additions or deletions.
- for (int i = 0; i < count2; ++i) {
- if (match_list2[i] != -1) continue;
- if (!treated_as_subset) {
- fieldDifferent = true;
- }
- if (reporter_ == NULL) continue;
- specific_field.index = i;
- specific_field.new_index = i;
- parent_fields->push_back(specific_field);
- reporter_->ReportAdded(message1, message2, *parent_fields);
- parent_fields->pop_back();
- }
- for (int i = 0; i < count1; ++i) {
- if (match_list1[i] != -1) continue;
- assert(reporter_ != NULL);
- specific_field.index = i;
- parent_fields->push_back(specific_field);
- reporter_->ReportDeleted(message1, message2, *parent_fields);
- parent_fields->pop_back();
- fieldDifferent = true;
- }
- return !fieldDifferent;
- }
- bool MessageDifferencer::CompareFieldValue(const Message& message1,
- const Message& message2,
- const FieldDescriptor* field,
- int index1,
- int index2) {
- return CompareFieldValueUsingParentFields(message1, message2, field, index1,
- index2, NULL);
- }
- bool MessageDifferencer::CompareFieldValueUsingParentFields(
- const Message& message1, const Message& message2,
- const FieldDescriptor* field, int index1, int index2,
- std::vector<SpecificField>* parent_fields) {
- FieldContext field_context(parent_fields);
- FieldComparator::ComparisonResult result = GetFieldComparisonResult(
- message1, message2, field, index1, index2, &field_context);
- if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE &&
- result == FieldComparator::RECURSE) {
- // Get the nested messages and compare them using one of the Compare
- // methods.
- const Reflection* reflection1 = message1.GetReflection();
- const Reflection* reflection2 = message2.GetReflection();
- const Message& m1 = field->is_repeated() ?
- reflection1->GetRepeatedMessage(message1, field, index1) :
- reflection1->GetMessage(message1, field);
- const Message& m2 = field->is_repeated() ?
- reflection2->GetRepeatedMessage(message2, field, index2) :
- reflection2->GetMessage(message2, field);
- // parent_fields is used in calls to Reporter methods.
- if (parent_fields != NULL) {
- // Append currently compared field to the end of parent_fields.
- SpecificField specific_field;
- specific_field.field = field;
- specific_field.index = index1;
- specific_field.new_index = index2;
- parent_fields->push_back(specific_field);
- const bool compare_result = Compare(m1, m2, parent_fields);
- parent_fields->pop_back();
- return compare_result;
- } else {
- // Recreates parent_fields as if m1 and m2 had no parents.
- return Compare(m1, m2);
- }
- } else {
- return (result == FieldComparator::SAME);
- }
- }
- 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;
- }
- bool MessageDifferencer::IsTreatedAsSet(const FieldDescriptor* field) {
- if (!field->is_repeated()) return false;
- if (repeated_field_comparison_ == AS_SET)
- return list_fields_.find(field) == list_fields_.end();
- return (set_fields_.find(field) != set_fields_.end());
- }
- bool MessageDifferencer::IsTreatedAsSubset(const FieldDescriptor* field) {
- return scope_ == PARTIAL &&
- (IsTreatedAsSet(field) || GetMapKeyComparator(field) != NULL);
- }
- bool MessageDifferencer::IsIgnored(
- const Message& message1,
- const Message& message2,
- const FieldDescriptor* field,
- const std::vector<SpecificField>& parent_fields) {
- if (ignored_fields_.find(field) != ignored_fields_.end()) {
- return true;
- }
- for (int i = 0; i < ignore_criteria_.size(); ++i) {
- if (ignore_criteria_[i]->IsIgnored(message1, message2, field,
- parent_fields)) {
- return true;
- }
- }
- return false;
- }
- bool MessageDifferencer::IsUnknownFieldIgnored(
- const Message& message1, const Message& message2,
- const SpecificField& field,
- const std::vector<SpecificField>& parent_fields) {
- for (int i = 0; i < ignore_criteria_.size(); ++i) {
- if (ignore_criteria_[i]->IsUnknownFieldIgnored(message1, message2, field,
- parent_fields)) {
- return true;
- }
- }
- return false;
- }
- const MessageDifferencer::MapKeyComparator*
- MessageDifferencer ::GetMapKeyComparator(const FieldDescriptor* field) const {
- if (!field->is_repeated()) return NULL;
- 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;
- }
- namespace {
- typedef std::pair<int, const UnknownField*> IndexUnknownFieldPair;
- struct UnknownFieldOrdering {
- inline bool operator()(const IndexUnknownFieldPair& a,
- const IndexUnknownFieldPair& b) const {
- if (a.second->number() < b.second->number()) return true;
- if (a.second->number() > b.second->number()) return false;
- return a.second->type() < b.second->type();
- }
- };
- } // namespace
- bool MessageDifferencer::UnpackAny(const Message& any,
- std::unique_ptr<Message>* data) {
- const Reflection* reflection = any.GetReflection();
- const FieldDescriptor* type_url_field;
- const FieldDescriptor* value_field;
- if (!internal::GetAnyFieldDescriptors(any, &type_url_field, &value_field)) {
- return false;
- }
- const string& type_url = reflection->GetString(any, type_url_field);
- string full_type_name;
- if (!internal::ParseAnyTypeUrl(type_url, &full_type_name)) {
- return false;
- }
- const google::protobuf::Descriptor* desc =
- any.GetDescriptor()->file()->pool()->FindMessageTypeByName(
- full_type_name);
- if (desc == NULL) {
- GOOGLE_DLOG(ERROR) << "Proto type '" << full_type_name << "' not found";
- return false;
- }
- if (dynamic_message_factory_ == NULL) {
- dynamic_message_factory_.reset(new DynamicMessageFactory());
- }
- data->reset(dynamic_message_factory_->GetPrototype(desc)->New());
- string serialized_value = reflection->GetString(any, value_field);
- if (!(*data)->ParseFromString(serialized_value)) {
- GOOGLE_DLOG(ERROR) << "Failed to parse value for " << full_type_name;
- return false;
- }
- return true;
- }
- bool MessageDifferencer::CompareUnknownFields(
- const Message& message1, const Message& message2,
- const google::protobuf::UnknownFieldSet& unknown_field_set1,
- const google::protobuf::UnknownFieldSet& unknown_field_set2,
- std::vector<SpecificField>* parent_field) {
- // Ignore unknown fields in EQUIVALENT mode.
- if (message_field_comparison_ == EQUIVALENT) return true;
- if (unknown_field_set1.empty() && unknown_field_set2.empty()) {
- return true;
- }
- bool is_different = false;
- // We first sort the unknown fields by field number and type (in other words,
- // in tag order), making sure to preserve ordering of values with the same
- // tag. This allows us to report only meaningful differences between the
- // two sets -- that is, differing values for the same tag. We use
- // IndexUnknownFieldPairs to keep track of the field's original index for
- // reporting purposes.
- std::vector<IndexUnknownFieldPair> fields1; // unknown_field_set1, sorted
- std::vector<IndexUnknownFieldPair> fields2; // unknown_field_set2, sorted
- fields1.reserve(unknown_field_set1.field_count());
- fields2.reserve(unknown_field_set2.field_count());
- for (int i = 0; i < unknown_field_set1.field_count(); i++) {
- fields1.push_back(std::make_pair(i, &unknown_field_set1.field(i)));
- }
- for (int i = 0; i < unknown_field_set2.field_count(); i++) {
- fields2.push_back(std::make_pair(i, &unknown_field_set2.field(i)));
- }
- UnknownFieldOrdering is_before;
- std::stable_sort(fields1.begin(), fields1.end(), is_before);
- std::stable_sort(fields2.begin(), fields2.end(), is_before);
- // In order to fill in SpecificField::index, we have to keep track of how
- // many values we've seen with the same field number and type.
- // current_repeated points at the first field in this range, and
- // current_repeated_start{1,2} are the indexes of the first field in the
- // range within fields1 and fields2.
- const UnknownField* current_repeated = NULL;
- int current_repeated_start1 = 0;
- int current_repeated_start2 = 0;
- // Now that we have two sorted lists, we can detect fields which appear only
- // in one list or the other by traversing them simultaneously.
- int index1 = 0;
- int index2 = 0;
- while (index1 < fields1.size() || index2 < fields2.size()) {
- enum { ADDITION, DELETION, MODIFICATION, COMPARE_GROUPS,
- NO_CHANGE } change_type;
- // focus_field is the field we're currently reporting on. (In the case
- // of a modification, it's the field on the left side.)
- const UnknownField* focus_field;
- bool match = false;
- if (index2 == fields2.size() ||
- (index1 < fields1.size() &&
- is_before(fields1[index1], fields2[index2]))) {
- // fields1[index1] is not present in fields2.
- change_type = DELETION;
- focus_field = fields1[index1].second;
- } else if (index1 == fields1.size() ||
- is_before(fields2[index2], fields1[index1])) {
- // fields2[index2] is not present in fields1.
- if (scope_ == PARTIAL) {
- // Ignore.
- ++index2;
- continue;
- }
- change_type = ADDITION;
- focus_field = fields2[index2].second;
- } else {
- // Field type and number are the same. See if the values differ.
- change_type = MODIFICATION;
- focus_field = fields1[index1].second;
- switch (focus_field->type()) {
- case UnknownField::TYPE_VARINT:
- match = fields1[index1].second->varint() ==
- fields2[index2].second->varint();
- break;
- case UnknownField::TYPE_FIXED32:
- match = fields1[index1].second->fixed32() ==
- fields2[index2].second->fixed32();
- break;
- case UnknownField::TYPE_FIXED64:
- match = fields1[index1].second->fixed64() ==
- fields2[index2].second->fixed64();
- break;
- case UnknownField::TYPE_LENGTH_DELIMITED:
- match = fields1[index1].second->length_delimited() ==
- fields2[index2].second->length_delimited();
- break;
- case UnknownField::TYPE_GROUP:
- // We must deal with this later, after building the SpecificField.
- change_type = COMPARE_GROUPS;
- break;
- }
- if (match && change_type != COMPARE_GROUPS) {
- change_type = NO_CHANGE;
- }
- }
- if (current_repeated == NULL ||
- focus_field->number() != current_repeated->number() ||
- focus_field->type() != current_repeated->type()) {
- // We've started a new repeated field.
- current_repeated = focus_field;
- current_repeated_start1 = index1;
- current_repeated_start2 = index2;
- }
- if (change_type == NO_CHANGE && reporter_ == NULL) {
- // Fields were already compared and matched and we have no reporter.
- ++index1;
- ++index2;
- continue;
- }
- // Build the SpecificField. This is slightly complicated.
- SpecificField specific_field;
- specific_field.unknown_field_number = focus_field->number();
- specific_field.unknown_field_type = focus_field->type();
- specific_field.unknown_field_set1 = &unknown_field_set1;
- specific_field.unknown_field_set2 = &unknown_field_set2;
- if (change_type != ADDITION) {
- specific_field.unknown_field_index1 = fields1[index1].first;
- }
- if (change_type != DELETION) {
- specific_field.unknown_field_index2 = fields2[index2].first;
- }
- // Calculate the field index.
- if (change_type == ADDITION) {
- specific_field.index = index2 - current_repeated_start2;
- specific_field.new_index = index2 - current_repeated_start2;
- } else {
- specific_field.index = index1 - current_repeated_start1;
- specific_field.new_index = index2 - current_repeated_start2;
- }
- if (IsUnknownFieldIgnored(message1, message2, specific_field,
- *parent_field)) {
- if (reporter_ != NULL) {
- parent_field->push_back(specific_field);
- reporter_->ReportUnknownFieldIgnored(message1, message2, *parent_field);
- parent_field->pop_back();
- }
- return true;
- }
- if (change_type == ADDITION || change_type == DELETION ||
- change_type == MODIFICATION) {
- if (reporter_ == NULL) {
- // We found a difference and we have no reproter.
- return false;
- }
- is_different = true;
- }
- parent_field->push_back(specific_field);
- switch (change_type) {
- case ADDITION:
- reporter_->ReportAdded(message1, message2, *parent_field);
- ++index2;
- break;
- case DELETION:
- reporter_->ReportDeleted(message1, message2, *parent_field);
- ++index1;
- break;
- case MODIFICATION:
- reporter_->ReportModified(message1, message2, *parent_field);
- ++index1;
- ++index2;
- break;
- case COMPARE_GROUPS:
- if (!CompareUnknownFields(message1, message2,
- fields1[index1].second->group(),
- fields2[index2].second->group(),
- parent_field)) {
- if (reporter_ == NULL) return false;
- is_different = true;
- reporter_->ReportModified(message1, message2, *parent_field);
- }
- ++index1;
- ++index2;
- break;
- case NO_CHANGE:
- ++index1;
- ++index2;
- if (report_matches_) {
- reporter_->ReportMatched(message1, message2, *parent_field);
- }
- }
- parent_field->pop_back();
- }
- return !is_different;
- }
- namespace {
- // Find maximum bipartite matching using the argumenting path algorithm.
- class MaximumMatcher {
- public:
- typedef ResultCallback2<bool, int, int> NodeMatchCallback;
- // MaximumMatcher takes ownership of the passed in callback and uses it to
- // determine whether a node on the left side of the bipartial graph matches
- // a node on the right side. count1 is the number of nodes on the left side
- // of the graph and count2 to is the number of nodes on the right side.
- // Every node is referred to using 0-based indices.
- // If a maximum match is found, the result will be stored in match_list1 and
- // match_list2. match_list1[i] == j means the i-th node on the left side is
- // matched to the j-th node on the right side and match_list2[x] == y means
- // the x-th node on the right side is matched to y-th node on the left side.
- // match_list1[i] == -1 means the node is not matched. Same with match_list2.
- MaximumMatcher(int count1, int count2, NodeMatchCallback* callback,
- std::vector<int>* match_list1, std::vector<int>* match_list2);
- // Find a maximum match and return the number of matched node pairs.
- // If early_return is true, this method will return 0 immediately when it
- // finds that not all nodes on the left side can be matched.
- int FindMaximumMatch(bool early_return);
- private:
- // Determines whether the node on the left side of the bipartial graph
- // matches the one on the right side.
- bool Match(int left, int right);
- // Find an argumenting path starting from the node v on the left side. If a
- // path can be found, update match_list2_ to reflect the path and return
- // true.
- bool FindArgumentPathDFS(int v, std::vector<bool>* visited);
- int count1_;
- int count2_;
- std::unique_ptr<NodeMatchCallback> match_callback_;
- std::map<std::pair<int, int>, bool> cached_match_results_;
- std::vector<int>* match_list1_;
- std::vector<int>* match_list2_;
- GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MaximumMatcher);
- };
- MaximumMatcher::MaximumMatcher(int count1, int count2,
- NodeMatchCallback* callback,
- std::vector<int>* match_list1,
- std::vector<int>* match_list2)
- : count1_(count1), count2_(count2), match_callback_(callback),
- match_list1_(match_list1), match_list2_(match_list2) {
- match_list1_->assign(count1, -1);
- match_list2_->assign(count2, -1);
- }
- int MaximumMatcher::FindMaximumMatch(bool early_return) {
- int result = 0;
- for (int i = 0; i < count1_; ++i) {
- std::vector<bool> visited(count1_);
- if (FindArgumentPathDFS(i, &visited)) {
- ++result;
- } else if (early_return) {
- return 0;
- }
- }
- // Backfill match_list1_ as we only filled match_list2_ when finding
- // argumenting pathes.
- for (int i = 0; i < count2_; ++i) {
- if ((*match_list2_)[i] != -1) {
- (*match_list1_)[(*match_list2_)[i]] = i;
- }
- }
- return result;
- }
- bool MaximumMatcher::Match(int left, int right) {
- std::pair<int, int> p(left, right);
- std::map<std::pair<int, int>, bool>::iterator it =
- cached_match_results_.find(p);
- if (it != cached_match_results_.end()) {
- return it->second;
- }
- cached_match_results_[p] = match_callback_->Run(left, right);
- return cached_match_results_[p];
- }
- bool MaximumMatcher::FindArgumentPathDFS(int v, std::vector<bool>* visited) {
- (*visited)[v] = true;
- // We try to match those un-matched nodes on the right side first. This is
- // the step that the navie greedy matching algorithm uses. In the best cases
- // where the greedy algorithm can find a maximum matching, we will always
- // find a match in this step and the performance will be identical to the
- // greedy algorithm.
- for (int i = 0; i < count2_; ++i) {
- int matched = (*match_list2_)[i];
- if (matched == -1 && Match(v, i)) {
- (*match_list2_)[i] = v;
- return true;
- }
- }
- // Then we try those already matched nodes and see if we can find an
- // alternaive match for the node matched to them.
- // The greedy algorithm will stop before this and fail to produce the
- // correct result.
- for (int i = 0; i < count2_; ++i) {
- int matched = (*match_list2_)[i];
- if (matched != -1 && Match(v, i)) {
- if (!(*visited)[matched] && FindArgumentPathDFS(matched, visited)) {
- (*match_list2_)[i] = v;
- return true;
- }
- }
- }
- return false;
- }
- } // namespace
- bool MessageDifferencer::MatchRepeatedFieldIndices(
- const Message& message1,
- const Message& message2,
- const FieldDescriptor* repeated_field,
- const std::vector<SpecificField>& parent_fields,
- std::vector<int>* match_list1,
- std::vector<int>* match_list2) {
- const int count1 =
- message1.GetReflection()->FieldSize(message1, repeated_field);
- const int count2 =
- message2.GetReflection()->FieldSize(message2, repeated_field);
- const MapKeyComparator* key_comparator = GetMapKeyComparator(repeated_field);
- match_list1->assign(count1, -1);
- match_list2->assign(count2, -1);
- bool success = true;
- // Find potential match if this is a special repeated field.
- if (key_comparator != NULL || IsTreatedAsSet(repeated_field)) {
- if (scope_ == PARTIAL) {
- // When partial matching is enabled, Compare(a, b) && Compare(a, c)
- // doesn't necessarily imply Compare(b, c). Therefore a naive greedy
- // algorithm will fail to find a maximum matching.
- // Here we use the argumenting path algorithm.
- MaximumMatcher::NodeMatchCallback* callback =
- ::google::protobuf::NewPermanentCallback(
- this, &MessageDifferencer::IsMatch,
- repeated_field, key_comparator,
- &message1, &message2, parent_fields);
- MaximumMatcher matcher(count1, count2, callback, match_list1,
- match_list2);
- // If diff info is not needed, we should end the matching process as
- // soon as possible if not all items can be matched.
- bool early_return = (reporter_ == NULL);
- int match_count = matcher.FindMaximumMatch(early_return);
- if (match_count != count1 && reporter_ == NULL) return false;
- success = success && (match_count == count1);
- } else {
- int start_offset = 0;
- // If the two repeated fields are treated as sets, optimize for the case
- // where both start with same items stored in the same order.
- if (IsTreatedAsSet(repeated_field)) {
- start_offset = std::min(count1, count2);
- for (int i = 0; i < count1 && i < count2; i++) {
- if (IsMatch(repeated_field, key_comparator, &message1, &message2,
- parent_fields, i, i)) {
- match_list1->at(i) = i;
- match_list2->at(i) = i;
- } else {
- start_offset = i;
- break;
- }
- }
- }
- for (int i = start_offset; i < count1; ++i) {
- // Indicates any matched elements for this repeated field.
- bool match = false;
- for (int j = start_offset; j < count2; j++) {
- if (match_list2->at(j) != -1) continue;
- match = IsMatch(repeated_field, key_comparator,
- &message1, &message2, parent_fields, i, j);
- if (match) {
- match_list1->at(i) = j;
- match_list2->at(j) = i;
- break;
- }
- }
- if (!match && reporter_ == NULL) return false;
- success = success && match;
- }
- }
- } else {
- // If this field should be treated as list, just label the match_list.
- for (int i = 0; i < count1 && i < count2; i++) {
- match_list1->at(i) = i;
- match_list2->at(i) = i;
- }
- }
- return success;
- }
- FieldComparator::ComparisonResult MessageDifferencer::GetFieldComparisonResult(
- const Message& message1, const Message& message2,
- const FieldDescriptor* field, int index1, int index2,
- const FieldContext* field_context) {
- FieldComparator* comparator = field_comparator_ != NULL ?
- field_comparator_ : &default_field_comparator_;
- return comparator->Compare(message1, message2, field,
- index1, index2, field_context);
- }
- // ===========================================================================
- MessageDifferencer::Reporter::Reporter() { }
- MessageDifferencer::Reporter::~Reporter() {}
- // ===========================================================================
- MessageDifferencer::MapKeyComparator::MapKeyComparator() {}
- MessageDifferencer::MapKeyComparator::~MapKeyComparator() {}
- // ===========================================================================
- MessageDifferencer::IgnoreCriteria::IgnoreCriteria() {}
- MessageDifferencer::IgnoreCriteria::~IgnoreCriteria() {}
- // ===========================================================================
- // Note that the printer's delimiter is not used, because if we are given a
- // printer, we don't know its delimiter.
- MessageDifferencer::StreamReporter::StreamReporter(
- io::ZeroCopyOutputStream* output) : printer_(new io::Printer(output, '$')),
- delete_printer_(true),
- report_modified_aggregates_(false) { }
- MessageDifferencer::StreamReporter::StreamReporter(
- io::Printer* printer) : printer_(printer),
- delete_printer_(false),
- report_modified_aggregates_(false) { }
- MessageDifferencer::StreamReporter::~StreamReporter() {
- if (delete_printer_) delete printer_;
- }
- void MessageDifferencer::StreamReporter::PrintPath(
- const std::vector<SpecificField>& field_path, bool left_side) {
- for (int i = 0; i < field_path.size(); ++i) {
- if (i > 0) {
- printer_->Print(".");
- }
- SpecificField specific_field = field_path[i];
- if (specific_field.field != NULL) {
- if (specific_field.field->is_extension()) {
- printer_->Print("($name$)", "name",
- specific_field.field->full_name());
- } else {
- printer_->PrintRaw(specific_field.field->name());
- }
- if (specific_field.field->is_map()) {
- // Don't print index in a map field; they are semantically unordered.
- continue;
- }
- } else {
- printer_->PrintRaw(SimpleItoa(specific_field.unknown_field_number));
- }
- if (left_side && specific_field.index >= 0) {
- printer_->Print("[$name$]", "name", SimpleItoa(specific_field.index));
- }
- if (!left_side && specific_field.new_index >= 0) {
- printer_->Print("[$name$]", "name", SimpleItoa(specific_field.new_index));
- }
- }
- }
- 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,
- bool left_side) {
- const SpecificField& specific_field = field_path.back();
- const FieldDescriptor* field = specific_field.field;
- if (field != NULL) {
- string output;
- int index = left_side ? specific_field.index : specific_field.new_index;
- if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
- const Reflection* reflection = message.GetReflection();
- const Message& field_message = field->is_repeated() ?
- reflection->GetRepeatedMessage(message, field, index) :
- reflection->GetMessage(message, field);
- output = field_message.ShortDebugString();
- if (output.empty()) {
- printer_->Print("{ }");
- } else {
- printer_->Print("{ $name$ }", "name", output);
- }
- } else {
- TextFormat::PrintFieldValueToString(message, field, index, &output);
- printer_->PrintRaw(output);
- }
- } else {
- const UnknownFieldSet* unknown_fields =
- (left_side ?
- specific_field.unknown_field_set1 :
- specific_field.unknown_field_set2);
- const UnknownField* unknown_field = &unknown_fields->field(
- left_side ?
- specific_field.unknown_field_index1 :
- specific_field.unknown_field_index2);
- PrintUnknownFieldValue(unknown_field);
- }
- }
- void MessageDifferencer::
- StreamReporter::PrintUnknownFieldValue(const UnknownField* unknown_field) {
- GOOGLE_CHECK(unknown_field != NULL) << " Cannot print NULL unknown_field.";
- string output;
- switch (unknown_field->type()) {
- case UnknownField::TYPE_VARINT:
- output = SimpleItoa(unknown_field->varint());
- break;
- case UnknownField::TYPE_FIXED32:
- output = StrCat("0x", strings::Hex(unknown_field->fixed32(),
- strings::ZERO_PAD_8));
- break;
- case UnknownField::TYPE_FIXED64:
- output = StrCat("0x", strings::Hex(unknown_field->fixed64(),
- strings::ZERO_PAD_16));
- break;
- case UnknownField::TYPE_LENGTH_DELIMITED:
- output = StringPrintf("\"%s\"",
- CEscape(unknown_field->length_delimited()).c_str());
- break;
- case UnknownField::TYPE_GROUP:
- // TODO(kenton): Print the contents of the group like we do for
- // messages. Requires an equivalent of ShortDebugString() for
- // UnknownFieldSet.
- output = "{ ... }";
- break;
- }
- printer_->PrintRaw(output);
- }
- void MessageDifferencer::StreamReporter::Print(const string& str) {
- printer_->Print(str.c_str());
- }
- void MessageDifferencer::StreamReporter::ReportAdded(
- const Message& message1,
- const Message& message2,
- const std::vector<SpecificField>& field_path) {
- printer_->Print("added: ");
- PrintPath(field_path, false, message2);
- printer_->Print(": ");
- PrintValue(message2, field_path, false);
- printer_->Print("\n"); // Print for newlines.
- }
- void MessageDifferencer::StreamReporter::ReportDeleted(
- const Message& message1,
- const Message& message2,
- const std::vector<SpecificField>& field_path) {
- printer_->Print("deleted: ");
- PrintPath(field_path, true, message1);
- printer_->Print(": ");
- PrintValue(message1, field_path, true);
- printer_->Print("\n"); // Print for newlines
- }
- void MessageDifferencer::StreamReporter::ReportModified(
- const Message& message1,
- const Message& message2,
- const std::vector<SpecificField>& field_path) {
- if (!report_modified_aggregates_ && field_path.back().field == NULL) {
- if (field_path.back().unknown_field_type == UnknownField::TYPE_GROUP) {
- // Any changes to the subfields have already been printed.
- return;
- }
- } else if (!report_modified_aggregates_) {
- if (field_path.back().field->cpp_type() ==
- FieldDescriptor::CPPTYPE_MESSAGE) {
- // Any changes to the subfields have already been printed.
- return;
- }
- }
- printer_->Print("modified: ");
- PrintPath(field_path, true, message1);
- if (CheckPathChanged(field_path)) {
- printer_->Print(" -> ");
- PrintPath(field_path, false, message2);
- }
- printer_->Print(": ");
- PrintValue(message1, field_path, true);
- printer_->Print(" -> ");
- PrintValue(message2, field_path, false);
- printer_->Print("\n"); // Print for newlines.
- }
- void MessageDifferencer::StreamReporter::ReportMoved(
- const Message& message1,
- const Message& message2,
- const std::vector<SpecificField>& field_path) {
- printer_->Print("moved: ");
- PrintPath(field_path, true, message1);
- printer_->Print(" -> ");
- PrintPath(field_path, false, message2);
- printer_->Print(" : ");
- PrintValue(message1, field_path, true);
- printer_->Print("\n"); // Print for newlines.
- }
- void MessageDifferencer::StreamReporter::ReportMatched(
- const Message& message1,
- const Message& message2,
- const std::vector<SpecificField>& field_path) {
- printer_->Print("matched: ");
- PrintPath(field_path, true, message1);
- if (CheckPathChanged(field_path)) {
- printer_->Print(" -> ");
- PrintPath(field_path, false, message2);
- }
- printer_->Print(" : ");
- PrintValue(message1, field_path, true);
- printer_->Print("\n"); // Print for newlines.
- }
- void MessageDifferencer::StreamReporter::ReportIgnored(
- const Message& message1,
- const Message& message2,
- const std::vector<SpecificField>& field_path) {
- printer_->Print("ignored: ");
- PrintPath(field_path, true, message1);
- if (CheckPathChanged(field_path)) {
- printer_->Print(" -> ");
- PrintPath(field_path, false, message2);
- }
- printer_->Print("\n"); // Print for newlines.
- }
- void MessageDifferencer::StreamReporter::ReportUnknownFieldIgnored(
- const Message& message1, const Message& message2,
- const std::vector<SpecificField>& field_path) {
- printer_->Print("ignored: ");
- PrintPath(field_path, true, message1);
- if (CheckPathChanged(field_path)) {
- printer_->Print(" -> ");
- PrintPath(field_path, false, message2);
- }
- printer_->Print("\n"); // Print for newlines.
- }
- MessageDifferencer::MapKeyComparator*
- MessageDifferencer::CreateMultipleFieldsMapKeyComparator(
- const std::vector<std::vector<const FieldDescriptor*> >& key_field_paths) {
- return new MultipleFieldsMapKeyComparator(this, key_field_paths);
- }
- } // namespace util
- } // namespace protobuf
- } // namespace google
|