diff options
Diffstat (limited to 'src/google/protobuf/util/message_differencer.h')
-rw-r--r-- | src/google/protobuf/util/message_differencer.h | 216 |
1 files changed, 131 insertions, 85 deletions
diff --git a/src/google/protobuf/util/message_differencer.h b/src/google/protobuf/util/message_differencer.h index 3ea74e67..bbcf8498 100644 --- a/src/google/protobuf/util/message_differencer.h +++ b/src/google/protobuf/util/message_differencer.h @@ -64,6 +64,7 @@ class Printer; namespace util { +class DefaultFieldComparator; class FieldContext; // declared below MessageDifferencer // A basic differencer that can be used to determine @@ -174,10 +175,8 @@ class LIBPROTOBUF_EXPORT MessageDifferencer { // If "field" is a repeated field which is being treated as a map or // a set (see TreatAsMap() and TreatAsSet(), below), new_index indicates - // the index the position to which the element has moved. This only - // applies to ReportMoved() and (in the case of TreatAsMap()) - // ReportModified(). In all other cases, "new_index" will have the same - // value as "index". + // the index the position to which the element has moved. If the element + // has not moved, "new_index" will have the same value as "index". int new_index; // For unknown fields, these are the pointers to the UnknownFieldSet @@ -221,19 +220,19 @@ class LIBPROTOBUF_EXPORT MessageDifferencer { // Reports that a field has been added into Message2. virtual void ReportAdded( const Message& message1, const Message& message2, - const vector<SpecificField>& field_path) = 0; + const std::vector<SpecificField>& field_path) = 0; // Reports that a field has been deleted from Message1. virtual void ReportDeleted( const Message& message1, const Message& message2, - const vector<SpecificField>& field_path) = 0; + const std::vector<SpecificField>& field_path) = 0; // Reports that the value of a field has been modified. virtual void ReportModified( const Message& message1, const Message& message2, - const vector<SpecificField>& field_path) = 0; + const std::vector<SpecificField>& field_path) = 0; // Reports that a repeated field has been moved to another location. This // only applies when using TreatAsSet or TreatAsMap() -- see below. Also @@ -241,18 +240,18 @@ class LIBPROTOBUF_EXPORT MessageDifferencer { // mutually exclusive. If a field has been both moved and modified, then // only ReportModified will be called. virtual void ReportMoved( - const Message& message1, - const Message& message2, - const vector<SpecificField>& field_path) { } + const Message& /* message1 */, + const Message& /* message2 */, + const std::vector<SpecificField>& /* field_path */) { } // Reports that two fields match. Useful for doing side-by-side diffs. // This function is mutually exclusive with ReportModified and ReportMoved. // Note that you must call set_report_matches(true) before calling Compare // to make use of this function. virtual void ReportMatched( - const Message& message1, - const Message& message2, - const vector<SpecificField>& field_path) { } + const Message& /* message1 */, + const Message& /* message2 */, + const std::vector<SpecificField>& /* field_path */) { } // Reports that two fields would have been compared, but the // comparison has been skipped because the field was marked as @@ -274,16 +273,16 @@ class LIBPROTOBUF_EXPORT MessageDifferencer { // the fields are equal or not (perhaps with a second call to // Compare()), if it cares. virtual void ReportIgnored( - const Message& message1, - const Message& message2, - const vector<SpecificField>& field_path) { } + const Message& /* message1 */, + const Message& /* message2 */, + const std::vector<SpecificField>& /* field_path */) { } - // Report that an unkown field is ignored. (see comment above). + // Report that an unknown field is ignored. (see comment above). // Note this is a different function since the last SpecificField in field // path has a null field. This could break existing Reporter. virtual void ReportUnknownFieldIgnored( - const Message& message1, const Message& message2, - const vector<SpecificField>& field_path) {} + const Message& /* message1 */, const Message& /* message2 */, + const std::vector<SpecificField>& /* field_path */) {} private: GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Reporter); @@ -296,9 +295,10 @@ class LIBPROTOBUF_EXPORT MessageDifferencer { MapKeyComparator(); virtual ~MapKeyComparator(); - virtual bool IsMatch(const Message& message1, - const Message& message2, - const vector<SpecificField>& parent_fields) const { + virtual bool IsMatch( + const Message& /* message1 */, + const Message& /* message2 */, + const std::vector<SpecificField>& /* parent_fields */) const { GOOGLE_CHECK(false) << "IsMatch() is not implemented."; return false; } @@ -320,18 +320,18 @@ class LIBPROTOBUF_EXPORT MessageDifferencer { // Returns true if the field should be ignored. virtual bool IsIgnored( - const Message& message1, - const Message& message2, - const FieldDescriptor* field, - const vector<SpecificField>& parent_fields) = 0; + const Message& /* message1 */, + const Message& /* message2 */, + const FieldDescriptor* /* field */, + const std::vector<SpecificField>& /* parent_fields */) = 0; // Returns true if the unknown field should be ignored. // Note: This will be called for unknown fields as well in which case // field.field will be null. virtual bool IsUnknownFieldIgnored( - const Message& message1, const Message& message2, - const SpecificField& field, - const vector<SpecificField>& parent_fields) { + const Message& /* message1 */, const Message& /* message2 */, + const SpecificField& /* field */, + const std::vector<SpecificField>& /* parent_fields */) { return false; } }; @@ -371,7 +371,7 @@ class LIBPROTOBUF_EXPORT MessageDifferencer { // repeated fields have different numbers of elements, the // unpaired elements are reported using ReportAdded() or // ReportDeleted(). - AS_SET, // Treat all the repeated fields as sets by default. + AS_SET, // Treat all the repeated fields as sets. // See TreatAsSet(), as below. }; @@ -385,6 +385,11 @@ class LIBPROTOBUF_EXPORT MessageDifferencer { // the only differences between the compared messages is that some fields // have been moved, then the comparison returns true. // + // Note that despite the name of this method, this is really + // comparison as multisets: if one side of the comparison has a duplicate + // in the repeated field but the other side doesn't, this will count as + // a mismatch. + // // If the scope of comparison is set to PARTIAL, then in addition to what's // above, extra values added to repeated fields of the second message will // not cause the comparison to fail. @@ -440,7 +445,7 @@ class LIBPROTOBUF_EXPORT MessageDifferencer { // size of each element. void TreatAsMapWithMultipleFieldsAsKey( const FieldDescriptor* field, - const vector<const FieldDescriptor*>& key_fields); + const std::vector<const FieldDescriptor*>& key_fields); // Same as TreatAsMapWithMultipleFieldsAsKey, except that each of the field // do not necessarily need to be a direct subfield. Each element in // key_field_paths indicate a path from the message being compared, listing @@ -456,7 +461,7 @@ class LIBPROTOBUF_EXPORT MessageDifferencer { // !key_field_path[i]->is_repeated() void TreatAsMapWithMultipleFieldPathsAsKey( const FieldDescriptor* field, - const vector<vector<const FieldDescriptor*> >& key_field_paths); + const std::vector<std::vector<const FieldDescriptor*> >& key_field_paths); // Uses a custom MapKeyComparator to determine if two elements have the same // key when comparing a repeated field as a map. @@ -469,6 +474,10 @@ class LIBPROTOBUF_EXPORT MessageDifferencer { const FieldDescriptor* field, const MapKeyComparator* key_comparator); + // Initiates and returns a new instance of MultipleFieldsMapKeyComparator. + MapKeyComparator* CreateMultipleFieldsMapKeyComparator( + const std::vector<std::vector<const FieldDescriptor*> >& key_field_paths); + // Add a custom ignore criteria that is evaluated in addition to the // ignored fields added with IgnoreField. // Takes ownership of ignore_criteria. @@ -517,6 +526,13 @@ class LIBPROTOBUF_EXPORT MessageDifferencer { report_matches_ = report_matches; } + // Tells the differencer whether or not to report moves (in a set or map + // repeated field). This method must be called before Compare. The default for + // a new differencer is true. + void set_report_moves(bool report_moves) { + report_moves_ = report_moves; + } + // Sets the scope of the comparison (as defined in the Scope enumeration // above) that is used by this differencer when determining which fields to // compare between the messages. @@ -549,9 +565,10 @@ class LIBPROTOBUF_EXPORT MessageDifferencer { // Same as above, except comparing only the list of fields specified by the // two vectors of FieldDescriptors. - bool CompareWithFields(const Message& message1, const Message& message2, - const vector<const FieldDescriptor*>& message1_fields, - const vector<const FieldDescriptor*>& message2_fields); + bool CompareWithFields( + const Message& message1, const Message& message2, + const std::vector<const FieldDescriptor*>& message1_fields, + const std::vector<const FieldDescriptor*>& message2_fields); // Automatically creates a reporter that will output the differences // found (if any) to the specified output string pointer. Note that this @@ -570,6 +587,12 @@ class LIBPROTOBUF_EXPORT MessageDifferencer { // any differences found in human-readable form to the supplied // ZeroCopyOutputStream or Printer. If a printer is used, the delimiter // *must* be '$'. + // + // WARNING: this reporter does not necessarily flush its output until it is + // destroyed. As a result, it is not safe to assume the output is valid or + // complete until after you destroy the reporter. For example, if you use a + // StreamReporter to write to a StringOutputStream, the target string may + // contain uninitialized data until the reporter is destroyed. class LIBPROTOBUF_EXPORT StreamReporter : public Reporter { public: explicit StreamReporter(io::ZeroCopyOutputStream* output); @@ -585,35 +608,40 @@ class LIBPROTOBUF_EXPORT MessageDifferencer { // The following are implementations of the methods described above. virtual void ReportAdded(const Message& message1, const Message& message2, - const vector<SpecificField>& field_path); + const std::vector<SpecificField>& field_path); virtual void ReportDeleted(const Message& message1, const Message& message2, - const vector<SpecificField>& field_path); + const std::vector<SpecificField>& field_path); virtual void ReportModified(const Message& message1, const Message& message2, - const vector<SpecificField>& field_path); + const std::vector<SpecificField>& field_path); virtual void ReportMoved(const Message& message1, const Message& message2, - const vector<SpecificField>& field_path); + const std::vector<SpecificField>& field_path); virtual void ReportMatched(const Message& message1, const Message& message2, - const vector<SpecificField>& field_path); + const std::vector<SpecificField>& field_path); virtual void ReportIgnored(const Message& message1, const Message& message2, - const vector<SpecificField>& field_path); + const std::vector<SpecificField>& field_path); virtual void ReportUnknownFieldIgnored( const Message& message1, const Message& message2, - const vector<SpecificField>& field_path); + const std::vector<SpecificField>& field_path); protected: + // Prints the specified path of fields to the buffer. message is used to + // print map keys. + virtual void PrintPath(const std::vector<SpecificField>& field_path, + bool left_side, const Message& message); + // Prints the specified path of fields to the buffer. - virtual void PrintPath(const vector<SpecificField>& field_path, + virtual void PrintPath(const std::vector<SpecificField>& field_path, bool left_side); // Prints the value of fields to the buffer. left_side is true if the @@ -622,7 +650,7 @@ class LIBPROTOBUF_EXPORT MessageDifferencer { // unknown_field_index1 or unknown_field_index2 when an unknown field // is encountered in field_path. virtual void PrintValue(const Message& message, - const vector<SpecificField>& field_path, + const std::vector<SpecificField>& field_path, bool left_side); // Prints the specified path of unknown fields to the buffer. @@ -640,11 +668,25 @@ class LIBPROTOBUF_EXPORT MessageDifferencer { }; private: + friend class DefaultFieldComparator; + // A MapKeyComparator to be used in TreatAsMapUsingKeyComparator. // Implementation of this class needs to do field value comparison which // relies on some private methods of MessageDifferencer. That's why this // class is declared as a nested class of MessageDifferencer. class MultipleFieldsMapKeyComparator; + + // A MapKeyComparator for use with map_entries. + class LIBPROTOBUF_EXPORT MapEntryKeyComparator : public MapKeyComparator { + public: + explicit MapEntryKeyComparator(MessageDifferencer* message_differencer); + virtual bool IsMatch(const Message& message1, const Message& message2, + const std::vector<SpecificField>& parent_fields) const; + + private: + MessageDifferencer* message_differencer_; + }; + // Returns true if field1's number() is less than field2's. static bool FieldBefore(const FieldDescriptor* field1, const FieldDescriptor* field2); @@ -653,11 +695,11 @@ class LIBPROTOBUF_EXPORT MessageDifferencer { // All fields present in both lists will always be included in the combined // list. Fields only present in one of the lists will only appear in the // combined list if the corresponding fields_scope option is set to FULL. - void CombineFields(const vector<const FieldDescriptor*>& fields1, + void CombineFields(const std::vector<const FieldDescriptor*>& fields1, Scope fields1_scope, - const vector<const FieldDescriptor*>& fields2, + const std::vector<const FieldDescriptor*>& fields2, Scope fields2_scope, - vector<const FieldDescriptor*>* combined_fields); + std::vector<const FieldDescriptor*>* combined_fields); // Internal version of the Compare method which performs the actual // comparison. The parent_fields vector is a vector containing field @@ -665,34 +707,34 @@ class LIBPROTOBUF_EXPORT MessageDifferencer { // (i.e. if the current message is an embedded message, the parent_fields // vector will contain the field that has this embedded message). bool Compare(const Message& message1, const Message& message2, - vector<SpecificField>* parent_fields); + std::vector<SpecificField>* parent_fields); // Compares all the unknown fields in two messages. bool CompareUnknownFields(const Message& message1, const Message& message2, const google::protobuf::UnknownFieldSet&, const google::protobuf::UnknownFieldSet&, - vector<SpecificField>* parent_fields); + std::vector<SpecificField>* parent_fields); // Compares the specified messages for the requested field lists. The field // lists are modified depending on comparison settings, and then passed to // CompareWithFieldsInternal. bool CompareRequestedFieldsUsingSettings( const Message& message1, const Message& message2, - const vector<const FieldDescriptor*>& message1_fields, - const vector<const FieldDescriptor*>& message2_fields, - vector<SpecificField>* parent_fields); + const std::vector<const FieldDescriptor*>& message1_fields, + const std::vector<const FieldDescriptor*>& message2_fields, + std::vector<SpecificField>* parent_fields); // Compares the specified messages with the specified field lists. bool CompareWithFieldsInternal( const Message& message1, const Message& message2, - const vector<const FieldDescriptor*>& message1_fields, - const vector<const FieldDescriptor*>& message2_fields, - vector<SpecificField>* parent_fields); + const std::vector<const FieldDescriptor*>& message1_fields, + const std::vector<const FieldDescriptor*>& message2_fields, + std::vector<SpecificField>* parent_fields); // Compares the repeated fields, and report the error. bool CompareRepeatedField(const Message& message1, const Message& message2, const FieldDescriptor* field, - vector<SpecificField>* parent_fields); + std::vector<SpecificField>* parent_fields); // Shorthand for CompareFieldValueUsingParentFields with NULL parent_fields. bool CompareFieldValue(const Message& message1, @@ -710,12 +752,13 @@ class LIBPROTOBUF_EXPORT MessageDifferencer { // list of parent messages if it needs to recursively compare the given field. // To avoid confusing users you should not set it to NULL unless you modified // Reporter to handle the change of parent_fields correctly. - bool CompareFieldValueUsingParentFields(const Message& message1, - const Message& message2, - const FieldDescriptor* field, - int index1, - int index2, - vector<SpecificField>* parent_fields); + bool CompareFieldValueUsingParentFields( + const Message& message1, + const Message& message2, + const FieldDescriptor* field, + int index1, + int index2, + std::vector<SpecificField>* parent_fields); // Compares the specified field on the two messages, returning comparison // result, as returned by appropriate FieldComparator. @@ -730,7 +773,7 @@ class LIBPROTOBUF_EXPORT MessageDifferencer { bool IsMatch(const FieldDescriptor* repeated_field, const MapKeyComparator* key_comparator, const Message* message1, const Message* message2, - const vector<SpecificField>& parent_fields, + const std::vector<SpecificField>& parent_fields, int index1, int index2); // Returns true when this repeated field has been configured to be treated @@ -748,17 +791,18 @@ class LIBPROTOBUF_EXPORT MessageDifferencer { const Message& message1, const Message& message2, const FieldDescriptor* field, - const vector<SpecificField>& parent_fields); + const std::vector<SpecificField>& parent_fields); // Returns true if this unknown field is to be ignored when this // MessageDifferencer compares messages. bool IsUnknownFieldIgnored(const Message& message1, const Message& message2, const SpecificField& field, - const vector<SpecificField>& parent_fields); + const std::vector<SpecificField>& parent_fields); - // Returns MapKeyComparator* when this field has been configured to - // be treated as a map. If not, returns NULL. - const MapKeyComparator* GetMapKeyComparator(const FieldDescriptor* field); + // Returns MapKeyComparator* when this field has been configured to be treated + // as a map or its is_map() return true. If not, returns NULL. + const MapKeyComparator* GetMapKeyComparator( + const FieldDescriptor* field) const; // Attempts to match indices of a repeated field, so that the contained values // match. Clears output vectors and sets their values to indices of paired @@ -767,28 +811,29 @@ class LIBPROTOBUF_EXPORT MessageDifferencer { // This method returns false if the match failed. However, it doesn't mean // that the comparison succeeds when this method returns true (you need to // double-check in this case). - bool MatchRepeatedFieldIndices(const Message& message1, - const Message& message2, - const FieldDescriptor* repeated_field, - const vector<SpecificField>& parent_fields, - vector<int>* match_list1, - vector<int>* match_list2); + bool 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); // If "any" is of type google.protobuf.Any, extract its payload using // DynamicMessageFactory and store in "data". - bool UnpackAny(const Message& any, google::protobuf::scoped_ptr<Message>* data); + bool UnpackAny(const Message& any, std::unique_ptr<Message>* data); // Checks if index is equal to new_index in all the specific fields. - static bool CheckPathChanged(const vector<SpecificField>& parent_fields); + static bool CheckPathChanged(const std::vector<SpecificField>& parent_fields); // Defines a map between field descriptors and their MapKeyComparators. // Used for repeated fields when they are configured as TreatAsMap. - typedef map<const FieldDescriptor*, + typedef std::map<const FieldDescriptor*, const MapKeyComparator*> FieldKeyComparatorMap; // Defines a set to store field descriptors. Used for repeated fields when // they are configured as TreatAsSet. - typedef set<const FieldDescriptor*> FieldSet; + typedef std::set<const FieldDescriptor*> FieldSet; Reporter* reporter_; DefaultFieldComparator default_field_comparator_; @@ -805,18 +850,19 @@ class LIBPROTOBUF_EXPORT MessageDifferencer { // When TreatAsMap or TreatAsMapWithMultipleFieldsAsKey is called, we don't // store the supplied FieldDescriptors directly. Instead, a new // MapKeyComparator is created for comparison purpose. - vector<MapKeyComparator*> owned_key_comparators_; + std::vector<MapKeyComparator*> owned_key_comparators_; FieldKeyComparatorMap map_field_key_comparator_; - vector<IgnoreCriteria*> ignore_criteria_; + MapEntryKeyComparator map_entry_key_comparator_; + std::vector<IgnoreCriteria*> ignore_criteria_; FieldSet ignored_fields_; - bool compare_unknown_fields_; bool report_matches_; + bool report_moves_; string* output_string_; - google::protobuf::scoped_ptr<DynamicMessageFactory> dynamic_message_factory_; + std::unique_ptr<DynamicMessageFactory> dynamic_message_factory_; GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageDifferencer); }; @@ -825,15 +871,15 @@ class LIBPROTOBUF_EXPORT MessageDifferencer { class LIBPROTOBUF_EXPORT FieldContext { public: explicit FieldContext( - vector<MessageDifferencer::SpecificField>* parent_fields) + std::vector<MessageDifferencer::SpecificField>* parent_fields) : parent_fields_(parent_fields) {} - vector<MessageDifferencer::SpecificField>* parent_fields() const { + std::vector<MessageDifferencer::SpecificField>* parent_fields() const { return parent_fields_; } private: - vector<MessageDifferencer::SpecificField>* parent_fields_; + std::vector<MessageDifferencer::SpecificField>* parent_fields_; }; } |