• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 Google Inc.  All rights reserved.
3 //
4 // Use of this source code is governed by a BSD-style
5 // license that can be found in the LICENSE file or at
6 // https://developers.google.com/open-source/licenses/bsd
7 
8 // Defines classes for field comparison.
9 
10 #ifndef GOOGLE_PROTOBUF_UTIL_FIELD_COMPARATOR_H__
11 #define GOOGLE_PROTOBUF_UTIL_FIELD_COMPARATOR_H__
12 
13 #include <cstdint>
14 #include <string>
15 #include <vector>
16 
17 #include "google/protobuf/stubs/common.h"
18 #include "absl/container/flat_hash_map.h"
19 #include "google/protobuf/port.h"
20 
21 // Must be included last.
22 #include "google/protobuf/port_def.inc"
23 
24 namespace google {
25 namespace protobuf {
26 
27 class Message;
28 class EnumValueDescriptor;
29 class FieldDescriptor;
30 
31 namespace util {
32 
33 class FieldContext;
34 class MessageDifferencer;
35 
36 // Base class specifying the interface for comparing protocol buffer fields.
37 // Regular users should consider using or subclassing DefaultFieldComparator
38 // rather than this interface.
39 // Currently, this does not support comparing unknown fields.
40 class PROTOBUF_EXPORT FieldComparator {
41  public:
42   FieldComparator();
43   FieldComparator(const FieldComparator&) = delete;
44   FieldComparator& operator=(const FieldComparator&) = delete;
45   virtual ~FieldComparator();
46 
47   enum ComparisonResult {
48     SAME,       // Compared fields are equal. In case of comparing submessages,
49                 // user should not recursively compare their contents.
50     DIFFERENT,  // Compared fields are different. In case of comparing
51                 // submessages, user should not recursively compare their
52                 // contents.
53     RECURSE,    // Compared submessages need to be compared recursively.
54                 // FieldComparator does not specify the semantics of recursive
55                 // comparison. This value should not be returned for simple
56                 // values.
57   };
58 
59   // Compares the values of a field in two protocol buffer messages.
60   // Returns SAME or DIFFERENT for simple values, and SAME, DIFFERENT or RECURSE
61   // for submessages. Returning RECURSE for fields not being submessages is
62   // illegal.
63   // In case the given FieldDescriptor points to a repeated field, the indices
64   // need to be valid. Otherwise they should be ignored.
65   //
66   // FieldContext contains information about the specific instances of the
67   // fields being compared, versus FieldDescriptor which only contains general
68   // type information about the fields.
69   virtual ComparisonResult Compare(const Message& message_1,
70                                    const Message& message_2,
71                                    const FieldDescriptor* field, int index_1,
72                                    int index_2,
73                                    const util::FieldContext* field_context) = 0;
74 };
75 
76 // Basic implementation of FieldComparator.  Supports three modes of floating
77 // point value comparison: exact, approximate using MathUtil::AlmostEqual
78 // method, and arbitrarily precise using MathUtil::WithinFractionOrMargin.
79 class PROTOBUF_EXPORT SimpleFieldComparator : public FieldComparator {
80  public:
81   enum FloatComparison {
82     EXACT,        // Floats and doubles are compared exactly.
83     APPROXIMATE,  // Floats and doubles are compared using the
84                   // MathUtil::AlmostEqual method or
85                   // MathUtil::WithinFractionOrMargin method.
86     // TODO: Introduce third value to differentiate uses of AlmostEqual
87     //               and WithinFractionOrMargin.
88   };
89 
90   // Creates new comparator with float comparison set to EXACT.
91   SimpleFieldComparator();
92   SimpleFieldComparator(const SimpleFieldComparator&) = delete;
93   SimpleFieldComparator& operator=(const SimpleFieldComparator&) = delete;
94 
95   ~SimpleFieldComparator() override;
96 
set_float_comparison(FloatComparison float_comparison)97   void set_float_comparison(FloatComparison float_comparison) {
98     float_comparison_ = float_comparison;
99   }
100 
float_comparison()101   FloatComparison float_comparison() const { return float_comparison_; }
102 
103   // Set whether the FieldComparator shall treat floats or doubles that are both
104   // NaN as equal (treat_nan_as_equal = true) or as different
105   // (treat_nan_as_equal = false). Default is treating NaNs always as different.
set_treat_nan_as_equal(bool treat_nan_as_equal)106   void set_treat_nan_as_equal(bool treat_nan_as_equal) {
107     treat_nan_as_equal_ = treat_nan_as_equal;
108   }
109 
treat_nan_as_equal()110   bool treat_nan_as_equal() const { return treat_nan_as_equal_; }
111 
112   // Sets the fraction and margin for the float comparison of a given field.
113   // Uses MathUtil::WithinFractionOrMargin to compare the values.
114   //
115   // REQUIRES: field->cpp_type == FieldDescriptor::CPPTYPE_DOUBLE or
116   //           field->cpp_type == FieldDescriptor::CPPTYPE_FLOAT
117   // REQUIRES: float_comparison_ == APPROXIMATE
118   void SetFractionAndMargin(const FieldDescriptor* field, double fraction,
119                             double margin);
120 
121   // Sets the fraction and margin for the float comparison of all float and
122   // double fields, unless a field has been given a specific setting via
123   // SetFractionAndMargin() above.
124   // Uses MathUtil::WithinFractionOrMargin to compare the values.
125   //
126   // REQUIRES: float_comparison_ == APPROXIMATE
127   void SetDefaultFractionAndMargin(double fraction, double margin);
128 
129  protected:
130   // Returns the comparison result for the given field in two messages.
131   //
132   // This function is called directly by DefaultFieldComparator::Compare.
133   // Subclasses can call this function to compare fields they do not need to
134   // handle specially.
135   ComparisonResult SimpleCompare(const Message& message_1,
136                                  const Message& message_2,
137                                  const FieldDescriptor* field, int index_1,
138                                  int index_2,
139                                  const util::FieldContext* field_context);
140 
141   // Compare using the provided message_differencer. For example, a subclass can
142   // use this method to compare some field in a certain way using the same
143   // message_differencer instance and the field context.
144   bool CompareWithDifferencer(MessageDifferencer* differencer,
145                               const Message& message1, const Message& message2,
146                               const util::FieldContext* field_context);
147 
148   // Returns FieldComparator::SAME if boolean_result is true and
149   // FieldComparator::DIFFERENT otherwise.
150   ComparisonResult ResultFromBoolean(bool boolean_result) const;
151 
152  private:
153   // Defines the tolerance for floating point comparison (fraction and margin).
154   struct Tolerance {
155     double fraction;
156     double margin;
ToleranceTolerance157     Tolerance() : fraction(0.0), margin(0.0) {}
ToleranceTolerance158     Tolerance(double f, double m) : fraction(f), margin(m) {}
159   };
160 
161   friend class MessageDifferencer;
162   // The following methods get executed when CompareFields is called for the
163   // basic types (instead of submessages). They return true on success. One
164   // can use ResultFromBoolean() to convert that boolean to a ComparisonResult
165   // value.
CompareBool(const FieldDescriptor &,bool value_1,bool value_2)166   bool CompareBool(const FieldDescriptor& /* unused */, bool value_1,
167                    bool value_2) {
168     return value_1 == value_2;
169   }
170 
171   // Uses CompareDoubleOrFloat, a helper function used by both CompareDouble and
172   // CompareFloat.
173   bool CompareDouble(const FieldDescriptor& field, double value_1,
174                      double value_2);
175 
176   bool CompareEnum(const FieldDescriptor& field,
177                    const EnumValueDescriptor* value_1,
178                    const EnumValueDescriptor* value_2);
179 
180   // Uses CompareDoubleOrFloat, a helper function used by both CompareDouble and
181   // CompareFloat.
182   bool CompareFloat(const FieldDescriptor& field, float value_1, float value_2);
183 
CompareInt32(const FieldDescriptor &,int32_t value_1,int32_t value_2)184   bool CompareInt32(const FieldDescriptor& /* unused */, int32_t value_1,
185                     int32_t value_2) {
186     return value_1 == value_2;
187   }
188 
CompareInt64(const FieldDescriptor &,int64_t value_1,int64_t value_2)189   bool CompareInt64(const FieldDescriptor& /* unused */, int64_t value_1,
190                     int64_t value_2) {
191     return value_1 == value_2;
192   }
193 
CompareString(const FieldDescriptor &,const std::string & value_1,const std::string & value_2)194   bool CompareString(const FieldDescriptor& /* unused */,
195                      const std::string& value_1, const std::string& value_2) {
196     return value_1 == value_2;
197   }
198 
CompareUInt32(const FieldDescriptor &,uint32_t value_1,uint32_t value_2)199   bool CompareUInt32(const FieldDescriptor& /* unused */, uint32_t value_1,
200                      uint32_t value_2) {
201     return value_1 == value_2;
202   }
203 
CompareUInt64(const FieldDescriptor &,uint64_t value_1,uint64_t value_2)204   bool CompareUInt64(const FieldDescriptor& /* unused */, uint64_t value_1,
205                      uint64_t value_2) {
206     return value_1 == value_2;
207   }
208 
209   // This function is used by CompareDouble and CompareFloat to avoid code
210   // duplication. There are no checks done against types of the values passed,
211   // but it's likely to fail if passed non-numeric arguments.
212   template <typename T>
213   bool CompareDoubleOrFloat(const FieldDescriptor& field, T value_1, T value_2);
214 
215   FloatComparison float_comparison_;
216 
217   // If true, floats and doubles that are both NaN are considered to be
218   // equal. Otherwise, two floats or doubles that are NaN are considered to be
219   // different.
220   bool treat_nan_as_equal_;
221 
222   // True iff default_tolerance_ has been explicitly set.
223   //
224   // If false, then the default tolerance for floats and doubles is that which
225   // is used by MathUtil::AlmostEquals().
226   bool has_default_tolerance_;
227 
228   // Default float/double tolerance. Only meaningful if
229   // has_default_tolerance_ == true.
230   Tolerance default_tolerance_;
231 
232   // Field-specific float/double tolerances, which override any default for
233   // those particular fields.
234   absl::flat_hash_map<const FieldDescriptor*, Tolerance> map_tolerance_;
235 };
236 
237 // Default field comparison: use the basic implementation of FieldComparator.
238 class PROTOBUF_EXPORT DefaultFieldComparator final
239     : public SimpleFieldComparator {
240  public:
Compare(const Message & message_1,const Message & message_2,const FieldDescriptor * field,int index_1,int index_2,const util::FieldContext * field_context)241   ComparisonResult Compare(const Message& message_1, const Message& message_2,
242                            const FieldDescriptor* field, int index_1,
243                            int index_2,
244                            const util::FieldContext* field_context) override {
245     return SimpleCompare(message_1, message_2, field, index_1, index_2,
246                          field_context);
247   }
248 };
249 
250 }  // namespace util
251 }  // namespace protobuf
252 }  // namespace google
253 
254 #include "google/protobuf/port_undef.inc"
255 
256 #endif  // GOOGLE_PROTOBUF_UTIL_FIELD_COMPARATOR_H__
257