Brian Silverman | 9c614bc | 2016-02-15 20:20:02 -0500 | [diff] [blame^] | 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__ |