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 | // Sep. 2020: Added option to output map keys in path |
42 | |
43 | #ifndef GOOGLE_PROTOBUF_UTIL_MESSAGE_DIFFERENCER_H__ |
44 | #define GOOGLE_PROTOBUF_UTIL_MESSAGE_DIFFERENCER_H__ |
45 | |
46 | |
47 | #include <functional> |
48 | #include <map> |
49 | #include <memory> |
50 | #include <set> |
51 | #include <string> |
52 | #include <vector> |
53 | |
54 | #include <google/protobuf/descriptor.h> // FieldDescriptor |
55 | #include <google/protobuf/message.h> // Message |
56 | #include <google/protobuf/unknown_field_set.h> |
57 | #include <google/protobuf/util/field_comparator.h> |
58 | |
59 | // Always include as last one, otherwise it can break compilation |
60 | #include <google/protobuf/port_def.inc> |
61 | |
62 | namespace google { |
63 | namespace protobuf { |
64 | |
65 | class DynamicMessageFactory; |
66 | class FieldDescriptor; |
67 | |
68 | namespace io { |
69 | class ZeroCopyOutputStream; |
70 | class Printer; |
71 | } // namespace io |
72 | |
73 | namespace util { |
74 | |
75 | class DefaultFieldComparator; |
76 | class FieldContext; // declared below MessageDifferencer |
77 | |
78 | // Defines a collection of field descriptors. |
79 | // In case of internal google codebase we are using absl::FixedArray instead |
80 | // of vector. It significantly speeds up proto comparison (by ~30%) by |
81 | // reducing the number of malloc/free operations |
82 | typedef std::vector<const FieldDescriptor*> FieldDescriptorArray; |
83 | |
84 | // A basic differencer that can be used to determine |
85 | // the differences between two specified Protocol Messages. If any differences |
86 | // are found, the Compare method will return false, and any differencer reporter |
87 | // specified via ReportDifferencesTo will have its reporting methods called (see |
88 | // below for implementation of the report). Based off of the original |
89 | // ProtocolDifferencer implementation in //net/proto/protocol-differencer.h |
90 | // (Thanks Todd!). |
91 | // |
92 | // MessageDifferencer REQUIRES that compared messages be the same type, defined |
93 | // as messages that share the same descriptor. If not, the behavior of this |
94 | // class is undefined. |
95 | // |
96 | // People disagree on what MessageDifferencer should do when asked to compare |
97 | // messages with different descriptors. Some people think it should always |
98 | // return false. Others expect it to try to look for similar fields and |
99 | // compare them anyway -- especially if the descriptors happen to be identical. |
100 | // If we chose either of these behaviors, some set of people would find it |
101 | // surprising, and could end up writing code expecting the other behavior |
102 | // without realizing their error. Therefore, we forbid that usage. |
103 | // |
104 | // This class is implemented based on the proto2 reflection. The performance |
105 | // should be good enough for normal usages. However, for places where the |
106 | // performance is extremely sensitive, there are several alternatives: |
107 | // - Comparing serialized string |
108 | // Downside: false negatives (there are messages that are the same but their |
109 | // serialized strings are different). |
110 | // - Equals code generator by compiler plugin (net/proto2/contrib/equals_plugin) |
111 | // Downside: more generated code; maintenance overhead for the additional rule |
112 | // (must be in sync with the original proto_library). |
113 | // |
114 | // Note on handling of google.protobuf.Any: MessageDifferencer automatically |
115 | // unpacks Any::value into a Message and compares its individual fields. |
116 | // Messages encoded in a repeated Any cannot be compared using TreatAsMap. |
117 | // |
118 | // Note on thread-safety: MessageDifferencer is *not* thread-safe. You need to |
119 | // guard it with a lock to use the same MessageDifferencer instance from |
120 | // multiple threads. Note that it's fine to call static comparison methods |
121 | // (like MessageDifferencer::Equals) concurrently, but it's not recommended for |
122 | // performance critical code as it leads to extra allocations. |
123 | class PROTOBUF_EXPORT MessageDifferencer { |
124 | public: |
125 | // Determines whether the supplied messages are equal. Equality is defined as |
126 | // all fields within the two messages being set to the same value. Primitive |
127 | // fields and strings are compared by value while embedded messages/groups |
128 | // are compared as if via a recursive call. Use Compare() with IgnoreField() |
129 | // if some fields should be ignored in the comparison. Use Compare() with |
130 | // TreatAsSet() if there are repeated fields where ordering does not matter. |
131 | // |
132 | // This method REQUIRES that the two messages have the same |
133 | // Descriptor (message1.GetDescriptor() == message2.GetDescriptor()). |
134 | static bool Equals(const Message& message1, const Message& message2); |
135 | |
136 | // Determines whether the supplied messages are equivalent. Equivalency is |
137 | // defined as all fields within the two messages having the same value. This |
138 | // differs from the Equals method above in that fields with default values |
139 | // are considered set to said value automatically. For details on how default |
140 | // values are defined for each field type, see: |
141 | // https://developers.google.com/protocol-buffers/docs/proto?csw=1#optional. |
142 | // Also, Equivalent() ignores unknown fields. Use IgnoreField() and Compare() |
143 | // if some fields should be ignored in the comparison. |
144 | // |
145 | // This method REQUIRES that the two messages have the same |
146 | // Descriptor (message1.GetDescriptor() == message2.GetDescriptor()). |
147 | static bool Equivalent(const Message& message1, const Message& message2); |
148 | |
149 | // Determines whether the supplied messages are approximately equal. |
150 | // Approximate equality is defined as all fields within the two messages |
151 | // being approximately equal. Primitive (non-float) fields and strings are |
152 | // compared by value, floats are compared using MathUtil::AlmostEquals() and |
153 | // embedded messages/groups are compared as if via a recursive call. Use |
154 | // IgnoreField() and Compare() if some fields should be ignored in the |
155 | // comparison. |
156 | // |
157 | // This method REQUIRES that the two messages have the same |
158 | // Descriptor (message1.GetDescriptor() == message2.GetDescriptor()). |
159 | static bool ApproximatelyEquals(const Message& message1, |
160 | const Message& message2); |
161 | |
162 | // Determines whether the supplied messages are approximately equivalent. |
163 | // Approximate equivalency is defined as all fields within the two messages |
164 | // being approximately equivalent. As in |
165 | // MessageDifferencer::ApproximatelyEquals, primitive (non-float) fields and |
166 | // strings are compared by value, floats are compared using |
167 | // MathUtil::AlmostEquals() and embedded messages/groups are compared as if |
168 | // via a recursive call. However, fields with default values are considered |
169 | // set to said value, as per MessageDiffencer::Equivalent. Use IgnoreField() |
170 | // and Compare() if some fields should be ignored in the comparison. |
171 | // |
172 | // This method REQUIRES that the two messages have the same |
173 | // Descriptor (message1.GetDescriptor() == message2.GetDescriptor()). |
174 | static bool ApproximatelyEquivalent(const Message& message1, |
175 | const Message& message2); |
176 | |
177 | // Identifies an individual field in a message instance. Used for field_path, |
178 | // below. |
179 | struct SpecificField { |
180 | // For known fields, "field" is filled in and "unknown_field_number" is -1. |
181 | // For unknown fields, "field" is NULL, "unknown_field_number" is the field |
182 | // number, and "unknown_field_type" is its type. |
183 | const FieldDescriptor* field = nullptr; |
184 | int unknown_field_number = -1; |
185 | UnknownField::Type unknown_field_type = UnknownField::Type::TYPE_VARINT; |
186 | |
187 | // If this a repeated field, "index" is the index within it. For unknown |
188 | // fields, this is the index of the field among all unknown fields of the |
189 | // same field number and type. |
190 | int index = -1; |
191 | |
192 | // If "field" is a repeated field which is being treated as a map or |
193 | // a set (see TreatAsMap() and TreatAsSet(), below), new_index indicates |
194 | // the index the position to which the element has moved. If the element |
195 | // has not moved, "new_index" will have the same value as "index". |
196 | int new_index = -1; |
197 | |
198 | // If "field" is a map field, point to the map entry. |
199 | const Message* map_entry1 = nullptr; |
200 | const Message* map_entry2 = nullptr; |
201 | |
202 | // For unknown fields, these are the pointers to the UnknownFieldSet |
203 | // containing the unknown fields. In certain cases (e.g. proto1's |
204 | // MessageSet, or nested groups of unknown fields), these may differ from |
205 | // the messages' internal UnknownFieldSets. |
206 | const UnknownFieldSet* unknown_field_set1 = nullptr; |
207 | const UnknownFieldSet* unknown_field_set2 = nullptr; |
208 | |
209 | // For unknown fields, these are the index of the field within the |
210 | // UnknownFieldSets. One or the other will be -1 when |
211 | // reporting an addition or deletion. |
212 | int unknown_field_index1 = -1; |
213 | int unknown_field_index2 = -1; |
214 | }; |
215 | |
216 | // Abstract base class from which all MessageDifferencer |
217 | // reporters derive. The five Report* methods below will be called when |
218 | // a field has been added, deleted, modified, moved, or matched. The third |
219 | // argument is a vector of FieldDescriptor pointers which describes the chain |
220 | // of fields that was taken to find the current field. For example, for a |
221 | // field found in an embedded message, the vector will contain two |
222 | // FieldDescriptors. The first will be the field of the embedded message |
223 | // itself and the second will be the actual field in the embedded message |
224 | // that was added/deleted/modified. |
225 | // Fields will be reported in PostTraversalOrder. |
226 | // For example, given following proto, if both baz and mooo are changed. |
227 | // foo { |
228 | // bar { |
229 | // baz: 1 |
230 | // mooo: 2 |
231 | // } |
232 | // } |
233 | // ReportModified will be invoked with following order: |
234 | // 1. foo.bar.baz or foo.bar.mooo |
235 | // 2. foo.bar.mooo or foo.bar.baz |
236 | // 2. foo.bar |
237 | // 3. foo |
238 | class PROTOBUF_EXPORT Reporter { |
239 | public: |
240 | Reporter(); |
241 | virtual ~Reporter(); |
242 | |
243 | // Reports that a field has been added into Message2. |
244 | virtual void ReportAdded(const Message& message1, const Message& message2, |
245 | const std::vector<SpecificField>& field_path) = 0; |
246 | |
247 | // Reports that a field has been deleted from Message1. |
248 | virtual void ReportDeleted( |
249 | const Message& message1, const Message& message2, |
250 | const std::vector<SpecificField>& field_path) = 0; |
251 | |
252 | // Reports that the value of a field has been modified. |
253 | virtual void ReportModified( |
254 | const Message& message1, const Message& message2, |
255 | const std::vector<SpecificField>& field_path) = 0; |
256 | |
257 | // Reports that a repeated field has been moved to another location. This |
258 | // only applies when using TreatAsSet or TreatAsMap() -- see below. Also |
259 | // note that for any given field, ReportModified and ReportMoved are |
260 | // mutually exclusive. If a field has been both moved and modified, then |
261 | // only ReportModified will be called. |
262 | virtual void ReportMoved( |
263 | const Message& /* message1 */, const Message& /* message2 */, |
264 | const std::vector<SpecificField>& /* field_path */) {} |
265 | |
266 | // Reports that two fields match. Useful for doing side-by-side diffs. |
267 | // This function is mutually exclusive with ReportModified and ReportMoved. |
268 | // Note that you must call set_report_matches(true) before calling Compare |
269 | // to make use of this function. |
270 | virtual void ReportMatched( |
271 | const Message& /* message1 */, const Message& /* message2 */, |
272 | const std::vector<SpecificField>& /* field_path */) {} |
273 | |
274 | // Reports that two fields would have been compared, but the |
275 | // comparison has been skipped because the field was marked as |
276 | // 'ignored' using IgnoreField(). This function is mutually |
277 | // exclusive with all the other Report() functions. |
278 | // |
279 | // The contract of ReportIgnored is slightly different than the |
280 | // other Report() functions, in that |field_path.back().index| is |
281 | // always equal to -1, even if the last field is repeated. This is |
282 | // because while the other Report() functions indicate where in a |
283 | // repeated field the action (Addition, Deletion, etc...) |
284 | // happened, when a repeated field is 'ignored', the differencer |
285 | // simply calls ReportIgnored on the repeated field as a whole and |
286 | // moves on without looking at its individual elements. |
287 | // |
288 | // Furthermore, ReportIgnored() does not indicate whether the |
289 | // fields were in fact equal or not, as Compare() does not inspect |
290 | // these fields at all. It is up to the Reporter to decide whether |
291 | // the fields are equal or not (perhaps with a second call to |
292 | // Compare()), if it cares. |
293 | virtual void ReportIgnored( |
294 | const Message& /* message1 */, const Message& /* message2 */, |
295 | const std::vector<SpecificField>& /* field_path */) {} |
296 | |
297 | // Report that an unknown field is ignored. (see comment above). |
298 | // Note this is a different function since the last SpecificField in field |
299 | // path has a null field. This could break existing Reporter. |
300 | virtual void ReportUnknownFieldIgnored( |
301 | const Message& /* message1 */, const Message& /* message2 */, |
302 | const std::vector<SpecificField>& /* field_path */) {} |
303 | |
304 | private: |
305 | GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Reporter); |
306 | }; |
307 | |
308 | // MapKeyComparator is used to determine if two elements have the same key |
309 | // when comparing elements of a repeated field as a map. |
310 | class PROTOBUF_EXPORT MapKeyComparator { |
311 | public: |
312 | MapKeyComparator(); |
313 | virtual ~MapKeyComparator(); |
314 | |
315 | virtual bool IsMatch( |
316 | const Message& /* message1 */, const Message& /* message2 */, |
317 | const std::vector<SpecificField>& /* parent_fields */) const { |
318 | GOOGLE_CHECK(false) << "IsMatch() is not implemented." ; |
319 | return false; |
320 | } |
321 | |
322 | private: |
323 | GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MapKeyComparator); |
324 | }; |
325 | |
326 | // Abstract base class from which all IgnoreCriteria derive. |
327 | // By adding IgnoreCriteria more complex ignore logic can be implemented. |
328 | // IgnoreCriteria are registered with AddIgnoreCriteria. For each compared |
329 | // field IsIgnored is called on each added IgnoreCriteria until one returns |
330 | // true or all return false. |
331 | // IsIgnored is called for fields where at least one side has a value. |
332 | class PROTOBUF_EXPORT IgnoreCriteria { |
333 | public: |
334 | IgnoreCriteria(); |
335 | virtual ~IgnoreCriteria(); |
336 | |
337 | // Returns true if the field should be ignored. |
338 | virtual bool IsIgnored( |
339 | const Message& /* message1 */, const Message& /* message2 */, |
340 | const FieldDescriptor* /* field */, |
341 | const std::vector<SpecificField>& /* parent_fields */) = 0; |
342 | |
343 | // Returns true if the unknown field should be ignored. |
344 | // Note: This will be called for unknown fields as well in which case |
345 | // field.field will be null. |
346 | virtual bool IsUnknownFieldIgnored( |
347 | const Message& /* message1 */, const Message& /* message2 */, |
348 | const SpecificField& /* field */, |
349 | const std::vector<SpecificField>& /* parent_fields */) { |
350 | return false; |
351 | } |
352 | }; |
353 | |
354 | // To add a Reporter, construct default here, then use ReportDifferencesTo or |
355 | // ReportDifferencesToString. |
356 | explicit MessageDifferencer(); |
357 | |
358 | ~MessageDifferencer(); |
359 | |
360 | enum MessageFieldComparison { |
361 | EQUAL, // Fields must be present in both messages |
362 | // for the messages to be considered the same. |
363 | EQUIVALENT, // Fields with default values are considered set |
364 | // for comparison purposes even if not explicitly |
365 | // set in the messages themselves. Unknown fields |
366 | // are ignored. |
367 | }; |
368 | |
369 | enum Scope { |
370 | FULL, // All fields of both messages are considered in the comparison. |
371 | PARTIAL // Only fields present in the first message are considered; fields |
372 | // set only in the second message will be skipped during |
373 | // comparison. |
374 | }; |
375 | |
376 | // DEPRECATED. Use FieldComparator::FloatComparison instead. |
377 | enum FloatComparison { |
378 | EXACT, // Floats and doubles are compared exactly. |
379 | APPROXIMATE // Floats and doubles are compared using the |
380 | // MathUtil::AlmostEquals method. |
381 | }; |
382 | |
383 | enum RepeatedFieldComparison { |
384 | AS_LIST, // Repeated fields are compared in order. Differing values at |
385 | // the same index are reported using ReportModified(). If the |
386 | // repeated fields have different numbers of elements, the |
387 | // unpaired elements are reported using ReportAdded() or |
388 | // ReportDeleted(). |
389 | AS_SET, // Treat all the repeated fields as sets. |
390 | // See TreatAsSet(), as below. |
391 | AS_SMART_LIST, // Similar to AS_SET, but preserve the order and find the |
392 | // longest matching sequence from the first matching |
393 | // element. To use an optimal solution, call |
394 | // SetMatchIndicesForSmartListCallback() to pass it in. |
395 | AS_SMART_SET, // Similar to AS_SET, but match elements with fewest diffs. |
396 | }; |
397 | |
398 | // The elements of the given repeated field will be treated as a set for |
399 | // diffing purposes, so different orderings of the same elements will be |
400 | // considered equal. Elements which are present on both sides of the |
401 | // comparison but which have changed position will be reported with |
402 | // ReportMoved(). Elements which only exist on one side or the other are |
403 | // reported with ReportAdded() and ReportDeleted() regardless of their |
404 | // positions. ReportModified() is never used for this repeated field. If |
405 | // the only differences between the compared messages is that some fields |
406 | // have been moved, then the comparison returns true. |
407 | // |
408 | // Note that despite the name of this method, this is really |
409 | // comparison as multisets: if one side of the comparison has a duplicate |
410 | // in the repeated field but the other side doesn't, this will count as |
411 | // a mismatch. |
412 | // |
413 | // If the scope of comparison is set to PARTIAL, then in addition to what's |
414 | // above, extra values added to repeated fields of the second message will |
415 | // not cause the comparison to fail. |
416 | // |
417 | // Note that set comparison is currently O(k * n^2) (where n is the total |
418 | // number of elements, and k is the average size of each element). In theory |
419 | // it could be made O(n * k) with a more complex hashing implementation. Feel |
420 | // free to contribute one if the current implementation is too slow for you. |
421 | // If partial matching is also enabled, the time complexity will be O(k * n^2 |
422 | // + n^3) in which n^3 is the time complexity of the maximum matching |
423 | // algorithm. |
424 | // |
425 | // REQUIRES: field->is_repeated() and field not registered with TreatAsMap* |
426 | void TreatAsSet(const FieldDescriptor* field); |
427 | void TreatAsSmartSet(const FieldDescriptor* field); |
428 | |
429 | // The elements of the given repeated field will be treated as a list for |
430 | // diffing purposes, so different orderings of the same elements will NOT be |
431 | // considered equal. |
432 | // |
433 | // REQUIRES: field->is_repeated() and field not registered with TreatAsMap* |
434 | void TreatAsList(const FieldDescriptor* field); |
435 | // Note that the complexity is similar to treating as SET. |
436 | void TreatAsSmartList(const FieldDescriptor* field); |
437 | |
438 | // The elements of the given repeated field will be treated as a map for |
439 | // diffing purposes, with |key| being the map key. Thus, elements with the |
440 | // same key will be compared even if they do not appear at the same index. |
441 | // Differences are reported similarly to TreatAsSet(), except that |
442 | // ReportModified() is used to report elements with the same key but |
443 | // different values. Note that if an element is both moved and modified, |
444 | // only ReportModified() will be called. As with TreatAsSet, if the only |
445 | // differences between the compared messages is that some fields have been |
446 | // moved, then the comparison returns true. See TreatAsSet for notes on |
447 | // performance. |
448 | // |
449 | // REQUIRES: field->is_repeated() |
450 | // REQUIRES: field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE |
451 | // REQUIRES: key->containing_type() == field->message_type() |
452 | void TreatAsMap(const FieldDescriptor* field, const FieldDescriptor* key); |
453 | // Same as TreatAsMap except that this method will use multiple fields as |
454 | // the key in comparison. All specified fields in 'key_fields' should be |
455 | // present in the compared elements. Two elements will be treated as having |
456 | // the same key iff they have the same value for every specified field. There |
457 | // are two steps in the comparison process. The first one is key matching. |
458 | // Every element from one message will be compared to every element from |
459 | // the other message. Only fields in 'key_fields' are compared in this step |
460 | // to decide if two elements have the same key. The second step is value |
461 | // comparison. Those pairs of elements with the same key (with equal value |
462 | // for every field in 'key_fields') will be compared in this step. |
463 | // Time complexity of the first step is O(s * m * n ^ 2) where s is the |
464 | // average size of the fields specified in 'key_fields', m is the number of |
465 | // fields in 'key_fields' and n is the number of elements. If partial |
466 | // matching is enabled, an extra O(n^3) will be incured by the maximum |
467 | // matching algorithm. The second step is O(k * n) where k is the average |
468 | // size of each element. |
469 | void TreatAsMapWithMultipleFieldsAsKey( |
470 | const FieldDescriptor* field, |
471 | const std::vector<const FieldDescriptor*>& key_fields); |
472 | // Same as TreatAsMapWithMultipleFieldsAsKey, except that each of the field |
473 | // do not necessarily need to be a direct subfield. Each element in |
474 | // key_field_paths indicate a path from the message being compared, listing |
475 | // successive subfield to reach the key field. |
476 | // |
477 | // REQUIRES: |
478 | // for key_field_path in key_field_paths: |
479 | // key_field_path[0]->containing_type() == field->message_type() |
480 | // for i in [0, key_field_path.size() - 1): |
481 | // key_field_path[i+1]->containing_type() == |
482 | // key_field_path[i]->message_type() |
483 | // key_field_path[i]->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE |
484 | // !key_field_path[i]->is_repeated() |
485 | void TreatAsMapWithMultipleFieldPathsAsKey( |
486 | const FieldDescriptor* field, |
487 | const std::vector<std::vector<const FieldDescriptor*> >& key_field_paths); |
488 | |
489 | // Uses a custom MapKeyComparator to determine if two elements have the same |
490 | // key when comparing a repeated field as a map. |
491 | // The caller is responsible to delete the key_comparator. |
492 | // This method varies from TreatAsMapWithMultipleFieldsAsKey only in the |
493 | // first key matching step. Rather than comparing some specified fields, it |
494 | // will invoke the IsMatch method of the given 'key_comparator' to decide if |
495 | // two elements have the same key. |
496 | void TreatAsMapUsingKeyComparator(const FieldDescriptor* field, |
497 | const MapKeyComparator* key_comparator); |
498 | |
499 | // Initiates and returns a new instance of MultipleFieldsMapKeyComparator. |
500 | MapKeyComparator* CreateMultipleFieldsMapKeyComparator( |
501 | const std::vector<std::vector<const FieldDescriptor*> >& key_field_paths); |
502 | |
503 | // Add a custom ignore criteria that is evaluated in addition to the |
504 | // ignored fields added with IgnoreField. |
505 | // Takes ownership of ignore_criteria. |
506 | void AddIgnoreCriteria(IgnoreCriteria* ignore_criteria); |
507 | |
508 | // Indicates that any field with the given descriptor should be |
509 | // ignored for the purposes of comparing two messages. This applies |
510 | // to fields nested in the message structure as well as top level |
511 | // ones. When the MessageDifferencer encounters an ignored field, |
512 | // ReportIgnored is called on the reporter, if one is specified. |
513 | // |
514 | // The only place where the field's 'ignored' status is not applied is when |
515 | // it is being used as a key in a field passed to TreatAsMap or is one of |
516 | // the fields passed to TreatAsMapWithMultipleFieldsAsKey. |
517 | // In this case it is compared in key matching but after that it's ignored |
518 | // in value comparison. |
519 | void IgnoreField(const FieldDescriptor* field); |
520 | |
521 | // Sets the field comparator used to determine differences between protocol |
522 | // buffer fields. By default it's set to a DefaultFieldComparator instance. |
523 | // MessageDifferencer doesn't take ownership over the passed object. |
524 | // Note that this method must be called before Compare for the comparator to |
525 | // be used. |
526 | void set_field_comparator(FieldComparator* comparator); |
527 | #ifdef PROTOBUF_FUTURE_BREAKING_CHANGES |
528 | void set_field_comparator(DefaultFieldComparator* comparator); |
529 | #endif // PROTOBUF_FUTURE_BREAKING_CHANGES |
530 | |
531 | // DEPRECATED. Pass a DefaultFieldComparator instance instead. |
532 | // Sets the fraction and margin for the float comparison of a given field. |
533 | // Uses MathUtil::WithinFractionOrMargin to compare the values. |
534 | // NOTE: this method does nothing if differencer's field comparator has been |
535 | // set to a custom object. |
536 | // |
537 | // REQUIRES: field->cpp_type == FieldDescriptor::CPPTYPE_DOUBLE or |
538 | // field->cpp_type == FieldDescriptor::CPPTYPE_FLOAT |
539 | // REQUIRES: float_comparison_ == APPROXIMATE |
540 | void SetFractionAndMargin(const FieldDescriptor* field, double fraction, |
541 | double margin); |
542 | |
543 | // Sets the type of comparison (as defined in the MessageFieldComparison |
544 | // enumeration above) that is used by this differencer when determining how |
545 | // to compare fields in messages. |
546 | void set_message_field_comparison(MessageFieldComparison comparison); |
547 | |
548 | // Returns the current message field comparison used in this differencer. |
549 | MessageFieldComparison message_field_comparison() const; |
550 | |
551 | // Tells the differencer whether or not to report matches. This method must |
552 | // be called before Compare. The default for a new differencer is false. |
553 | void set_report_matches(bool report_matches) { |
554 | report_matches_ = report_matches; |
555 | } |
556 | |
557 | // Tells the differencer whether or not to report moves (in a set or map |
558 | // repeated field). This method must be called before Compare. The default for |
559 | // a new differencer is true. |
560 | void set_report_moves(bool report_moves) { report_moves_ = report_moves; } |
561 | |
562 | // Tells the differencer whether or not to report ignored values. This method |
563 | // must be called before Compare. The default for a new differencer is true. |
564 | void set_report_ignores(bool report_ignores) { |
565 | report_ignores_ = report_ignores; |
566 | } |
567 | |
568 | // Sets the scope of the comparison (as defined in the Scope enumeration |
569 | // above) that is used by this differencer when determining which fields to |
570 | // compare between the messages. |
571 | void set_scope(Scope scope); |
572 | |
573 | // Returns the current scope used by this differencer. |
574 | Scope scope() const; |
575 | |
576 | // DEPRECATED. Pass a DefaultFieldComparator instance instead. |
577 | // Sets the type of comparison (as defined in the FloatComparison enumeration |
578 | // above) that is used by this differencer when comparing float (and double) |
579 | // fields in messages. |
580 | // NOTE: this method does nothing if differencer's field comparator has been |
581 | // set to a custom object. |
582 | void set_float_comparison(FloatComparison comparison); |
583 | |
584 | // Sets the type of comparison for repeated field (as defined in the |
585 | // RepeatedFieldComparison enumeration above) that is used by this |
586 | // differencer when compare repeated fields in messages. |
587 | void set_repeated_field_comparison(RepeatedFieldComparison comparison); |
588 | |
589 | // Returns the current repeated field comparison used by this differencer. |
590 | RepeatedFieldComparison repeated_field_comparison() const; |
591 | |
592 | // Compares the two specified messages, returning true if they are the same, |
593 | // false otherwise. If this method returns false, any changes between the |
594 | // two messages will be reported if a Reporter was specified via |
595 | // ReportDifferencesTo (see also ReportDifferencesToString). |
596 | // |
597 | // This method REQUIRES that the two messages have the same |
598 | // Descriptor (message1.GetDescriptor() == message2.GetDescriptor()). |
599 | bool Compare(const Message& message1, const Message& message2); |
600 | |
601 | // Same as above, except comparing only the list of fields specified by the |
602 | // two vectors of FieldDescriptors. |
603 | bool CompareWithFields( |
604 | const Message& message1, const Message& message2, |
605 | const std::vector<const FieldDescriptor*>& message1_fields, |
606 | const std::vector<const FieldDescriptor*>& message2_fields); |
607 | |
608 | // Automatically creates a reporter that will output the differences |
609 | // found (if any) to the specified output string pointer. Note that this |
610 | // method must be called before Compare. |
611 | void ReportDifferencesToString(std::string* output); |
612 | |
613 | // Tells the MessageDifferencer to report differences via the specified |
614 | // reporter. Note that this method must be called before Compare for |
615 | // the reporter to be used. It is the responsibility of the caller to delete |
616 | // this object. |
617 | // If the provided pointer equals NULL, the MessageDifferencer stops reporting |
618 | // differences to any previously set reporters or output strings. |
619 | void ReportDifferencesTo(Reporter* reporter); |
620 | |
621 | private: |
622 | // Class for processing Any deserialization. This logic is used by both the |
623 | // MessageDifferencer and StreamReporter classes. |
624 | class UnpackAnyField { |
625 | private: |
626 | std::unique_ptr<DynamicMessageFactory> dynamic_message_factory_; |
627 | |
628 | public: |
629 | UnpackAnyField() = default; |
630 | ~UnpackAnyField() = default; |
631 | // If "any" is of type google.protobuf.Any, extract its payload using |
632 | // DynamicMessageFactory and store in "data". |
633 | bool UnpackAny(const Message& any, std::unique_ptr<Message>* data); |
634 | }; |
635 | |
636 | public: |
637 | // An implementation of the MessageDifferencer Reporter that outputs |
638 | // any differences found in human-readable form to the supplied |
639 | // ZeroCopyOutputStream or Printer. If a printer is used, the delimiter |
640 | // *must* be '$'. |
641 | // |
642 | // WARNING: this reporter does not necessarily flush its output until it is |
643 | // destroyed. As a result, it is not safe to assume the output is valid or |
644 | // complete until after you destroy the reporter. For example, if you use a |
645 | // StreamReporter to write to a StringOutputStream, the target string may |
646 | // contain uninitialized data until the reporter is destroyed. |
647 | class PROTOBUF_EXPORT StreamReporter : public Reporter { |
648 | public: |
649 | explicit StreamReporter(io::ZeroCopyOutputStream* output); |
650 | explicit StreamReporter(io::Printer* printer); // delimiter '$' |
651 | ~StreamReporter() override; |
652 | |
653 | // When set to true, the stream reporter will also output aggregates nodes |
654 | // (i.e. messages and groups) whose subfields have been modified. When |
655 | // false, will only report the individual subfields. Defaults to false. |
656 | void set_report_modified_aggregates(bool report) { |
657 | report_modified_aggregates_ = report; |
658 | } |
659 | |
660 | // The following are implementations of the methods described above. |
661 | |
662 | void ReportAdded(const Message& message1, const Message& message2, |
663 | const std::vector<SpecificField>& field_path) override; |
664 | |
665 | void ReportDeleted(const Message& message1, const Message& message2, |
666 | const std::vector<SpecificField>& field_path) override; |
667 | |
668 | void ReportModified(const Message& message1, const Message& message2, |
669 | const std::vector<SpecificField>& field_path) override; |
670 | |
671 | void ReportMoved(const Message& message1, const Message& message2, |
672 | const std::vector<SpecificField>& field_path) override; |
673 | |
674 | void ReportMatched(const Message& message1, const Message& message2, |
675 | const std::vector<SpecificField>& field_path) override; |
676 | |
677 | void ReportIgnored(const Message& message1, const Message& message2, |
678 | const std::vector<SpecificField>& field_path) override; |
679 | |
680 | void ReportUnknownFieldIgnored( |
681 | const Message& message1, const Message& message2, |
682 | const std::vector<SpecificField>& field_path) override; |
683 | |
684 | // Messages that are being compared must be provided to StreamReporter prior |
685 | // to processing |
686 | void SetMessages(const Message& message1, const Message& message2); |
687 | |
688 | protected: |
689 | // Prints the specified path of fields to the buffer. |
690 | virtual void PrintPath(const std::vector<SpecificField>& field_path, |
691 | bool left_side); |
692 | |
693 | // Prints the value of fields to the buffer. left_side is true if the |
694 | // given message is from the left side of the comparison, false if it |
695 | // was the right. This is relevant only to decide whether to follow |
696 | // unknown_field_index1 or unknown_field_index2 when an unknown field |
697 | // is encountered in field_path. |
698 | virtual void PrintValue(const Message& message, |
699 | const std::vector<SpecificField>& field_path, |
700 | bool left_side); |
701 | |
702 | // Prints the specified path of unknown fields to the buffer. |
703 | virtual void PrintUnknownFieldValue(const UnknownField* unknown_field); |
704 | |
705 | // Just print a string |
706 | void Print(const std::string& str); |
707 | |
708 | private: |
709 | // helper function for PrintPath that contains logic for printing maps |
710 | void PrintMapKey(bool left_side, const SpecificField& specific_field); |
711 | |
712 | io::Printer* printer_; |
713 | bool delete_printer_; |
714 | bool report_modified_aggregates_; |
715 | const Message* message1_; |
716 | const Message* message2_; |
717 | MessageDifferencer::UnpackAnyField unpack_any_field_; |
718 | GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(StreamReporter); |
719 | }; |
720 | |
721 | private: |
722 | friend class SimpleFieldComparator; |
723 | |
724 | // A MapKeyComparator to be used in TreatAsMapUsingKeyComparator. |
725 | // Implementation of this class needs to do field value comparison which |
726 | // relies on some private methods of MessageDifferencer. That's why this |
727 | // class is declared as a nested class of MessageDifferencer. |
728 | class MultipleFieldsMapKeyComparator; |
729 | |
730 | // A MapKeyComparator for use with map_entries. |
731 | class PROTOBUF_EXPORT MapEntryKeyComparator : public MapKeyComparator { |
732 | public: |
733 | explicit MapEntryKeyComparator(MessageDifferencer* message_differencer); |
734 | bool IsMatch( |
735 | const Message& message1, const Message& message2, |
736 | const std::vector<SpecificField>& parent_fields) const override; |
737 | |
738 | private: |
739 | MessageDifferencer* message_differencer_; |
740 | }; |
741 | |
742 | // Returns true if field1's number() is less than field2's. |
743 | static bool FieldBefore(const FieldDescriptor* field1, |
744 | const FieldDescriptor* field2); |
745 | |
746 | // Retrieve all the set fields, including extensions. |
747 | FieldDescriptorArray RetrieveFields(const Message& message, |
748 | bool base_message); |
749 | |
750 | // Combine the two lists of fields into the combined_fields output vector. |
751 | // All fields present in both lists will always be included in the combined |
752 | // list. Fields only present in one of the lists will only appear in the |
753 | // combined list if the corresponding fields_scope option is set to FULL. |
754 | FieldDescriptorArray CombineFields(const FieldDescriptorArray& fields1, |
755 | Scope fields1_scope, |
756 | const FieldDescriptorArray& fields2, |
757 | Scope fields2_scope); |
758 | |
759 | // Internal version of the Compare method which performs the actual |
760 | // comparison. The parent_fields vector is a vector containing field |
761 | // descriptors of all fields accessed to get to this comparison operation |
762 | // (i.e. if the current message is an embedded message, the parent_fields |
763 | // vector will contain the field that has this embedded message). |
764 | bool Compare(const Message& message1, const Message& message2, |
765 | std::vector<SpecificField>* parent_fields); |
766 | |
767 | // Compares all the unknown fields in two messages. |
768 | bool CompareUnknownFields(const Message& message1, const Message& message2, |
769 | const UnknownFieldSet&, const UnknownFieldSet&, |
770 | std::vector<SpecificField>* parent_fields); |
771 | |
772 | // Compares the specified messages for the requested field lists. The field |
773 | // lists are modified depending on comparison settings, and then passed to |
774 | // CompareWithFieldsInternal. |
775 | bool CompareRequestedFieldsUsingSettings( |
776 | const Message& message1, const Message& message2, |
777 | const FieldDescriptorArray& message1_fields, |
778 | const FieldDescriptorArray& message2_fields, |
779 | std::vector<SpecificField>* parent_fields); |
780 | |
781 | // Compares the specified messages with the specified field lists. |
782 | bool CompareWithFieldsInternal(const Message& message1, |
783 | const Message& message2, |
784 | const FieldDescriptorArray& message1_fields, |
785 | const FieldDescriptorArray& message2_fields, |
786 | std::vector<SpecificField>* parent_fields); |
787 | |
788 | // Compares the repeated fields, and report the error. |
789 | bool CompareRepeatedField(const Message& message1, const Message& message2, |
790 | const FieldDescriptor* field, |
791 | std::vector<SpecificField>* parent_fields); |
792 | |
793 | // Compares map fields, and report the error. |
794 | bool CompareMapField(const Message& message1, const Message& message2, |
795 | const FieldDescriptor* field, |
796 | std::vector<SpecificField>* parent_fields); |
797 | |
798 | // Helper for CompareRepeatedField and CompareMapField: compares and reports |
799 | // differences element-wise. This is the implementation for non-map fields, |
800 | // and can also compare map fields by using the underlying representation. |
801 | bool CompareRepeatedRep(const Message& message1, const Message& message2, |
802 | const FieldDescriptor* field, |
803 | std::vector<SpecificField>* parent_fields); |
804 | |
805 | // Helper for CompareMapField: compare the map fields using map reflection |
806 | // instead of sync to repeated. |
807 | bool CompareMapFieldByMapReflection(const Message& message1, |
808 | const Message& message2, |
809 | const FieldDescriptor* field, |
810 | std::vector<SpecificField>* parent_fields, |
811 | DefaultFieldComparator* comparator); |
812 | |
813 | // Shorthand for CompareFieldValueUsingParentFields with NULL parent_fields. |
814 | bool CompareFieldValue(const Message& message1, const Message& message2, |
815 | const FieldDescriptor* field, int index1, int index2); |
816 | |
817 | // Compares the specified field on the two messages, returning |
818 | // true if they are the same, false otherwise. For repeated fields, |
819 | // this method only compares the value in the specified index. This method |
820 | // uses Compare functions to recurse into submessages. |
821 | // The parent_fields vector is used in calls to a Reporter instance calls. |
822 | // It can be NULL, in which case the MessageDifferencer will create new |
823 | // list of parent messages if it needs to recursively compare the given field. |
824 | // To avoid confusing users you should not set it to NULL unless you modified |
825 | // Reporter to handle the change of parent_fields correctly. |
826 | bool CompareFieldValueUsingParentFields( |
827 | const Message& message1, const Message& message2, |
828 | const FieldDescriptor* field, int index1, int index2, |
829 | std::vector<SpecificField>* parent_fields); |
830 | |
831 | // Compares the specified field on the two messages, returning comparison |
832 | // result, as returned by appropriate FieldComparator. |
833 | FieldComparator::ComparisonResult GetFieldComparisonResult( |
834 | const Message& message1, const Message& message2, |
835 | const FieldDescriptor* field, int index1, int index2, |
836 | const FieldContext* field_context); |
837 | |
838 | // Check if the two elements in the repeated field are match to each other. |
839 | // if the key_comprator is NULL, this function returns true when the two |
840 | // elements are equal. |
841 | bool IsMatch(const FieldDescriptor* repeated_field, |
842 | const MapKeyComparator* key_comparator, const Message* message1, |
843 | const Message* message2, |
844 | const std::vector<SpecificField>& parent_fields, |
845 | Reporter* reporter, int index1, int index2); |
846 | |
847 | // Returns true when this repeated field has been configured to be treated |
848 | // as a Set / SmartSet / SmartList. |
849 | bool IsTreatedAsSet(const FieldDescriptor* field); |
850 | bool IsTreatedAsSmartSet(const FieldDescriptor* field); |
851 | |
852 | bool IsTreatedAsSmartList(const FieldDescriptor* field); |
853 | // When treating as SMART_LIST, it uses MatchIndicesPostProcessorForSmartList |
854 | // by default to find the longest matching sequence from the first matching |
855 | // element. The callback takes two vectors showing the matching indices from |
856 | // the other vector, where -1 means an unmatch. |
857 | void SetMatchIndicesForSmartListCallback( |
858 | std::function<void(std::vector<int>*, std::vector<int>*)> callback); |
859 | |
860 | // Returns true when this repeated field is to be compared as a subset, ie. |
861 | // has been configured to be treated as a set or map and scope is set to |
862 | // PARTIAL. |
863 | bool IsTreatedAsSubset(const FieldDescriptor* field); |
864 | |
865 | // Returns true if this field is to be ignored when this |
866 | // MessageDifferencer compares messages. |
867 | bool IsIgnored(const Message& message1, const Message& message2, |
868 | const FieldDescriptor* field, |
869 | const std::vector<SpecificField>& parent_fields); |
870 | |
871 | // Returns true if this unknown field is to be ignored when this |
872 | // MessageDifferencer compares messages. |
873 | bool IsUnknownFieldIgnored(const Message& message1, const Message& message2, |
874 | const SpecificField& field, |
875 | const std::vector<SpecificField>& parent_fields); |
876 | |
877 | // Returns MapKeyComparator* when this field has been configured to be treated |
878 | // as a map or its is_map() return true. If not, returns NULL. |
879 | const MapKeyComparator* GetMapKeyComparator( |
880 | const FieldDescriptor* field) const; |
881 | |
882 | // Attempts to match indices of a repeated field, so that the contained values |
883 | // match. Clears output vectors and sets their values to indices of paired |
884 | // messages, ie. if message1[0] matches message2[1], then match_list1[0] == 1 |
885 | // and match_list2[1] == 0. The unmatched indices are indicated by -1. |
886 | // Assumes the repeated field is not treated as a simple list. |
887 | // This method returns false if the match failed. However, it doesn't mean |
888 | // that the comparison succeeds when this method returns true (you need to |
889 | // double-check in this case). |
890 | bool MatchRepeatedFieldIndices( |
891 | const Message& message1, const Message& message2, |
892 | const FieldDescriptor* repeated_field, |
893 | const MapKeyComparator* key_comparator, |
894 | const std::vector<SpecificField>& parent_fields, |
895 | std::vector<int>* match_list1, std::vector<int>* match_list2); |
896 | |
897 | // Checks if index is equal to new_index in all the specific fields. |
898 | static bool CheckPathChanged(const std::vector<SpecificField>& parent_fields); |
899 | |
900 | // CHECKs that the given repeated field can be compared according to |
901 | // new_comparison. |
902 | void CheckRepeatedFieldComparisons( |
903 | const FieldDescriptor* field, |
904 | const RepeatedFieldComparison& new_comparison); |
905 | |
906 | // Defines a map between field descriptors and their MapKeyComparators. |
907 | // Used for repeated fields when they are configured as TreatAsMap. |
908 | typedef std::map<const FieldDescriptor*, const MapKeyComparator*> |
909 | FieldKeyComparatorMap; |
910 | |
911 | // Defines a set to store field descriptors. Used for repeated fields when |
912 | // they are configured as TreatAsSet. |
913 | typedef std::set<const FieldDescriptor*> FieldSet; |
914 | typedef std::map<const FieldDescriptor*, RepeatedFieldComparison> FieldMap; |
915 | |
916 | Reporter* reporter_; |
917 | DefaultFieldComparator default_field_comparator_; |
918 | MessageFieldComparison message_field_comparison_; |
919 | Scope scope_; |
920 | RepeatedFieldComparison repeated_field_comparison_; |
921 | |
922 | FieldMap repeated_field_comparisons_; |
923 | // Keeps track of MapKeyComparators that are created within |
924 | // MessageDifferencer. These MapKeyComparators should be deleted |
925 | // before MessageDifferencer is destroyed. |
926 | // When TreatAsMap or TreatAsMapWithMultipleFieldsAsKey is called, we don't |
927 | // store the supplied FieldDescriptors directly. Instead, a new |
928 | // MapKeyComparator is created for comparison purpose. |
929 | std::vector<MapKeyComparator*> owned_key_comparators_; |
930 | FieldKeyComparatorMap map_field_key_comparator_; |
931 | MapEntryKeyComparator map_entry_key_comparator_; |
932 | std::vector<IgnoreCriteria*> ignore_criteria_; |
933 | // Reused multiple times in RetrieveFields to avoid extra allocations |
934 | std::vector<const FieldDescriptor*> tmp_message_fields_; |
935 | |
936 | FieldSet ignored_fields_; |
937 | |
938 | union { |
939 | DefaultFieldComparator* default_impl; |
940 | FieldComparator* base; |
941 | } field_comparator_ = {.default_impl: &default_field_comparator_}; |
942 | enum { kFCDefault, kFCBase } field_comparator_kind_ = kFCDefault; |
943 | |
944 | bool report_matches_; |
945 | bool report_moves_; |
946 | bool report_ignores_; |
947 | |
948 | std::string* output_string_; |
949 | |
950 | // Callback to post-process the matched indices to support SMART_LIST. |
951 | std::function<void(std::vector<int>*, std::vector<int>*)> |
952 | match_indices_for_smart_list_callback_; |
953 | |
954 | MessageDifferencer::UnpackAnyField unpack_any_field_; |
955 | GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageDifferencer); |
956 | }; |
957 | |
958 | // This class provides extra information to the FieldComparator::Compare |
959 | // function. |
960 | class PROTOBUF_EXPORT FieldContext { |
961 | public: |
962 | explicit FieldContext( |
963 | std::vector<MessageDifferencer::SpecificField>* parent_fields) |
964 | : parent_fields_(parent_fields) {} |
965 | |
966 | std::vector<MessageDifferencer::SpecificField>* parent_fields() const { |
967 | return parent_fields_; |
968 | } |
969 | |
970 | private: |
971 | std::vector<MessageDifferencer::SpecificField>* parent_fields_; |
972 | }; |
973 | |
974 | } // namespace util |
975 | } // namespace protobuf |
976 | } // namespace google |
977 | |
978 | #include <google/protobuf/port_undef.inc> |
979 | |
980 | #endif // GOOGLE_PROTOBUF_UTIL_MESSAGE_DIFFERENCER_H__ |
981 | |