OLD | NEW |
(Empty) | |
| 1 // Protocol Buffers - Google's data interchange format |
| 2 // Copyright 2008 Google Inc. All rights reserved. |
| 3 // https://developers.google.com/protocol-buffers/ |
| 4 // |
| 5 // Redistribution and use in source and binary forms, with or without |
| 6 // modification, are permitted provided that the following conditions are |
| 7 // met: |
| 8 // |
| 9 // * Redistributions of source code must retain the above copyright |
| 10 // notice, this list of conditions and the following disclaimer. |
| 11 // * Redistributions in binary form must reproduce the above |
| 12 // copyright notice, this list of conditions and the following disclaimer |
| 13 // in the documentation and/or other materials provided with the |
| 14 // distribution. |
| 15 // * Neither the name of Google Inc. nor the names of its |
| 16 // contributors may be used to endorse or promote products derived from |
| 17 // this software without specific prior written permission. |
| 18 // |
| 19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| 20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| 21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| 22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| 23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| 24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| 25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 30 |
| 31 // Author: jschorr@google.com (Joseph Schorr) |
| 32 // Based on original Protocol Buffers design by |
| 33 // Sanjay Ghemawat, Jeff Dean, and others. |
| 34 // |
| 35 // This file defines static methods and classes for comparing Protocol |
| 36 // Messages. |
| 37 // |
| 38 // Aug. 2008: Added Unknown Fields Comparison for messages. |
| 39 // Aug. 2009: Added different options to compare repeated fields. |
| 40 // Apr. 2010: Moved field comparison to FieldComparator. |
| 41 |
| 42 #ifndef GOOGLE_PROTOBUF_UTIL_MESSAGE_DIFFERENCER_H__ |
| 43 #define GOOGLE_PROTOBUF_UTIL_MESSAGE_DIFFERENCER_H__ |
| 44 |
| 45 #include <map> |
| 46 #include <set> |
| 47 #include <string> |
| 48 #include <vector> |
| 49 #include <google/protobuf/descriptor.h> // FieldDescriptor |
| 50 #include <google/protobuf/message.h> // Message |
| 51 #include <google/protobuf/unknown_field_set.h> |
| 52 #include <google/protobuf/util/field_comparator.h> |
| 53 |
| 54 namespace google { |
| 55 namespace protobuf { |
| 56 |
| 57 class DynamicMessageFactory; |
| 58 class FieldDescriptor; |
| 59 |
| 60 namespace io { |
| 61 class ZeroCopyOutputStream; |
| 62 class Printer; |
| 63 } |
| 64 |
| 65 namespace util { |
| 66 |
| 67 class FieldContext; // declared below MessageDifferencer |
| 68 |
| 69 // A basic differencer that can be used to determine |
| 70 // the differences between two specified Protocol Messages. If any differences |
| 71 // are found, the Compare method will return false, and any differencer reporter |
| 72 // specified via ReportDifferencesTo will have its reporting methods called (see |
| 73 // below for implementation of the report). Based off of the original |
| 74 // ProtocolDifferencer implementation in //net/proto/protocol-differencer.h |
| 75 // (Thanks Todd!). |
| 76 // |
| 77 // MessageDifferencer REQUIRES that compared messages be the same type, defined |
| 78 // as messages that share the same descriptor. If not, the behavior of this |
| 79 // class is undefined. |
| 80 // |
| 81 // People disagree on what MessageDifferencer should do when asked to compare |
| 82 // messages with different descriptors. Some people think it should always |
| 83 // return false. Others expect it to try to look for similar fields and |
| 84 // compare them anyway -- especially if the descriptors happen to be identical. |
| 85 // If we chose either of these behaviors, some set of people would find it |
| 86 // surprising, and could end up writing code expecting the other behavior |
| 87 // without realizing their error. Therefore, we forbid that usage. |
| 88 // |
| 89 // This class is implemented based on the proto2 reflection. The performance |
| 90 // should be good enough for normal usages. However, for places where the |
| 91 // performance is extremely sensitive, there are several alternatives: |
| 92 // - Comparing serialized string |
| 93 // Downside: false negatives (there are messages that are the same but their |
| 94 // serialized strings are different). |
| 95 // - Equals code generator by compiler plugin (net/proto2/contrib/equals_plugin) |
| 96 // Downside: more generated code; maintenance overhead for the additional rule |
| 97 // (must be in sync with the original proto_library). |
| 98 // |
| 99 // Note on handling of google.protobuf.Any: MessageDifferencer automatically |
| 100 // unpacks Any::value into a Message and compares its individual fields. |
| 101 // Messages encoded in a repeated Any cannot be compared using TreatAsMap. |
| 102 // |
| 103 // |
| 104 // Note on thread-safety: MessageDifferencer is *not* thread-safe. You need to |
| 105 // guard it with a lock to use the same MessageDifferencer instance from |
| 106 // multiple threads. Note that it's fine to call static comparison methods |
| 107 // (like MessageDifferencer::Equals) concurrently. |
| 108 class LIBPROTOBUF_EXPORT MessageDifferencer { |
| 109 public: |
| 110 // Determines whether the supplied messages are equal. Equality is defined as |
| 111 // all fields within the two messages being set to the same value. Primitive |
| 112 // fields and strings are compared by value while embedded messages/groups |
| 113 // are compared as if via a recursive call. Use IgnoreField() and Compare() |
| 114 // if some fields should be ignored in the comparison. |
| 115 // |
| 116 // This method REQUIRES that the two messages have the same |
| 117 // Descriptor (message1.GetDescriptor() == message2.GetDescriptor()). |
| 118 static bool Equals(const Message& message1, const Message& message2); |
| 119 |
| 120 // Determines whether the supplied messages are equivalent. Equivalency is |
| 121 // defined as all fields within the two messages having the same value. This |
| 122 // differs from the Equals method above in that fields with default values |
| 123 // are considered set to said value automatically. For details on how default |
| 124 // values are defined for each field type, see http://shortn/_x2Gv6XFrWt. |
| 125 // Also, Equivalent() ignores unknown fields. Use IgnoreField() and Compare() |
| 126 // if some fields should be ignored in the comparison. |
| 127 // |
| 128 // This method REQUIRES that the two messages have the same |
| 129 // Descriptor (message1.GetDescriptor() == message2.GetDescriptor()). |
| 130 static bool Equivalent(const Message& message1, const Message& message2); |
| 131 |
| 132 // Determines whether the supplied messages are approximately equal. |
| 133 // Approximate equality is defined as all fields within the two messages |
| 134 // being approximately equal. Primitive (non-float) fields and strings are |
| 135 // compared by value, floats are compared using MathUtil::AlmostEquals() and |
| 136 // embedded messages/groups are compared as if via a recursive call. Use |
| 137 // IgnoreField() and Compare() if some fields should be ignored in the |
| 138 // comparison. |
| 139 // |
| 140 // This method REQUIRES that the two messages have the same |
| 141 // Descriptor (message1.GetDescriptor() == message2.GetDescriptor()). |
| 142 static bool ApproximatelyEquals(const Message& message1, |
| 143 const Message& message2); |
| 144 |
| 145 // Determines whether the supplied messages are approximately equivalent. |
| 146 // Approximate equivalency is defined as all fields within the two messages |
| 147 // being approximately equivalent. As in |
| 148 // MessageDifferencer::ApproximatelyEquals, primitive (non-float) fields and |
| 149 // strings are compared by value, floats are compared using |
| 150 // MathUtil::AlmostEquals() and embedded messages/groups are compared as if |
| 151 // via a recursive call. However, fields with default values are considered |
| 152 // set to said value, as per MessageDiffencer::Equivalent. Use IgnoreField() |
| 153 // and Compare() if some fields should be ignored in the comparison. |
| 154 // |
| 155 // This method REQUIRES that the two messages have the same |
| 156 // Descriptor (message1.GetDescriptor() == message2.GetDescriptor()). |
| 157 static bool ApproximatelyEquivalent(const Message& message1, |
| 158 const Message& message2); |
| 159 |
| 160 // Identifies an individual field in a message instance. Used for field_path, |
| 161 // below. |
| 162 struct SpecificField { |
| 163 // For known fields, "field" is filled in and "unknown_field_number" is -1. |
| 164 // For unknown fields, "field" is NULL, "unknown_field_number" is the field |
| 165 // number, and "unknown_field_type" is its type. |
| 166 const FieldDescriptor* field; |
| 167 int unknown_field_number; |
| 168 UnknownField::Type unknown_field_type; |
| 169 |
| 170 // If this a repeated field, "index" is the index within it. For unknown |
| 171 // fields, this is the index of the field among all unknown fields of the |
| 172 // same field number and type. |
| 173 int index; |
| 174 |
| 175 // If "field" is a repeated field which is being treated as a map or |
| 176 // a set (see TreatAsMap() and TreatAsSet(), below), new_index indicates |
| 177 // the index the position to which the element has moved. This only |
| 178 // applies to ReportMoved() and (in the case of TreatAsMap()) |
| 179 // ReportModified(). In all other cases, "new_index" will have the same |
| 180 // value as "index". |
| 181 int new_index; |
| 182 |
| 183 // For unknown fields, these are the pointers to the UnknownFieldSet |
| 184 // containing the unknown fields. In certain cases (e.g. proto1's |
| 185 // MessageSet, or nested groups of unknown fields), these may differ from |
| 186 // the messages' internal UnknownFieldSets. |
| 187 const UnknownFieldSet* unknown_field_set1; |
| 188 const UnknownFieldSet* unknown_field_set2; |
| 189 |
| 190 // For unknown fields, these are the index of the field within the |
| 191 // UnknownFieldSets. One or the other will be -1 when |
| 192 // reporting an addition or deletion. |
| 193 int unknown_field_index1; |
| 194 int unknown_field_index2; |
| 195 |
| 196 SpecificField() |
| 197 : field(NULL), |
| 198 unknown_field_number(-1), |
| 199 index(-1), |
| 200 new_index(-1), |
| 201 unknown_field_set1(NULL), |
| 202 unknown_field_set2(NULL), |
| 203 unknown_field_index1(-1), |
| 204 unknown_field_index2(-1) {} |
| 205 }; |
| 206 |
| 207 // Abstract base class from which all MessageDifferencer |
| 208 // reporters derive. The five Report* methods below will be called when |
| 209 // a field has been added, deleted, modified, moved, or matched. The third |
| 210 // argument is a vector of FieldDescriptor pointers which describes the chain |
| 211 // of fields that was taken to find the current field. For example, for a |
| 212 // field found in an embedded message, the vector will contain two |
| 213 // FieldDescriptors. The first will be the field of the embedded message |
| 214 // itself and the second will be the actual field in the embedded message |
| 215 // that was added/deleted/modified. |
| 216 class LIBPROTOBUF_EXPORT Reporter { |
| 217 public: |
| 218 Reporter(); |
| 219 virtual ~Reporter(); |
| 220 |
| 221 // Reports that a field has been added into Message2. |
| 222 virtual void ReportAdded( |
| 223 const Message& message1, const Message& message2, |
| 224 const vector<SpecificField>& field_path) = 0; |
| 225 |
| 226 // Reports that a field has been deleted from Message1. |
| 227 virtual void ReportDeleted( |
| 228 const Message& message1, |
| 229 const Message& message2, |
| 230 const vector<SpecificField>& field_path) = 0; |
| 231 |
| 232 // Reports that the value of a field has been modified. |
| 233 virtual void ReportModified( |
| 234 const Message& message1, |
| 235 const Message& message2, |
| 236 const vector<SpecificField>& field_path) = 0; |
| 237 |
| 238 // Reports that a repeated field has been moved to another location. This |
| 239 // only applies when using TreatAsSet or TreatAsMap() -- see below. Also |
| 240 // note that for any given field, ReportModified and ReportMoved are |
| 241 // mutually exclusive. If a field has been both moved and modified, then |
| 242 // only ReportModified will be called. |
| 243 virtual void ReportMoved( |
| 244 const Message& message1, |
| 245 const Message& message2, |
| 246 const vector<SpecificField>& field_path) { } |
| 247 |
| 248 // Reports that two fields match. Useful for doing side-by-side diffs. |
| 249 // This function is mutually exclusive with ReportModified and ReportMoved. |
| 250 // Note that you must call set_report_matches(true) before calling Compare |
| 251 // to make use of this function. |
| 252 virtual void ReportMatched( |
| 253 const Message& message1, |
| 254 const Message& message2, |
| 255 const vector<SpecificField>& field_path) { } |
| 256 |
| 257 // Reports that two fields would have been compared, but the |
| 258 // comparison has been skipped because the field was marked as |
| 259 // 'ignored' using IgnoreField(). This function is mutually |
| 260 // exclusive with all the other Report() functions. |
| 261 // |
| 262 // The contract of ReportIgnored is slightly different than the |
| 263 // other Report() functions, in that |field_path.back().index| is |
| 264 // always equal to -1, even if the last field is repeated. This is |
| 265 // because while the other Report() functions indicate where in a |
| 266 // repeated field the action (Addition, Deletion, etc...) |
| 267 // happened, when a repeated field is 'ignored', the differencer |
| 268 // simply calls ReportIgnored on the repeated field as a whole and |
| 269 // moves on without looking at its individual elements. |
| 270 // |
| 271 // Furthermore, ReportIgnored() does not indicate whether the |
| 272 // fields were in fact equal or not, as Compare() does not inspect |
| 273 // these fields at all. It is up to the Reporter to decide whether |
| 274 // the fields are equal or not (perhaps with a second call to |
| 275 // Compare()), if it cares. |
| 276 virtual void ReportIgnored( |
| 277 const Message& message1, |
| 278 const Message& message2, |
| 279 const vector<SpecificField>& field_path) { } |
| 280 |
| 281 // Report that an unkown field is ignored. (see comment above). |
| 282 // Note this is a different function since the last SpecificField in field |
| 283 // path has a null field. This could break existing Reporter. |
| 284 virtual void ReportUnknownFieldIgnored( |
| 285 const Message& message1, const Message& message2, |
| 286 const vector<SpecificField>& field_path) {} |
| 287 |
| 288 private: |
| 289 GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Reporter); |
| 290 }; |
| 291 |
| 292 // MapKeyComparator is used to determine if two elements have the same key |
| 293 // when comparing elements of a repeated field as a map. |
| 294 class LIBPROTOBUF_EXPORT MapKeyComparator { |
| 295 public: |
| 296 MapKeyComparator(); |
| 297 virtual ~MapKeyComparator(); |
| 298 |
| 299 virtual bool IsMatch(const Message& message1, |
| 300 const Message& message2, |
| 301 const vector<SpecificField>& parent_fields) const { |
| 302 GOOGLE_CHECK(false) << "IsMatch() is not implemented."; |
| 303 return false; |
| 304 } |
| 305 |
| 306 private: |
| 307 GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MapKeyComparator); |
| 308 }; |
| 309 |
| 310 // Abstract base class from which all IgnoreCriteria derive. |
| 311 // By adding IgnoreCriteria more complex ignore logic can be implemented. |
| 312 // IgnoreCriteria are registed with AddIgnoreCriteria. For each compared |
| 313 // field IsIgnored is called on each added IgnoreCriteria until one returns |
| 314 // true or all return false. |
| 315 // IsIgnored is called for fields where at least one side has a value. |
| 316 class LIBPROTOBUF_EXPORT IgnoreCriteria { |
| 317 public: |
| 318 IgnoreCriteria(); |
| 319 virtual ~IgnoreCriteria(); |
| 320 |
| 321 // Returns true if the field should be ignored. |
| 322 virtual bool IsIgnored( |
| 323 const Message& message1, |
| 324 const Message& message2, |
| 325 const FieldDescriptor* field, |
| 326 const vector<SpecificField>& parent_fields) = 0; |
| 327 |
| 328 // Returns true if the unknown field should be ignored. |
| 329 // Note: This will be called for unknown fields as well in which case |
| 330 // field.field will be null. |
| 331 virtual bool IsUnknownFieldIgnored( |
| 332 const Message& message1, const Message& message2, |
| 333 const SpecificField& field, |
| 334 const vector<SpecificField>& parent_fields) { |
| 335 return false; |
| 336 } |
| 337 }; |
| 338 |
| 339 // To add a Reporter, construct default here, then use ReportDifferencesTo or |
| 340 // ReportDifferencesToString. |
| 341 explicit MessageDifferencer(); |
| 342 |
| 343 ~MessageDifferencer(); |
| 344 |
| 345 enum MessageFieldComparison { |
| 346 EQUAL, // Fields must be present in both messages |
| 347 // for the messages to be considered the same. |
| 348 EQUIVALENT, // Fields with default values are considered set |
| 349 // for comparison purposes even if not explicitly |
| 350 // set in the messages themselves. Unknown fields |
| 351 // are ignored. |
| 352 }; |
| 353 |
| 354 enum Scope { |
| 355 FULL, // All fields of both messages are considered in the comparison. |
| 356 PARTIAL // Only fields present in the first message are considered; fields |
| 357 // set only in the second message will be skipped during |
| 358 // comparison. |
| 359 }; |
| 360 |
| 361 // DEPRECATED. Use FieldComparator::FloatComparison instead. |
| 362 enum FloatComparison { |
| 363 EXACT, // Floats and doubles are compared exactly. |
| 364 APPROXIMATE // Floats and doubles are compared using the |
| 365 // MathUtil::AlmostEquals method. |
| 366 }; |
| 367 |
| 368 enum RepeatedFieldComparison { |
| 369 AS_LIST, // Repeated fields are compared in order. Differing values at |
| 370 // the same index are reported using ReportModified(). If the |
| 371 // repeated fields have different numbers of elements, the |
| 372 // unpaired elements are reported using ReportAdded() or |
| 373 // ReportDeleted(). |
| 374 AS_SET, // Treat all the repeated fields as sets by default. |
| 375 // See TreatAsSet(), as below. |
| 376 }; |
| 377 |
| 378 // The elements of the given repeated field will be treated as a set for |
| 379 // diffing purposes, so different orderings of the same elements will be |
| 380 // considered equal. Elements which are present on both sides of the |
| 381 // comparison but which have changed position will be reported with |
| 382 // ReportMoved(). Elements which only exist on one side or the other are |
| 383 // reported with ReportAdded() and ReportDeleted() regardless of their |
| 384 // positions. ReportModified() is never used for this repeated field. If |
| 385 // the only differences between the compared messages is that some fields |
| 386 // have been moved, then the comparison returns true. |
| 387 // |
| 388 // If the scope of comparison is set to PARTIAL, then in addition to what's |
| 389 // above, extra values added to repeated fields of the second message will |
| 390 // not cause the comparison to fail. |
| 391 // |
| 392 // Note that set comparison is currently O(k * n^2) (where n is the total |
| 393 // number of elements, and k is the average size of each element). In theory |
| 394 // it could be made O(n * k) with a more complex hashing implementation. Feel |
| 395 // free to contribute one if the current implementation is too slow for you. |
| 396 // If partial matching is also enabled, the time complexity will be O(k * n^2 |
| 397 // + n^3) in which n^3 is the time complexity of the maximum matching |
| 398 // algorithm. |
| 399 // |
| 400 // REQUIRES: field->is_repeated() and field not registered with TreatAsList |
| 401 void TreatAsSet(const FieldDescriptor* field); |
| 402 |
| 403 // The elements of the given repeated field will be treated as a list for |
| 404 // diffing purposes, so different orderings of the same elements will NOT be |
| 405 // considered equal. |
| 406 // |
| 407 // REQUIRED: field->is_repeated() and field not registered with TreatAsSet |
| 408 void TreatAsList(const FieldDescriptor* field); |
| 409 |
| 410 // The elements of the given repeated field will be treated as a map for |
| 411 // diffing purposes, with |key| being the map key. Thus, elements with the |
| 412 // same key will be compared even if they do not appear at the same index. |
| 413 // Differences are reported similarly to TreatAsSet(), except that |
| 414 // ReportModified() is used to report elements with the same key but |
| 415 // different values. Note that if an element is both moved and modified, |
| 416 // only ReportModified() will be called. As with TreatAsSet, if the only |
| 417 // differences between the compared messages is that some fields have been |
| 418 // moved, then the comparison returns true. See TreatAsSet for notes on |
| 419 // performance. |
| 420 // |
| 421 // REQUIRES: field->is_repeated() |
| 422 // REQUIRES: field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE |
| 423 // REQUIRES: key->containing_type() == field->message_type() |
| 424 void TreatAsMap(const FieldDescriptor* field, const FieldDescriptor* key); |
| 425 // Same as TreatAsMap except that this method will use multiple fields as |
| 426 // the key in comparison. All specified fields in 'key_fields' should be |
| 427 // present in the compared elements. Two elements will be treated as having |
| 428 // the same key iff they have the same value for every specified field. There |
| 429 // are two steps in the comparison process. The first one is key matching. |
| 430 // Every element from one message will be compared to every element from |
| 431 // the other message. Only fields in 'key_fields' are compared in this step |
| 432 // to decide if two elements have the same key. The second step is value |
| 433 // comparison. Those pairs of elements with the same key (with equal value |
| 434 // for every field in 'key_fields') will be compared in this step. |
| 435 // Time complexity of the first step is O(s * m * n ^ 2) where s is the |
| 436 // average size of the fields specified in 'key_fields', m is the number of |
| 437 // fields in 'key_fields' and n is the number of elements. If partial |
| 438 // matching is enabled, an extra O(n^3) will be incured by the maximum |
| 439 // matching algorithm. The second step is O(k * n) where k is the average |
| 440 // size of each element. |
| 441 void TreatAsMapWithMultipleFieldsAsKey( |
| 442 const FieldDescriptor* field, |
| 443 const vector<const FieldDescriptor*>& key_fields); |
| 444 // Same as TreatAsMapWithMultipleFieldsAsKey, except that each of the field |
| 445 // do not necessarily need to be a direct subfield. Each element in |
| 446 // key_field_paths indicate a path from the message being compared, listing |
| 447 // successive subfield to reach the key field. |
| 448 // |
| 449 // REQUIRES: |
| 450 // for key_field_path in key_field_paths: |
| 451 // key_field_path[0]->containing_type() == field->message_type() |
| 452 // for i in [0, key_field_path.size() - 1): |
| 453 // key_field_path[i+1]->containing_type() == |
| 454 // key_field_path[i]->message_type() |
| 455 // key_field_path[i]->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE |
| 456 // !key_field_path[i]->is_repeated() |
| 457 void TreatAsMapWithMultipleFieldPathsAsKey( |
| 458 const FieldDescriptor* field, |
| 459 const vector<vector<const FieldDescriptor*> >& key_field_paths); |
| 460 |
| 461 // Uses a custom MapKeyComparator to determine if two elements have the same |
| 462 // key when comparing a repeated field as a map. |
| 463 // The caller is responsible to delete the key_comparator. |
| 464 // This method varies from TreatAsMapWithMultipleFieldsAsKey only in the |
| 465 // first key matching step. Rather than comparing some specified fields, it |
| 466 // will invoke the IsMatch method of the given 'key_comparator' to decide if |
| 467 // two elements have the same key. |
| 468 void TreatAsMapUsingKeyComparator( |
| 469 const FieldDescriptor* field, |
| 470 const MapKeyComparator* key_comparator); |
| 471 |
| 472 // Add a custom ignore criteria that is evaluated in addition to the |
| 473 // ignored fields added with IgnoreField. |
| 474 // Takes ownership of ignore_criteria. |
| 475 void AddIgnoreCriteria(IgnoreCriteria* ignore_criteria); |
| 476 |
| 477 // Indicates that any field with the given descriptor should be |
| 478 // ignored for the purposes of comparing two messages. This applies |
| 479 // to fields nested in the message structure as well as top level |
| 480 // ones. When the MessageDifferencer encounters an ignored field, |
| 481 // ReportIgnored is called on the reporter, if one is specified. |
| 482 // |
| 483 // The only place where the field's 'ignored' status is not applied is when |
| 484 // it is being used as a key in a field passed to TreatAsMap or is one of |
| 485 // the fields passed to TreatAsMapWithMultipleFieldsAsKey. |
| 486 // In this case it is compared in key matching but after that it's ignored |
| 487 // in value comparison. |
| 488 void IgnoreField(const FieldDescriptor* field); |
| 489 |
| 490 // Sets the field comparator used to determine differences between protocol |
| 491 // buffer fields. By default it's set to a DefaultFieldComparator instance. |
| 492 // MessageDifferencer doesn't take ownership over the passed object. |
| 493 // Note that this method must be called before Compare for the comparator to |
| 494 // be used. |
| 495 void set_field_comparator(FieldComparator* comparator); |
| 496 |
| 497 // DEPRECATED. Pass a DefaultFieldComparator instance instead. |
| 498 // Sets the fraction and margin for the float comparison of a given field. |
| 499 // Uses MathUtil::WithinFractionOrMargin to compare the values. |
| 500 // NOTE: this method does nothing if differencer's field comparator has been |
| 501 // set to a custom object. |
| 502 // |
| 503 // REQUIRES: field->cpp_type == FieldDescriptor::CPPTYPE_DOUBLE or |
| 504 // field->cpp_type == FieldDescriptor::CPPTYPE_FLOAT |
| 505 // REQUIRES: float_comparison_ == APPROXIMATE |
| 506 void SetFractionAndMargin(const FieldDescriptor* field, double fraction, |
| 507 double margin); |
| 508 |
| 509 // Sets the type of comparison (as defined in the MessageFieldComparison |
| 510 // enumeration above) that is used by this differencer when determining how |
| 511 // to compare fields in messages. |
| 512 void set_message_field_comparison(MessageFieldComparison comparison); |
| 513 |
| 514 // Tells the differencer whether or not to report matches. This method must |
| 515 // be called before Compare. The default for a new differencer is false. |
| 516 void set_report_matches(bool report_matches) { |
| 517 report_matches_ = report_matches; |
| 518 } |
| 519 |
| 520 // Sets the scope of the comparison (as defined in the Scope enumeration |
| 521 // above) that is used by this differencer when determining which fields to |
| 522 // compare between the messages. |
| 523 void set_scope(Scope scope); |
| 524 |
| 525 // Returns the current scope used by this differencer. |
| 526 Scope scope(); |
| 527 |
| 528 // DEPRECATED. Pass a DefaultFieldComparator instance instead. |
| 529 // Sets the type of comparison (as defined in the FloatComparison enumeration |
| 530 // above) that is used by this differencer when comparing float (and double) |
| 531 // fields in messages. |
| 532 // NOTE: this method does nothing if differencer's field comparator has been |
| 533 // set to a custom object. |
| 534 void set_float_comparison(FloatComparison comparison); |
| 535 |
| 536 // Sets the type of comparison for repeated field (as defined in the |
| 537 // RepeatedFieldComparison enumeration above) that is used by this |
| 538 // differencer when compare repeated fields in messages. |
| 539 void set_repeated_field_comparison(RepeatedFieldComparison comparison); |
| 540 |
| 541 // Compares the two specified messages, returning true if they are the same, |
| 542 // false otherwise. If this method returns false, any changes between the |
| 543 // two messages will be reported if a Reporter was specified via |
| 544 // ReportDifferencesTo (see also ReportDifferencesToString). |
| 545 // |
| 546 // This method REQUIRES that the two messages have the same |
| 547 // Descriptor (message1.GetDescriptor() == message2.GetDescriptor()). |
| 548 bool Compare(const Message& message1, const Message& message2); |
| 549 |
| 550 // Same as above, except comparing only the list of fields specified by the |
| 551 // two vectors of FieldDescriptors. |
| 552 bool CompareWithFields(const Message& message1, const Message& message2, |
| 553 const vector<const FieldDescriptor*>& message1_fields, |
| 554 const vector<const FieldDescriptor*>& message2_fields); |
| 555 |
| 556 // Automatically creates a reporter that will output the differences |
| 557 // found (if any) to the specified output string pointer. Note that this |
| 558 // method must be called before Compare. |
| 559 void ReportDifferencesToString(string* output); |
| 560 |
| 561 // Tells the MessageDifferencer to report differences via the specified |
| 562 // reporter. Note that this method must be called before Compare for |
| 563 // the reporter to be used. It is the responsibility of the caller to delete |
| 564 // this object. |
| 565 // If the provided pointer equals NULL, the MessageDifferencer stops reporting |
| 566 // differences to any previously set reporters or output strings. |
| 567 void ReportDifferencesTo(Reporter* reporter); |
| 568 |
| 569 // An implementation of the MessageDifferencer Reporter that outputs |
| 570 // any differences found in human-readable form to the supplied |
| 571 // ZeroCopyOutputStream or Printer. If a printer is used, the delimiter |
| 572 // *must* be '$'. |
| 573 class LIBPROTOBUF_EXPORT StreamReporter : public Reporter { |
| 574 public: |
| 575 explicit StreamReporter(io::ZeroCopyOutputStream* output); |
| 576 explicit StreamReporter(io::Printer* printer); // delimiter '$' |
| 577 virtual ~StreamReporter(); |
| 578 |
| 579 // When set to true, the stream reporter will also output aggregates nodes |
| 580 // (i.e. messages and groups) whose subfields have been modified. When |
| 581 // false, will only report the individual subfields. Defaults to false. |
| 582 void set_report_modified_aggregates(bool report) { |
| 583 report_modified_aggregates_ = report; |
| 584 } |
| 585 |
| 586 // The following are implementations of the methods described above. |
| 587 virtual void ReportAdded(const Message& message1, const Message& message2, |
| 588 const vector<SpecificField>& field_path); |
| 589 |
| 590 virtual void ReportDeleted(const Message& message1, |
| 591 const Message& message2, |
| 592 const vector<SpecificField>& field_path); |
| 593 |
| 594 virtual void ReportModified(const Message& message1, |
| 595 const Message& message2, |
| 596 const vector<SpecificField>& field_path); |
| 597 |
| 598 virtual void ReportMoved(const Message& message1, |
| 599 const Message& message2, |
| 600 const vector<SpecificField>& field_path); |
| 601 |
| 602 virtual void ReportMatched(const Message& message1, |
| 603 const Message& message2, |
| 604 const vector<SpecificField>& field_path); |
| 605 |
| 606 virtual void ReportIgnored(const Message& message1, |
| 607 const Message& message2, |
| 608 const vector<SpecificField>& field_path); |
| 609 |
| 610 virtual void ReportUnknownFieldIgnored( |
| 611 const Message& message1, const Message& message2, |
| 612 const vector<SpecificField>& field_path); |
| 613 |
| 614 protected: |
| 615 // Prints the specified path of fields to the buffer. |
| 616 virtual void PrintPath(const vector<SpecificField>& field_path, |
| 617 bool left_side); |
| 618 |
| 619 // Prints the value of fields to the buffer. left_side is true if the |
| 620 // given message is from the left side of the comparison, false if it |
| 621 // was the right. This is relevant only to decide whether to follow |
| 622 // unknown_field_index1 or unknown_field_index2 when an unknown field |
| 623 // is encountered in field_path. |
| 624 virtual void PrintValue(const Message& message, |
| 625 const vector<SpecificField>& field_path, |
| 626 bool left_side); |
| 627 |
| 628 // Prints the specified path of unknown fields to the buffer. |
| 629 virtual void PrintUnknownFieldValue(const UnknownField* unknown_field); |
| 630 |
| 631 // Just print a string |
| 632 void Print(const string& str); |
| 633 |
| 634 private: |
| 635 io::Printer* printer_; |
| 636 bool delete_printer_; |
| 637 bool report_modified_aggregates_; |
| 638 |
| 639 GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(StreamReporter); |
| 640 }; |
| 641 |
| 642 private: |
| 643 // A MapKeyComparator to be used in TreatAsMapUsingKeyComparator. |
| 644 // Implementation of this class needs to do field value comparison which |
| 645 // relies on some private methods of MessageDifferencer. That's why this |
| 646 // class is declared as a nested class of MessageDifferencer. |
| 647 class MultipleFieldsMapKeyComparator; |
| 648 // Returns true if field1's number() is less than field2's. |
| 649 static bool FieldBefore(const FieldDescriptor* field1, |
| 650 const FieldDescriptor* field2); |
| 651 |
| 652 // Combine the two lists of fields into the combined_fields output vector. |
| 653 // All fields present in both lists will always be included in the combined |
| 654 // list. Fields only present in one of the lists will only appear in the |
| 655 // combined list if the corresponding fields_scope option is set to FULL. |
| 656 void CombineFields(const vector<const FieldDescriptor*>& fields1, |
| 657 Scope fields1_scope, |
| 658 const vector<const FieldDescriptor*>& fields2, |
| 659 Scope fields2_scope, |
| 660 vector<const FieldDescriptor*>* combined_fields); |
| 661 |
| 662 // Internal version of the Compare method which performs the actual |
| 663 // comparison. The parent_fields vector is a vector containing field |
| 664 // descriptors of all fields accessed to get to this comparison operation |
| 665 // (i.e. if the current message is an embedded message, the parent_fields |
| 666 // vector will contain the field that has this embedded message). |
| 667 bool Compare(const Message& message1, const Message& message2, |
| 668 vector<SpecificField>* parent_fields); |
| 669 |
| 670 // Compares all the unknown fields in two messages. |
| 671 bool CompareUnknownFields(const Message& message1, const Message& message2, |
| 672 const google::protobuf::UnknownFieldSet&, |
| 673 const google::protobuf::UnknownFieldSet&, |
| 674 vector<SpecificField>* parent_fields); |
| 675 |
| 676 // Compares the specified messages for the requested field lists. The field |
| 677 // lists are modified depending on comparison settings, and then passed to |
| 678 // CompareWithFieldsInternal. |
| 679 bool CompareRequestedFieldsUsingSettings( |
| 680 const Message& message1, const Message& message2, |
| 681 const vector<const FieldDescriptor*>& message1_fields, |
| 682 const vector<const FieldDescriptor*>& message2_fields, |
| 683 vector<SpecificField>* parent_fields); |
| 684 |
| 685 // Compares the specified messages with the specified field lists. |
| 686 bool CompareWithFieldsInternal( |
| 687 const Message& message1, const Message& message2, |
| 688 const vector<const FieldDescriptor*>& message1_fields, |
| 689 const vector<const FieldDescriptor*>& message2_fields, |
| 690 vector<SpecificField>* parent_fields); |
| 691 |
| 692 // Compares the repeated fields, and report the error. |
| 693 bool CompareRepeatedField(const Message& message1, const Message& message2, |
| 694 const FieldDescriptor* field, |
| 695 vector<SpecificField>* parent_fields); |
| 696 |
| 697 // Shorthand for CompareFieldValueUsingParentFields with NULL parent_fields. |
| 698 bool CompareFieldValue(const Message& message1, |
| 699 const Message& message2, |
| 700 const FieldDescriptor* field, |
| 701 int index1, |
| 702 int index2); |
| 703 |
| 704 // Compares the specified field on the two messages, returning |
| 705 // true if they are the same, false otherwise. For repeated fields, |
| 706 // this method only compares the value in the specified index. This method |
| 707 // uses Compare functions to recurse into submessages. |
| 708 // The parent_fields vector is used in calls to a Reporter instance calls. |
| 709 // It can be NULL, in which case the MessageDifferencer will create new |
| 710 // list of parent messages if it needs to recursively compare the given field. |
| 711 // To avoid confusing users you should not set it to NULL unless you modified |
| 712 // Reporter to handle the change of parent_fields correctly. |
| 713 bool CompareFieldValueUsingParentFields(const Message& message1, |
| 714 const Message& message2, |
| 715 const FieldDescriptor* field, |
| 716 int index1, |
| 717 int index2, |
| 718 vector<SpecificField>* parent_fields); |
| 719 |
| 720 // Compares the specified field on the two messages, returning comparison |
| 721 // result, as returned by appropriate FieldComparator. |
| 722 FieldComparator::ComparisonResult GetFieldComparisonResult( |
| 723 const Message& message1, const Message& message2, |
| 724 const FieldDescriptor* field, int index1, int index2, |
| 725 const FieldContext* field_context); |
| 726 |
| 727 // Check if the two elements in the repeated field are match to each other. |
| 728 // if the key_comprator is NULL, this function returns true when the two |
| 729 // elements are equal. |
| 730 bool IsMatch(const FieldDescriptor* repeated_field, |
| 731 const MapKeyComparator* key_comparator, |
| 732 const Message* message1, const Message* message2, |
| 733 const vector<SpecificField>& parent_fields, |
| 734 int index1, int index2); |
| 735 |
| 736 // Returns true when this repeated field has been configured to be treated |
| 737 // as a set. |
| 738 bool IsTreatedAsSet(const FieldDescriptor* field); |
| 739 |
| 740 // Returns true when this repeated field is to be compared as a subset, ie. |
| 741 // has been configured to be treated as a set or map and scope is set to |
| 742 // PARTIAL. |
| 743 bool IsTreatedAsSubset(const FieldDescriptor* field); |
| 744 |
| 745 // Returns true if this field is to be ignored when this |
| 746 // MessageDifferencer compares messages. |
| 747 bool IsIgnored( |
| 748 const Message& message1, |
| 749 const Message& message2, |
| 750 const FieldDescriptor* field, |
| 751 const vector<SpecificField>& parent_fields); |
| 752 |
| 753 // Returns true if this unknown field is to be ignored when this |
| 754 // MessageDifferencer compares messages. |
| 755 bool IsUnknownFieldIgnored(const Message& message1, const Message& message2, |
| 756 const SpecificField& field, |
| 757 const vector<SpecificField>& parent_fields); |
| 758 |
| 759 // Returns MapKeyComparator* when this field has been configured to |
| 760 // be treated as a map. If not, returns NULL. |
| 761 const MapKeyComparator* GetMapKeyComparator(const FieldDescriptor* field); |
| 762 |
| 763 // Attempts to match indices of a repeated field, so that the contained values |
| 764 // match. Clears output vectors and sets their values to indices of paired |
| 765 // messages, ie. if message1[0] matches message2[1], then match_list1[0] == 1 |
| 766 // and match_list2[1] == 0. The unmatched indices are indicated by -1. |
| 767 // This method returns false if the match failed. However, it doesn't mean |
| 768 // that the comparison succeeds when this method returns true (you need to |
| 769 // double-check in this case). |
| 770 bool MatchRepeatedFieldIndices(const Message& message1, |
| 771 const Message& message2, |
| 772 const FieldDescriptor* repeated_field, |
| 773 const vector<SpecificField>& parent_fields, |
| 774 vector<int>* match_list1, |
| 775 vector<int>* match_list2); |
| 776 |
| 777 // If "any" is of type google.protobuf.Any, extract its payload using |
| 778 // DynamicMessageFactory and store in "data". |
| 779 bool UnpackAny(const Message& any, google::protobuf::scoped_ptr<Message>* data
); |
| 780 |
| 781 // Checks if index is equal to new_index in all the specific fields. |
| 782 static bool CheckPathChanged(const vector<SpecificField>& parent_fields); |
| 783 |
| 784 // Defines a map between field descriptors and their MapKeyComparators. |
| 785 // Used for repeated fields when they are configured as TreatAsMap. |
| 786 typedef map<const FieldDescriptor*, |
| 787 const MapKeyComparator*> FieldKeyComparatorMap; |
| 788 |
| 789 // Defines a set to store field descriptors. Used for repeated fields when |
| 790 // they are configured as TreatAsSet. |
| 791 typedef set<const FieldDescriptor*> FieldSet; |
| 792 |
| 793 Reporter* reporter_; |
| 794 DefaultFieldComparator default_field_comparator_; |
| 795 FieldComparator* field_comparator_; |
| 796 MessageFieldComparison message_field_comparison_; |
| 797 Scope scope_; |
| 798 RepeatedFieldComparison repeated_field_comparison_; |
| 799 |
| 800 FieldSet set_fields_; |
| 801 FieldSet list_fields_; |
| 802 // Keeps track of MapKeyComparators that are created within |
| 803 // MessageDifferencer. These MapKeyComparators should be deleted |
| 804 // before MessageDifferencer is destroyed. |
| 805 // When TreatAsMap or TreatAsMapWithMultipleFieldsAsKey is called, we don't |
| 806 // store the supplied FieldDescriptors directly. Instead, a new |
| 807 // MapKeyComparator is created for comparison purpose. |
| 808 vector<MapKeyComparator*> owned_key_comparators_; |
| 809 FieldKeyComparatorMap map_field_key_comparator_; |
| 810 vector<IgnoreCriteria*> ignore_criteria_; |
| 811 |
| 812 FieldSet ignored_fields_; |
| 813 |
| 814 bool compare_unknown_fields_; |
| 815 bool report_matches_; |
| 816 |
| 817 string* output_string_; |
| 818 |
| 819 google::protobuf::scoped_ptr<DynamicMessageFactory> dynamic_message_factory_; |
| 820 GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageDifferencer); |
| 821 }; |
| 822 |
| 823 // This class provides extra information to the FieldComparator::Compare |
| 824 // function. |
| 825 class LIBPROTOBUF_EXPORT FieldContext { |
| 826 public: |
| 827 explicit FieldContext( |
| 828 vector<MessageDifferencer::SpecificField>* parent_fields) |
| 829 : parent_fields_(parent_fields) {} |
| 830 |
| 831 vector<MessageDifferencer::SpecificField>* parent_fields() const { |
| 832 return parent_fields_; |
| 833 } |
| 834 |
| 835 private: |
| 836 vector<MessageDifferencer::SpecificField>* parent_fields_; |
| 837 }; |
| 838 |
| 839 } |
| 840 } |
| 841 |
| 842 } // namespace google |
| 843 #endif // GOOGLE_PROTOBUF_UTIL_MESSAGE_DIFFERENCER_H__ |
OLD | NEW |