|
|
|||
File indexing completed on 2026-10-02 09:07:06
0001 // Protocol Buffers - Google's data interchange format 0002 // Copyright 2008 Google Inc. All rights reserved. 0003 // 0004 // Use of this source code is governed by a BSD-style 0005 // license that can be found in the LICENSE file or at 0006 // https://developers.google.com/open-source/licenses/bsd 0007 0008 // Author: jschorr@google.com (Joseph Schorr) 0009 // Based on original Protocol Buffers design by 0010 // Sanjay Ghemawat, Jeff Dean, and others. 0011 // 0012 // This file defines static methods and classes for comparing Protocol 0013 // Messages. 0014 // 0015 // Aug. 2008: Added Unknown Fields Comparison for messages. 0016 // Aug. 2009: Added different options to compare repeated fields. 0017 // Apr. 2010: Moved field comparison to FieldComparator 0018 // Sep. 2020: Added option to output map keys in path 0019 0020 #ifndef GOOGLE_PROTOBUF_UTIL_MESSAGE_DIFFERENCER_H__ 0021 #define GOOGLE_PROTOBUF_UTIL_MESSAGE_DIFFERENCER_H__ 0022 0023 #include <functional> 0024 #include <memory> 0025 #include <string> 0026 #include <vector> 0027 0028 #include "absl/base/macros.h" 0029 #include "absl/container/fixed_array.h" 0030 #include "absl/container/flat_hash_map.h" 0031 #include "absl/container/flat_hash_set.h" 0032 #include "absl/log/absl_check.h" 0033 #include "google/protobuf/descriptor.h" // FieldDescriptor 0034 #include "google/protobuf/message.h" // Message 0035 #include "google/protobuf/text_format.h" 0036 #include "google/protobuf/unknown_field_set.h" 0037 #include "google/protobuf/util/field_comparator.h" 0038 0039 // Always include as last one, otherwise it can break compilation 0040 #include "google/protobuf/port_def.inc" 0041 0042 namespace google { 0043 namespace protobuf { 0044 0045 class DynamicMessageFactory; 0046 class FieldDescriptor; 0047 0048 namespace io { 0049 class ZeroCopyOutputStream; 0050 class Printer; 0051 } // namespace io 0052 0053 namespace util { 0054 0055 class DefaultFieldComparator; 0056 class FieldContext; // declared below MessageDifferencer 0057 0058 // A basic differencer that can be used to determine 0059 // the differences between two specified Protocol Messages. If any differences 0060 // are found, the Compare method will return false, and any differencer reporter 0061 // specified via ReportDifferencesTo will have its reporting methods called (see 0062 // below for implementation of the report). Based off of the original 0063 // ProtocolDifferencer implementation in //net/proto/protocol-differencer.h 0064 // (Thanks Todd!). 0065 // 0066 // MessageDifferencer REQUIRES that compared messages be the same type, defined 0067 // as messages that share the same descriptor. If not, the behavior of this 0068 // class is undefined. 0069 // 0070 // People disagree on what MessageDifferencer should do when asked to compare 0071 // messages with different descriptors. Some people think it should always 0072 // return false. Others expect it to try to look for similar fields and 0073 // compare them anyway -- especially if the descriptors happen to be identical. 0074 // If we chose either of these behaviors, some set of people would find it 0075 // surprising, and could end up writing code expecting the other behavior 0076 // without realizing their error. Therefore, we forbid that usage. 0077 // 0078 // This class is implemented based on the proto2 reflection. The performance 0079 // should be good enough for normal usages. However, for places where the 0080 // performance is extremely sensitive, there are several alternatives: 0081 // - Comparing serialized string 0082 // Downside: false negatives (there are messages that are the same but their 0083 // serialized strings are different). 0084 // - Equals code generator by compiler plugin (net/proto2/contrib/equals_plugin) 0085 // Downside: more generated code; maintenance overhead for the additional rule 0086 // (must be in sync with the original proto_library). 0087 // 0088 // Note on handling of google.protobuf.Any: MessageDifferencer automatically 0089 // unpacks Any::value into a Message and compares its individual fields. 0090 // Messages encoded in a repeated Any cannot be compared using TreatAsMap. 0091 // 0092 // Note on thread-safety: MessageDifferencer is *not* thread-safe. You need to 0093 // guard it with a lock to use the same MessageDifferencer instance from 0094 // multiple threads. Note that it's fine to call static comparison methods 0095 // (like MessageDifferencer::Equals) concurrently, but it's not recommended for 0096 // performance critical code as it leads to extra allocations. 0097 class PROTOBUF_EXPORT MessageDifferencer { 0098 public: 0099 // Determines whether the supplied messages are equal. Equality is defined as 0100 // all fields within the two messages being set to the same value. Primitive 0101 // fields and strings are compared by value while embedded messages/groups 0102 // are compared as if via a recursive call. Use Compare() with IgnoreField() 0103 // if some fields should be ignored in the comparison. Use Compare() with 0104 // TreatAsSet() if there are repeated fields where ordering does not matter. 0105 // 0106 // This method REQUIRES that the two messages have the same 0107 // Descriptor (message1.GetDescriptor() == message2.GetDescriptor()). 0108 static bool Equals(const Message& message1, const Message& message2); 0109 0110 // Determines whether the supplied messages are equivalent. Equivalency is 0111 // defined as all fields within the two messages having the same value. This 0112 // differs from the Equals method above in that fields with default values 0113 // are considered set to said value automatically. For details on how default 0114 // values are defined for each field type, see: 0115 // https://developers.google.com/protocol-buffers/docs/proto?csw=1#optional. 0116 // Also, Equivalent() ignores unknown fields. Use IgnoreField() and Compare() 0117 // if some fields should be ignored in the comparison. 0118 // 0119 // This method REQUIRES that the two messages have the same 0120 // Descriptor (message1.GetDescriptor() == message2.GetDescriptor()). 0121 static bool Equivalent(const Message& message1, const Message& message2); 0122 0123 // Determines whether the supplied messages are approximately equal. 0124 // Approximate equality is defined as all fields within the two messages 0125 // being approximately equal. Primitive (non-float) fields and strings are 0126 // compared by value, floats are compared using MathUtil::AlmostEquals() and 0127 // embedded messages/groups are compared as if via a recursive call. Use 0128 // IgnoreField() and Compare() if some fields should be ignored in the 0129 // comparison. 0130 // 0131 // This method REQUIRES that the two messages have the same 0132 // Descriptor (message1.GetDescriptor() == message2.GetDescriptor()). 0133 static bool ApproximatelyEquals(const Message& message1, 0134 const Message& message2); 0135 0136 // Determines whether the supplied messages are approximately equivalent. 0137 // Approximate equivalency is defined as all fields within the two messages 0138 // being approximately equivalent. As in 0139 // MessageDifferencer::ApproximatelyEquals, primitive (non-float) fields and 0140 // strings are compared by value, floats are compared using 0141 // MathUtil::AlmostEquals() and embedded messages/groups are compared as if 0142 // via a recursive call. However, fields with default values are considered 0143 // set to said value, as per MessageDiffencer::Equivalent. Use IgnoreField() 0144 // and Compare() if some fields should be ignored in the comparison. 0145 // 0146 // This method REQUIRES that the two messages have the same 0147 // Descriptor (message1.GetDescriptor() == message2.GetDescriptor()). 0148 static bool ApproximatelyEquivalent(const Message& message1, 0149 const Message& message2); 0150 0151 // Identifies an individual field in a message instance. Used for field_path, 0152 // below. 0153 struct SpecificField { 0154 // The messages that contain this field. They are always set. They are valid 0155 // only during a call to Reporter::Report* methods. 0156 // 0157 // If the original messages are of type google.protobuf.Any, these fields 0158 // will store the unpacked payloads, and unpacked_any will become > 0. More 0159 // precisely, unpacked_any defines the nesting level of Any. For example, 0160 // if the original message packs another Any, then unpacked_any=2, assuming 0161 // the differencer unpacked both of them. 0162 // 0163 // When an Any object packs a non-Any proto object whose field includes 0164 // Any, then unpacked_any=1. Thus, in most practical applications, 0165 // unpacked_any will be 0 or 1. 0166 const Message* message1 = nullptr; 0167 const Message* message2 = nullptr; 0168 int unpacked_any = 0; 0169 0170 // For known fields, "field" is filled in and "unknown_field_number" is -1. 0171 // For unknown fields, "field" is NULL, "unknown_field_number" is the field 0172 // number, and "unknown_field_type" is its type. 0173 const FieldDescriptor* field = nullptr; 0174 int unknown_field_number = -1; 0175 UnknownField::Type unknown_field_type = UnknownField::Type::TYPE_VARINT; 0176 0177 // If this a repeated field, "index" is the index within it. For unknown 0178 // fields, this is the index of the field among all unknown fields of the 0179 // same field number and type. 0180 int index = -1; 0181 0182 // If "field" is a repeated field which is being treated as a map or 0183 // a set (see TreatAsMap() and TreatAsSet(), below), new_index indicates 0184 // the index the position to which the element has moved. If the element 0185 // has not moved, "new_index" will have the same value as "index". 0186 int new_index = -1; 0187 0188 // If "field" is a map field, point to the map entry. 0189 const Message* map_entry1 = nullptr; 0190 const Message* map_entry2 = nullptr; 0191 0192 // For unknown fields, these are the pointers to the UnknownFieldSet 0193 // containing the unknown fields. In certain cases (e.g. proto1's 0194 // MessageSet, or nested groups of unknown fields), these may differ from 0195 // the messages' internal UnknownFieldSets. 0196 const UnknownFieldSet* unknown_field_set1 = nullptr; 0197 const UnknownFieldSet* unknown_field_set2 = nullptr; 0198 0199 // For unknown fields, these are the index of the field within the 0200 // UnknownFieldSets. One or the other will be -1 when 0201 // reporting an addition or deletion. 0202 int unknown_field_index1 = -1; 0203 int unknown_field_index2 = -1; 0204 0205 // Was this field added to the diffing because set_force_compare_no_presence 0206 // was called on the MessageDifferencer object. 0207 bool forced_compare_no_presence_ = false; 0208 }; 0209 0210 // Abstract base class from which all MessageDifferencer 0211 // reporters derive. The five Report* methods below will be called when 0212 // a field has been added, deleted, modified, moved, or matched. The third 0213 // argument is a vector of FieldDescriptor pointers which describes the chain 0214 // of fields that was taken to find the current field. For example, for a 0215 // field found in an embedded message, the vector will contain two 0216 // FieldDescriptors. The first will be the field of the embedded message 0217 // itself and the second will be the actual field in the embedded message 0218 // that was added/deleted/modified. 0219 // Fields will be reported in PostTraversalOrder. 0220 // For example, given following proto, if both baz and mooo are changed. 0221 // foo { 0222 // bar { 0223 // baz: 1 0224 // mooo: 2 0225 // } 0226 // } 0227 // ReportModified will be invoked with following order: 0228 // 1. foo.bar.baz or foo.bar.mooo 0229 // 2. foo.bar.mooo or foo.bar.baz 0230 // 2. foo.bar 0231 // 3. foo 0232 class PROTOBUF_EXPORT Reporter { 0233 public: 0234 Reporter(); 0235 Reporter(const Reporter&) = delete; 0236 Reporter& operator=(const Reporter&) = delete; 0237 virtual ~Reporter(); 0238 0239 // Reports that a field has been added into Message2. 0240 virtual void ReportAdded(const Message& message1, const Message& message2, 0241 const std::vector<SpecificField>& field_path) {} 0242 0243 // Reports that a field has been deleted from Message1. 0244 virtual void ReportDeleted(const Message& message1, const Message& message2, 0245 const std::vector<SpecificField>& field_path) {} 0246 0247 // Reports that the value of a field has been modified. 0248 virtual void ReportModified(const Message& message1, 0249 const Message& message2, 0250 const std::vector<SpecificField>& field_path) {} 0251 0252 // Reports that a repeated field has been moved to another location. This 0253 // only applies when using TreatAsSet or TreatAsMap() -- see below. Also 0254 // note that for any given field, ReportModified and ReportMoved are 0255 // mutually exclusive. If a field has been both moved and modified, then 0256 // only ReportModified will be called. 0257 virtual void ReportMoved( 0258 const Message& /* message1 */, const Message& /* message2 */, 0259 const std::vector<SpecificField>& /* field_path */) {} 0260 0261 // Reports that two fields match. Useful for doing side-by-side diffs. 0262 // This function is mutually exclusive with ReportModified and ReportMoved. 0263 // Note that you must call set_report_matches(true) before calling Compare 0264 // to make use of this function. 0265 virtual void ReportMatched( 0266 const Message& /* message1 */, const Message& /* message2 */, 0267 const std::vector<SpecificField>& /* field_path */) {} 0268 0269 // Reports that two fields would have been compared, but the 0270 // comparison has been skipped because the field was marked as 0271 // 'ignored' using IgnoreField(). This function is mutually 0272 // exclusive with all the other Report() functions. 0273 // 0274 // The contract of ReportIgnored is slightly different than the 0275 // other Report() functions, in that |field_path.back().index| is 0276 // always equal to -1, even if the last field is repeated. This is 0277 // because while the other Report() functions indicate where in a 0278 // repeated field the action (Addition, Deletion, etc...) 0279 // happened, when a repeated field is 'ignored', the differencer 0280 // simply calls ReportIgnored on the repeated field as a whole and 0281 // moves on without looking at its individual elements. 0282 // 0283 // Furthermore, ReportIgnored() does not indicate whether the 0284 // fields were in fact equal or not, as Compare() does not inspect 0285 // these fields at all. It is up to the Reporter to decide whether 0286 // the fields are equal or not (perhaps with a second call to 0287 // Compare()), if it cares. 0288 virtual void ReportIgnored( 0289 const Message& /* message1 */, const Message& /* message2 */, 0290 const std::vector<SpecificField>& /* field_path */) {} 0291 0292 // Report that an unknown field is ignored. (see comment above). 0293 // Note this is a different function since the last SpecificField in field 0294 // path has a null field. This could break existing Reporter. 0295 virtual void ReportUnknownFieldIgnored( 0296 const Message& /* message1 */, const Message& /* message2 */, 0297 const std::vector<SpecificField>& /* field_path */) {} 0298 }; 0299 0300 // MapKeyComparator is used to determine if two elements have the same key 0301 // when comparing elements of a repeated field as a map. 0302 class PROTOBUF_EXPORT MapKeyComparator { 0303 public: 0304 MapKeyComparator(); 0305 MapKeyComparator(const MapKeyComparator&) = delete; 0306 MapKeyComparator& operator=(const MapKeyComparator&) = delete; 0307 virtual ~MapKeyComparator(); 0308 0309 // This method should be overridden by every implementation. The arg 0310 // unmapped_any is nonzero the original messages provided by the user are of 0311 // type google.protobuf.Any. 0312 // 0313 // More precisely, unpacked_any defines the nesting level of Any. For 0314 // example, if Any packs another Any then unpacked_any=2, assuming the 0315 // patcher unpacked both. Note that when an Any object packs a non-Any 0316 // proto object whose field includes Any, then unpacked_any=1. Thus, in most 0317 // practical applications, unpacked_any will be 0 or 1. 0318 virtual bool IsMatch(const Message& message1, const Message& message2, 0319 int /* unmapped_any */, 0320 const std::vector<SpecificField>& fields) const { 0321 ABSL_CHECK(false) << "IsMatch() is not implemented."; 0322 return false; 0323 } 0324 }; 0325 0326 // Abstract base class from which all IgnoreCriteria derive. 0327 // By adding IgnoreCriteria more complex ignore logic can be implemented. 0328 // IgnoreCriteria are registered with AddIgnoreCriteria. For each compared 0329 // field IsIgnored is called on each added IgnoreCriteria until one returns 0330 // true or all return false. 0331 // IsIgnored is called for fields where at least one side has a value. 0332 class PROTOBUF_EXPORT IgnoreCriteria { 0333 public: 0334 IgnoreCriteria(); 0335 virtual ~IgnoreCriteria(); 0336 0337 // Returns true if the field should be ignored. 0338 virtual bool IsIgnored( 0339 const Message& /* message1 */, const Message& /* message2 */, 0340 const FieldDescriptor* /* field */, 0341 const std::vector<SpecificField>& /* parent_fields */) = 0; 0342 0343 // Returns true if the unknown field should be ignored. 0344 // Note: This will be called for unknown fields as well in which case 0345 // field.field will be null. 0346 virtual bool IsUnknownFieldIgnored( 0347 const Message& /* message1 */, const Message& /* message2 */, 0348 const SpecificField& /* field */, 0349 const std::vector<SpecificField>& /* parent_fields */) { 0350 return false; 0351 } 0352 }; 0353 0354 // To add a Reporter, construct default here, then use ReportDifferencesTo or 0355 // ReportDifferencesToString. 0356 explicit MessageDifferencer(); 0357 MessageDifferencer(const MessageDifferencer&) = delete; 0358 MessageDifferencer& operator=(const MessageDifferencer&) = delete; 0359 0360 ~MessageDifferencer(); 0361 0362 enum MessageFieldComparison { 0363 EQUAL, // Fields must be present in both messages 0364 // for the messages to be considered the same. 0365 EQUIVALENT, // Fields with default values are considered set 0366 // for comparison purposes even if not explicitly 0367 // set in the messages themselves. Unknown fields 0368 // are ignored. 0369 }; 0370 0371 enum Scope { 0372 FULL, // All fields of both messages are considered in the comparison. 0373 PARTIAL // Only fields present in the first message are considered; fields 0374 // set only in the second message will be skipped during 0375 // comparison. 0376 }; 0377 0378 // DEPRECATED. Use FieldComparator::FloatComparison instead. 0379 enum FloatComparison { 0380 EXACT, // Floats and doubles are compared exactly. 0381 APPROXIMATE // Floats and doubles are compared using the 0382 // MathUtil::AlmostEquals method. 0383 }; 0384 0385 enum RepeatedFieldComparison { 0386 AS_LIST, // Repeated fields are compared in order. Differing values at 0387 // the same index are reported using ReportModified(). If the 0388 // repeated fields have different numbers of elements, the 0389 // unpaired elements are reported using ReportAdded() or 0390 // ReportDeleted(). 0391 AS_SET, // Treat all the repeated fields as sets. 0392 // See TreatAsSet(), as below. 0393 AS_SMART_LIST, // Similar to AS_SET, but preserve the order and find the 0394 // longest matching sequence from the first matching 0395 // element. To use an optimal solution, call 0396 // SetMatchIndicesForSmartListCallback() to pass it in. 0397 AS_SMART_SET, // Similar to AS_SET, but match elements with fewest diffs. 0398 }; 0399 0400 // The elements of the given repeated field will be treated as a set for 0401 // diffing purposes, so different orderings of the same elements will be 0402 // considered equal. Elements which are present on both sides of the 0403 // comparison but which have changed position will be reported with 0404 // ReportMoved(). Elements which only exist on one side or the other are 0405 // reported with ReportAdded() and ReportDeleted() regardless of their 0406 // positions. ReportModified() is never used for this repeated field. If 0407 // the only differences between the compared messages is that some fields 0408 // have been moved, then the comparison returns true. 0409 // 0410 // Note that despite the name of this method, this is really 0411 // comparison as multisets: if one side of the comparison has a duplicate 0412 // in the repeated field but the other side doesn't, this will count as 0413 // a mismatch. 0414 // 0415 // If the scope of comparison is set to PARTIAL, then in addition to what's 0416 // above, extra values added to repeated fields of the second message will 0417 // not cause the comparison to fail. 0418 // 0419 // Note that set comparison is currently O(k * n^2) (where n is the total 0420 // number of elements, and k is the average size of each element). In theory 0421 // it could be made O(n * k) with a more complex hashing implementation. Feel 0422 // free to contribute one if the current implementation is too slow for you. 0423 // If partial matching is also enabled, the time complexity will be O(k * n^2 0424 // + n^3) in which n^3 is the time complexity of the maximum matching 0425 // algorithm. 0426 // 0427 // REQUIRES: field->is_repeated() and field not registered with TreatAsMap* 0428 void TreatAsSet(const FieldDescriptor* field); 0429 void TreatAsSmartSet(const FieldDescriptor* field); 0430 0431 // The elements of the given repeated field will be treated as a list for 0432 // diffing purposes, so different orderings of the same elements will NOT be 0433 // considered equal. 0434 // 0435 // REQUIRES: field->is_repeated() and field not registered with TreatAsMap* 0436 void TreatAsList(const FieldDescriptor* field); 0437 // Note that the complexity is similar to treating as SET. 0438 void TreatAsSmartList(const FieldDescriptor* field); 0439 0440 // The elements of the given repeated field will be treated as a map for 0441 // diffing purposes, with |key| being the map key. Thus, elements with the 0442 // same key will be compared even if they do not appear at the same index. 0443 // Differences are reported similarly to TreatAsSet(), except that 0444 // ReportModified() is used to report elements with the same key but 0445 // different values. Note that if an element is both moved and modified, 0446 // only ReportModified() will be called. As with TreatAsSet, if the only 0447 // differences between the compared messages is that some fields have been 0448 // moved, then the comparison returns true. See TreatAsSet for notes on 0449 // performance. 0450 // 0451 // REQUIRES: field->is_repeated() 0452 // REQUIRES: field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE 0453 // REQUIRES: key->containing_type() == field->message_type() 0454 void TreatAsMap(const FieldDescriptor* field, const FieldDescriptor* key); 0455 // Same as TreatAsMap except that this method will use multiple fields as 0456 // the key in comparison. All specified fields in 'key_fields' should be 0457 // present in the compared elements. Two elements will be treated as having 0458 // the same key iff they have the same value for every specified field. There 0459 // are two steps in the comparison process. The first one is key matching. 0460 // Every element from one message will be compared to every element from 0461 // the other message. Only fields in 'key_fields' are compared in this step 0462 // to decide if two elements have the same key. The second step is value 0463 // comparison. Those pairs of elements with the same key (with equal value 0464 // for every field in 'key_fields') will be compared in this step. 0465 // Time complexity of the first step is O(s * m * n ^ 2) where s is the 0466 // average size of the fields specified in 'key_fields', m is the number of 0467 // fields in 'key_fields' and n is the number of elements. If partial 0468 // matching is enabled, an extra O(n^3) will be incured by the maximum 0469 // matching algorithm. The second step is O(k * n) where k is the average 0470 // size of each element. 0471 void TreatAsMapWithMultipleFieldsAsKey( 0472 const FieldDescriptor* field, 0473 const std::vector<const FieldDescriptor*>& key_fields); 0474 // Same as TreatAsMapWithMultipleFieldsAsKey, except that each of the field 0475 // do not necessarily need to be a direct subfield. Each element in 0476 // key_field_paths indicate a path from the message being compared, listing 0477 // successive subfield to reach the key field. 0478 // 0479 // REQUIRES: 0480 // for key_field_path in key_field_paths: 0481 // key_field_path[0]->containing_type() == field->message_type() 0482 // for i in [0, key_field_path.size() - 1): 0483 // key_field_path[i+1]->containing_type() == 0484 // key_field_path[i]->message_type() 0485 // key_field_path[i]->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE 0486 // !key_field_path[i]->is_repeated() 0487 void TreatAsMapWithMultipleFieldPathsAsKey( 0488 const FieldDescriptor* field, 0489 const std::vector<std::vector<const FieldDescriptor*> >& key_field_paths); 0490 0491 // Uses a custom MapKeyComparator to determine if two elements have the same 0492 // key when comparing a repeated field as a map. 0493 // The caller is responsible to delete the key_comparator. 0494 // This method varies from TreatAsMapWithMultipleFieldsAsKey only in the 0495 // first key matching step. Rather than comparing some specified fields, it 0496 // will invoke the IsMatch method of the given 'key_comparator' to decide if 0497 // two elements have the same key. 0498 void TreatAsMapUsingKeyComparator(const FieldDescriptor* field, 0499 const MapKeyComparator* key_comparator); 0500 0501 // Initiates and returns a new instance of MultipleFieldsMapKeyComparator. 0502 MapKeyComparator* CreateMultipleFieldsMapKeyComparator( 0503 const std::vector<std::vector<const FieldDescriptor*> >& key_field_paths); 0504 0505 // Add a custom ignore criteria that is evaluated in addition to the 0506 // ignored fields added with IgnoreField. 0507 #ifndef PROTOBUF_FUTURE_REMOVE_ADD_IGNORE_CRITERIA 0508 ABSL_DEPRECATE_AND_INLINE() 0509 void AddIgnoreCriteria(IgnoreCriteria* ignore_criteria) { 0510 AddIgnoreCriteria(absl::WrapUnique(ignore_criteria)); 0511 } 0512 #endif // !PROTOBUF_FUTURE_REMOVE_ADD_IGNORE_CRITERIA 0513 0514 void AddIgnoreCriteria(std::unique_ptr<IgnoreCriteria> ignore_criteria); 0515 0516 // Indicates that any field with the given descriptor should be 0517 // ignored for the purposes of comparing two messages. This applies 0518 // to fields nested in the message structure as well as top level 0519 // ones. When the MessageDifferencer encounters an ignored field, 0520 // ReportIgnored is called on the reporter, if one is specified. 0521 // 0522 // The only place where the field's 'ignored' status is not applied is when 0523 // it is being used as a key in a field passed to TreatAsMap or is one of 0524 // the fields passed to TreatAsMapWithMultipleFieldsAsKey. 0525 // In this case it is compared in key matching but after that it's ignored 0526 // in value comparison. 0527 void IgnoreField(const FieldDescriptor* field); 0528 0529 // Sets the field comparator used to determine differences between protocol 0530 // buffer fields. By default it's set to a DefaultFieldComparator instance. 0531 // MessageDifferencer doesn't take ownership over the passed object. 0532 // Note that this method must be called before Compare for the comparator to 0533 // be used. 0534 void set_field_comparator(FieldComparator* comparator); 0535 void set_field_comparator(DefaultFieldComparator* comparator); 0536 0537 // DEPRECATED. Pass a DefaultFieldComparator instance instead. 0538 // Sets the fraction and margin for the float comparison of a given field. 0539 // Uses MathUtil::WithinFractionOrMargin to compare the values. 0540 // NOTE: this method does nothing if differencer's field comparator has been 0541 // set to a custom object. 0542 // 0543 // REQUIRES: field->cpp_type == FieldDescriptor::CPPTYPE_DOUBLE or 0544 // field->cpp_type == FieldDescriptor::CPPTYPE_FLOAT 0545 // REQUIRES: float_comparison_ == APPROXIMATE 0546 void SetFractionAndMargin(const FieldDescriptor* field, double fraction, 0547 double margin); 0548 0549 // Sets the type of comparison (as defined in the MessageFieldComparison 0550 // enumeration above) that is used by this differencer when determining how 0551 // to compare fields in messages. 0552 void set_message_field_comparison(MessageFieldComparison comparison); 0553 0554 // Returns the current message field comparison used in this differencer. 0555 MessageFieldComparison message_field_comparison() const; 0556 0557 // Tells the differencer whether or not to report matches. This method must 0558 // be called before Compare. The default for a new differencer is false. 0559 void set_report_matches(bool report_matches) { 0560 report_matches_ = report_matches; 0561 } 0562 0563 // Tells the differencer whether or not to report moves (in a set or map 0564 // repeated field). This method must be called before Compare. The default for 0565 // a new differencer is true. 0566 void set_report_moves(bool report_moves) { report_moves_ = report_moves; } 0567 0568 // Tells the differencer whether or not to report ignored values. This method 0569 // must be called before Compare. The default for a new differencer is true. 0570 void set_report_ignores(bool report_ignores) { 0571 report_ignores_ = report_ignores; 0572 } 0573 0574 // Sets the scope of the comparison (as defined in the Scope enumeration 0575 // above) that is used by this differencer when determining which fields to 0576 // compare between the messages. 0577 void set_scope(Scope scope); 0578 0579 // Returns the current scope used by this differencer. 0580 Scope scope() const; 0581 0582 // Only affects PARTIAL diffing. When set, all non-repeated no-presence fields 0583 // which are set to their default value (which is the same as being unset) in 0584 // message1 but are set to a non-default value in message2 will also be used 0585 // in the comparison. 0586 void set_force_compare_no_presence(bool value); 0587 0588 // If set, the fields in message1 that equal the fields passed here will be 0589 // treated as required for comparison, even if they are absent. 0590 void set_require_no_presence_fields( 0591 const google::protobuf::TextFormat::Parser::UnsetFieldsMetadata& fields) { 0592 require_no_presence_fields_ = fields; 0593 } 0594 0595 // DEPRECATED. Pass a DefaultFieldComparator instance instead. 0596 // Sets the type of comparison (as defined in the FloatComparison enumeration 0597 // above) that is used by this differencer when comparing float (and double) 0598 // fields in messages. 0599 // NOTE: this method does nothing if differencer's field comparator has been 0600 // set to a custom object. 0601 void set_float_comparison(FloatComparison comparison); 0602 0603 // Sets the type of comparison for repeated field (as defined in the 0604 // RepeatedFieldComparison enumeration above) that is used by this 0605 // differencer when compare repeated fields in messages. 0606 void set_repeated_field_comparison(RepeatedFieldComparison comparison); 0607 0608 // Returns the current repeated field comparison used by this differencer. 0609 RepeatedFieldComparison repeated_field_comparison() const; 0610 0611 // Compares the two specified messages, returning true if they are the same, 0612 // false otherwise. If this method returns false, any changes between the 0613 // two messages will be reported if a Reporter was specified via 0614 // ReportDifferencesTo (see also ReportDifferencesToString). 0615 // 0616 // This method REQUIRES that the two messages have the same 0617 // Descriptor (message1.GetDescriptor() == message2.GetDescriptor()). 0618 bool Compare(const Message& message1, const Message& message2); 0619 0620 // Same as above, except comparing only the list of fields specified by the 0621 // two vectors of FieldDescriptors. 0622 bool CompareWithFields( 0623 const Message& message1, const Message& message2, 0624 const std::vector<const FieldDescriptor*>& message1_fields, 0625 const std::vector<const FieldDescriptor*>& message2_fields); 0626 0627 // Automatically creates a reporter that will output the differences 0628 // found (if any) to the specified output string pointer. Note that this 0629 // method must be called before Compare. 0630 void ReportDifferencesToString(std::string* output); 0631 0632 // Tells the MessageDifferencer to report differences via the specified 0633 // reporter. Note that this method must be called before Compare for 0634 // the reporter to be used. It is the responsibility of the caller to delete 0635 // this object. 0636 // If the provided pointer equals NULL, the MessageDifferencer stops reporting 0637 // differences to any previously set reporters or output strings. 0638 void ReportDifferencesTo(Reporter* reporter); 0639 0640 // Returns the list of fields which was automatically added to the list of 0641 // compared fields by calling set_force_compare_no_presence and caused the 0642 // last call to Compare to fail. 0643 const absl::flat_hash_set<std::string>& NoPresenceFieldsCausingFailure() { 0644 return force_compare_failure_triggering_fields_; 0645 } 0646 0647 private: 0648 // Class for processing Any deserialization. This logic is used by both the 0649 // MessageDifferencer and StreamReporter classes. 0650 class UnpackAnyField { 0651 private: 0652 std::unique_ptr<DynamicMessageFactory> dynamic_message_factory_; 0653 0654 public: 0655 UnpackAnyField() = default; 0656 ~UnpackAnyField() = default; 0657 // If "any" is of type google.protobuf.Any, extract its payload using 0658 // DynamicMessageFactory and store in "data". 0659 bool UnpackAny(const Message& any, std::unique_ptr<Message>* data); 0660 }; 0661 0662 public: 0663 // An implementation of the MessageDifferencer Reporter that outputs 0664 // any differences found in human-readable form to the supplied 0665 // ZeroCopyOutputStream or Printer. If a printer is used, the delimiter 0666 // *must* be '$'. 0667 // 0668 // WARNING: this reporter does not necessarily flush its output until it is 0669 // destroyed. As a result, it is not safe to assume the output is valid or 0670 // complete until after you destroy the reporter. For example, if you use a 0671 // StreamReporter to write to a StringOutputStream, the target string may 0672 // contain uninitialized data until the reporter is destroyed. 0673 class PROTOBUF_EXPORT StreamReporter : public Reporter { 0674 public: 0675 explicit StreamReporter(io::ZeroCopyOutputStream* output); 0676 explicit StreamReporter(io::Printer* printer); // delimiter '$' 0677 StreamReporter(const StreamReporter&) = delete; 0678 StreamReporter& operator=(const StreamReporter&) = delete; 0679 ~StreamReporter() override; 0680 0681 // When set to true, the stream reporter will also output aggregates nodes 0682 // (i.e. messages and groups) whose subfields have been modified. When 0683 // false, will only report the individual subfields. Defaults to false. 0684 void set_report_modified_aggregates(bool report) { 0685 report_modified_aggregates_ = report; 0686 } 0687 0688 // The following are implementations of the methods described above. 0689 0690 void ReportAdded(const Message& message1, const Message& message2, 0691 const std::vector<SpecificField>& field_path) override; 0692 0693 void ReportDeleted(const Message& message1, const Message& message2, 0694 const std::vector<SpecificField>& field_path) override; 0695 0696 void ReportModified(const Message& message1, const Message& message2, 0697 const std::vector<SpecificField>& field_path) override; 0698 0699 void ReportMoved(const Message& message1, const Message& message2, 0700 const std::vector<SpecificField>& field_path) override; 0701 0702 void ReportMatched(const Message& message1, const Message& message2, 0703 const std::vector<SpecificField>& field_path) override; 0704 0705 void ReportIgnored(const Message& message1, const Message& message2, 0706 const std::vector<SpecificField>& field_path) override; 0707 0708 void ReportUnknownFieldIgnored( 0709 const Message& message1, const Message& message2, 0710 const std::vector<SpecificField>& field_path) override; 0711 0712 // Messages that are being compared must be provided to StreamReporter prior 0713 // to processing 0714 void SetMessages(const Message& message1, const Message& message2); 0715 0716 protected: 0717 // Prints the specified path of fields to the buffer. 0718 virtual void PrintPath(const std::vector<SpecificField>& field_path, 0719 bool left_side); 0720 0721 // Prints the value of fields to the buffer. left_side is true if the 0722 // given message is from the left side of the comparison, false if it 0723 // was the right. This is relevant only to decide whether to follow 0724 // unknown_field_index1 or unknown_field_index2 when an unknown field 0725 // is encountered in field_path. 0726 virtual void PrintValue(const Message& message, 0727 const std::vector<SpecificField>& field_path, 0728 bool left_side); 0729 0730 // Prints the specified path of unknown fields to the buffer. 0731 virtual void PrintUnknownFieldValue(const UnknownField* unknown_field); 0732 0733 // Just print a string 0734 void Print(const std::string& str); 0735 0736 private: 0737 // helper function for PrintPath that contains logic for printing maps 0738 void PrintMapKey(bool left_side, const SpecificField& specific_field); 0739 0740 io::Printer* printer_; 0741 bool delete_printer_; 0742 bool report_modified_aggregates_; 0743 const Message* message1_; 0744 const Message* message2_; 0745 }; 0746 0747 private: 0748 friend class SimpleFieldComparator; 0749 0750 // A MapKeyComparator to be used in TreatAsMapUsingKeyComparator. 0751 // Implementation of this class needs to do field value comparison which 0752 // relies on some private methods of MessageDifferencer. That's why this 0753 // class is declared as a nested class of MessageDifferencer. 0754 class MultipleFieldsMapKeyComparator; 0755 0756 // A MapKeyComparator for use with map_entries. 0757 class PROTOBUF_EXPORT MapEntryKeyComparator : public MapKeyComparator { 0758 public: 0759 explicit MapEntryKeyComparator(MessageDifferencer* message_differencer); 0760 bool IsMatch( 0761 const Message& message1, const Message& message2, int unpacked_any, 0762 const std::vector<SpecificField>& parent_fields) const override; 0763 0764 private: 0765 MessageDifferencer* message_differencer_; 0766 }; 0767 0768 // Returns true if field1's number() is less than field2's. 0769 static bool FieldBefore(const FieldDescriptor* field1, 0770 const FieldDescriptor* field2); 0771 0772 // Retrieve all the set fields, including extensions. 0773 std::vector<const FieldDescriptor*> RetrieveFields(const Message& message, 0774 bool base_message); 0775 0776 // Combine the two lists of fields into the combined_fields output vector. 0777 // All fields present in both lists will always be included in the combined 0778 // list. Fields only present in one of the lists will only appear in the 0779 // combined list if the corresponding fields_scope option is set to FULL. 0780 std::vector<const FieldDescriptor*> CombineFields( 0781 const Message& message1, 0782 const std::vector<const FieldDescriptor*>& fields1, Scope fields1_scope, 0783 const std::vector<const FieldDescriptor*>& fields2, Scope fields2_scope); 0784 0785 // Internal version of the Compare method which performs the actual 0786 // comparison. The parent_fields vector is a vector containing field 0787 // descriptors of all fields accessed to get to this comparison operation 0788 // (i.e. if the current message is an embedded message, the parent_fields 0789 // vector will contain the field that has this embedded message). 0790 bool Compare(const Message& message1, const Message& message2, 0791 int unpacked_any, std::vector<SpecificField>* parent_fields); 0792 0793 // Compares all the unknown fields in two messages. 0794 bool CompareUnknownFields(const Message& message1, const Message& message2, 0795 const UnknownFieldSet&, const UnknownFieldSet&, 0796 std::vector<SpecificField>* parent_fields); 0797 0798 // Compares the specified messages for the requested field lists. The field 0799 // lists are modified depending on comparison settings, and then passed to 0800 // CompareWithFieldsInternal. 0801 bool CompareRequestedFieldsUsingSettings( 0802 const Message& message1, const Message& message2, int unpacked_any, 0803 const std::vector<const FieldDescriptor*>& message1_fields, 0804 const std::vector<const FieldDescriptor*>& message2_fields, 0805 std::vector<SpecificField>* parent_fields); 0806 0807 // Compares the specified messages with the specified field lists. 0808 bool CompareWithFieldsInternal( 0809 const Message& message1, const Message& message2, int unpacked_any, 0810 const std::vector<const FieldDescriptor*>& message1_fields, 0811 const std::vector<const FieldDescriptor*>& message2_fields, 0812 std::vector<SpecificField>* parent_fields); 0813 0814 // Compares the repeated fields, and report the error. 0815 bool CompareRepeatedField(const Message& message1, const Message& message2, 0816 int unpacked_any, const FieldDescriptor* field, 0817 std::vector<SpecificField>* parent_fields); 0818 0819 // Compares map fields, and report the error. 0820 bool CompareMapField(const Message& message1, const Message& message2, 0821 int unpacked_any, const FieldDescriptor* field, 0822 std::vector<SpecificField>* parent_fields); 0823 0824 // Helper for CompareRepeatedField and CompareMapField: compares and reports 0825 // differences element-wise. This is the implementation for non-map fields, 0826 // and can also compare map fields by using the underlying representation. 0827 bool CompareRepeatedRep(const Message& message1, const Message& message2, 0828 int unpacked_any, const FieldDescriptor* field, 0829 std::vector<SpecificField>* parent_fields); 0830 0831 // Helper for CompareMapField: compare the map fields using map reflection 0832 // instead of sync to repeated. 0833 bool CompareMapFieldByMapReflection(const Message& message1, 0834 const Message& message2, int unpacked_any, 0835 const FieldDescriptor* field, 0836 std::vector<SpecificField>* parent_fields, 0837 DefaultFieldComparator* comparator); 0838 0839 // Shorthand for CompareFieldValueUsingParentFields with NULL parent_fields. 0840 bool CompareFieldValue(const Message& message1, const Message& message2, 0841 int unpacked_any, const FieldDescriptor* field, 0842 int index1, int index2); 0843 0844 // Compares the specified field on the two messages, returning 0845 // true if they are the same, false otherwise. For repeated fields, 0846 // this method only compares the value in the specified index. This method 0847 // uses Compare functions to recurse into submessages. 0848 // The parent_fields vector is used in calls to a Reporter instance calls. 0849 // It can be NULL, in which case the MessageDifferencer will create new 0850 // list of parent messages if it needs to recursively compare the given field. 0851 // To avoid confusing users you should not set it to NULL unless you modified 0852 // Reporter to handle the change of parent_fields correctly. 0853 bool CompareFieldValueUsingParentFields( 0854 const Message& message1, const Message& message2, int unpacked_any, 0855 const FieldDescriptor* field, int index1, int index2, 0856 std::vector<SpecificField>* parent_fields); 0857 0858 // Compares the specified field on the two messages, returning comparison 0859 // result, as returned by appropriate FieldComparator. 0860 FieldComparator::ComparisonResult GetFieldComparisonResult( 0861 const Message& message1, const Message& message2, 0862 const FieldDescriptor* field, int index1, int index2, 0863 const FieldContext* field_context); 0864 0865 // Check if the two elements in the repeated field are match to each other. 0866 // if the key_comprator is NULL, this function returns true when the two 0867 // elements are equal. 0868 bool IsMatch(const FieldDescriptor* repeated_field, 0869 const MapKeyComparator* key_comparator, const Message* message1, 0870 const Message* message2, int unpacked_any, 0871 const std::vector<SpecificField>& parent_fields, 0872 Reporter* reporter, int index1, int index2); 0873 0874 // Returns true when this repeated field has been configured to be treated 0875 // as a Set / SmartSet / SmartList. 0876 bool IsTreatedAsSet(const FieldDescriptor* field); 0877 bool IsTreatedAsSmartSet(const FieldDescriptor* field); 0878 0879 bool IsTreatedAsSmartList(const FieldDescriptor* field); 0880 // When treating as SMART_LIST, it uses MatchIndicesPostProcessorForSmartList 0881 // by default to find the longest matching sequence from the first matching 0882 // element. The callback takes two vectors showing the matching indices from 0883 // the other vector, where -1 means an unmatch. 0884 void SetMatchIndicesForSmartListCallback( 0885 std::function<void(std::vector<int>*, std::vector<int>*)> callback); 0886 0887 // Returns true when this repeated field is to be compared as a subset, ie. 0888 // has been configured to be treated as a set or map and scope is set to 0889 // PARTIAL. 0890 bool IsTreatedAsSubset(const FieldDescriptor* field); 0891 0892 // Returns true if this field is to be ignored when this 0893 // MessageDifferencer compares messages. 0894 bool IsIgnored(const Message& message1, const Message& message2, 0895 const FieldDescriptor* field, 0896 const std::vector<SpecificField>& parent_fields); 0897 0898 // Returns true if this unknown field is to be ignored when this 0899 // MessageDifferencer compares messages. 0900 bool IsUnknownFieldIgnored(const Message& message1, const Message& message2, 0901 const SpecificField& field, 0902 const std::vector<SpecificField>& parent_fields); 0903 0904 // Returns MapKeyComparator* when this field has been configured to be treated 0905 // as a map or its is_map() return true. If not, returns NULL. 0906 const MapKeyComparator* GetMapKeyComparator( 0907 const FieldDescriptor* field) const; 0908 0909 // Attempts to match indices of a repeated field, so that the contained values 0910 // match. Clears output vectors and sets their values to indices of paired 0911 // messages, ie. if message1[0] matches message2[1], then match_list1[0] == 1 0912 // and match_list2[1] == 0. The unmatched indices are indicated by -1. 0913 // Assumes the repeated field is not treated as a simple list. 0914 // This method returns false if the match failed. However, it doesn't mean 0915 // that the comparison succeeds when this method returns true (you need to 0916 // double-check in this case). 0917 bool MatchRepeatedFieldIndices( 0918 const Message& message1, const Message& message2, int unpacked_any, 0919 const FieldDescriptor* repeated_field, 0920 const MapKeyComparator* key_comparator, 0921 const std::vector<SpecificField>& parent_fields, 0922 std::vector<int>* match_list1, std::vector<int>* match_list2); 0923 0924 // Checks if index is equal to new_index in all the specific fields. 0925 static bool CheckPathChanged(const std::vector<SpecificField>& parent_fields); 0926 0927 // ABSL_CHECKs that the given repeated field can be compared according to 0928 // new_comparison. 0929 void CheckRepeatedFieldComparisons( 0930 const FieldDescriptor* field, 0931 const RepeatedFieldComparison& new_comparison); 0932 0933 // Whether we should still compare the field despite its absence in message1. 0934 bool ShouldCompareNoPresence(const Message& message1, 0935 const Reflection& reflection1, 0936 const FieldDescriptor* field2) const; 0937 0938 // We move this code out of line to reduce stack cost of the caller. 0939 // The map lookups and string copies are costly in stack space. 0940 PROTOBUF_NOINLINE void ForceCompareField(const FieldDescriptor* field); 0941 0942 Reporter* reporter_; 0943 DefaultFieldComparator default_field_comparator_; 0944 MessageFieldComparison message_field_comparison_; 0945 Scope scope_; 0946 absl::flat_hash_set<const FieldDescriptor*> force_compare_no_presence_fields_; 0947 google::protobuf::TextFormat::Parser::UnsetFieldsMetadata require_no_presence_fields_; 0948 absl::flat_hash_set<std::string> force_compare_failure_triggering_fields_; 0949 RepeatedFieldComparison repeated_field_comparison_; 0950 0951 absl::flat_hash_map<const FieldDescriptor*, RepeatedFieldComparison> 0952 repeated_field_comparisons_; 0953 // Keeps track of MapKeyComparators that are created within 0954 // MessageDifferencer. These MapKeyComparators should be deleted 0955 // before MessageDifferencer is destroyed. 0956 // When TreatAsMap or TreatAsMapWithMultipleFieldsAsKey is called, we don't 0957 // store the supplied FieldDescriptors directly. Instead, a new 0958 // MapKeyComparator is created for comparison purpose. 0959 std::vector<MapKeyComparator*> owned_key_comparators_; 0960 absl::flat_hash_map<const FieldDescriptor*, const MapKeyComparator*> 0961 map_field_key_comparator_; 0962 MapEntryKeyComparator map_entry_key_comparator_; 0963 std::vector<std::unique_ptr<IgnoreCriteria>> ignore_criteria_; 0964 // Reused multiple times in RetrieveFields to avoid extra allocations 0965 std::vector<const FieldDescriptor*> tmp_message_fields_; 0966 0967 absl::flat_hash_set<const FieldDescriptor*> ignored_fields_; 0968 0969 union { 0970 DefaultFieldComparator* default_impl; 0971 FieldComparator* base; 0972 } field_comparator_ = {&default_field_comparator_}; 0973 enum { kFCDefault, kFCBase } field_comparator_kind_ = kFCDefault; 0974 0975 bool report_matches_; 0976 bool report_moves_; 0977 bool report_ignores_; 0978 bool force_compare_no_presence_ = false; 0979 0980 std::string* output_string_; 0981 0982 // Callback to post-process the matched indices to support SMART_LIST. 0983 std::function<void(std::vector<int>*, std::vector<int>*)> 0984 match_indices_for_smart_list_callback_; 0985 0986 MessageDifferencer::UnpackAnyField unpack_any_field_; 0987 }; 0988 0989 // This class provides extra information to the FieldComparator::Compare 0990 // function. 0991 class PROTOBUF_EXPORT FieldContext { 0992 public: 0993 explicit FieldContext( 0994 std::vector<MessageDifferencer::SpecificField>* parent_fields) 0995 : parent_fields_(parent_fields) {} 0996 0997 std::vector<MessageDifferencer::SpecificField>* parent_fields() const { 0998 return parent_fields_; 0999 } 1000 1001 private: 1002 std::vector<MessageDifferencer::SpecificField>* parent_fields_; 1003 }; 1004 1005 } // namespace util 1006 } // namespace protobuf 1007 } // namespace google 1008 1009 #include "google/protobuf/port_undef.inc" 1010 1011 #endif // GOOGLE_PROTOBUF_UTIL_MESSAGE_DIFFERENCER_H__
| [ Source navigation ] | [ Diff markup ] | [ Identifier search ] | [ general search ] |
|
This page was automatically generated by the 2.3.7 LXR engine. The LXR team |
|